libgds_dist/0000755000175000017500000000000014003627131012416 5ustar rooksrookslibgds_dist/INSTALL0000644000175000017500000000110513546124132013450 0ustar rooksrooks libgds A library of C functions which read and write GDSII pattern format. M. Rooks, Yale University Look at libgds.c for more details on GDS format. Look at write_gds_examples.c obviously. Simply type "make" to compile the library and the example program. Run the example program to create the file stuff.gds then use your favorite CAD program to display the GDS file. To install the library for general use, copy libgds.a to somewhere in LD_LIBRARY_PATH, such as /usr/local/lib and copy libgds.h to somewhere like /usr/local/include libgds_dist/makefile0000644000175000017500000000042713546124132014125 0ustar rooksrooksall: libgds write_gds_examples libgds libgds.a: libgds.c libgds.h rm -f libgds.a libgds.o gcc -g -c libgds.c -lc -lm -o libgds.o ar -cvq libgds.a libgds.o write_gds_examples: write_gds_examples.c libgds.a gcc -g -o write_gds_examples write_gds_examples.c -lm -lc libgds.a libgds_dist/stuff.gds0000644000175000017500000000117614003627010014245 0ustar rooksrooksX.. meats>A79D/.. hotdogs ,   reflected   not reflected  !  - . ,  .. sausage hotdogs AP Aff 0.. meatball sausageL libgds_dist/libgds.h0000644000175000017500000002140114003126210014021 0ustar rooksrooks #include #include #include #include #include #include #include #include // Setting BYTESWAP to 1 is appropriate for big-endian Intel processors. // GDS format was originally used on little-endian, older computers. #define BYTESWAP 1 #define BYTE unsigned char #define BOOL int #define TRUE 1 #define FALSE 0 BYTE gdsswap; short gdsword; #define SKIPOVER( fd, count ) { for ( i=0; i < ((count)-4); i+=2 ) read( (fd), &gdsword, 2 ); } #define BAILOUT( message ) { printf( "\n\nERROR: %s\n\n", (message) ); fflush(stdout); exit(-1); } #define WARNING( message ) { printf( "\n\nWARNING: %s\n\n", (message) ); fflush(stdout); } #define MAX_FORWARD_REFS 1000 struct gds_itemtype { /* an item might be a polygon, path, aref, sref or text */ int type; /* 0 = polygon, 1 = path, 2 = aref, 3 = sref, 4 = text, 5 = box */ int n; /* in the case of polygons or paths, this is the number of verticies */ /* for text this is the number of characters in the string */ int layer; /* layer */ int dt; /* datatype */ int cell_number; /* index into the table of cells- relevant for sref and aref */ float mag; /* magnification- relevant to sref, aref and text */ float angle; /* the angle - relevant to sref and aref */ BOOL abs_angle; /* from strans - normally false */ BOOL abs_mag; /* from strans - normally false */ BOOL reflect; /* from strans (reflect over x axis before rotating) */ int cols; /* Yes, many of these items are relevant to only one type of item, so */ int rows; /* perhaps we should invent a different item type for each item, then */ int col_pitch; /* string them together in a linked list of items. Why not? */ int row_pitch; /* Because the "library" has to be a linked list of one "thing". What we */ int col_pitchy; /* An array's column pitch in y, which would create a diagonal array. */ int row_pitchx; /* An array's row pitch in x. Diagonal arrays are strange and useless. */ int path_end; /* 0 = flush, 1 = round, 2 = extended. Default 0. */ int hor_present; /* The horizontal presentation for text. */ int ver_present; /* The vertical presentation for text. */ int font; /* Also relevant only for text. */ int width; /* Relevant only to paths. */ int *x; /* array of x coordinates or possibly just the reference point X */ int *y; /* array of y coordinates or possibly just the reference point Y */ char *text; /* Used only for strings. Such a waste. */ struct gds_itemtype *nextitem; }; struct gds_celltype /* A GDS library is a linked list of cells. */ { /* A cell is a linked list of items. */ char *name; /* name of the cell */ struct gds_itemtype *item; /* one element of the cell */ struct gds_celltype *nextcell; /* pointer to the next cell, forming a linked list */ }; char *gds_read_libname( int fd, int count, BOOL verbose ); void gds_read_header( int fd, int count, BOOL verbose ); void gds_swap4bytes( BYTE *four ); void gds_swap2bytes( BYTE *two ); void gds_read_header( int fd, int count, BOOL verbose ); void gds_write_header( int fd ); void gds_read_bgnlib( int fd, int count, int *cell_table_size, struct gds_celltype **lib, struct gds_celltype ***c, struct gds_celltype **cc, BOOL verbose ); void gds_write_bgnlib( int fd ); void gds_read_bgnstr( int fd, int count, int *cell_table_size, int *num_cells, struct gds_celltype ***c, struct gds_celltype **cc, struct gds_itemtype **ci, BOOL verbose ); void gds_write_bgnstr( int fd ); void gds_read_endlib( int fd, int count, BOOL verbose ); void gds_write_endlib( int fd ); void gds_read_endstr( int fd, int count, BOOL verbose ); void gds_write_endstr( int fd ); void gds_write_libname( int fd, char *name ); void gds_read_strname( int fd, int count, int num_cells, struct gds_celltype ***c, struct gds_celltype **cc, BOOL verbose ); void gds_write_strname( int fd, char *name ); void gds_read_string( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_string( int fd, char *s ); void gds_read_sname( int fd, int count, int num_cells, int *forward_num, char ***f, struct gds_celltype ***c, struct gds_itemtype **ci, BOOL verbose ); void gds_write_sname( int fd, char *s ); void gds_read_boundary( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_boundary( int fd ); void gds_read_box( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_box( int fd ); void gds_read_boxtype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_boxtype( int fd, short int dt ); void gds_read_path( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_path( int fd ); void gds_read_sref( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_sref( int fd ); void gds_read_aref( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_aref( int fd ); void gds_read_text( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_text( int fd ); void gds_read_endel( int fd, int count, BOOL verbose ); void gds_write_endel( int fd ); void gds_read_layer( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_layer( int fd, short int layer ); void gds_read_width( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_width( int fd, int width ); void gds_read_datatype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_datatype( int fd, short int dt ); void gds_read_texttype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_texttype( int fd, short int dt ); void gds_read_generations( int fd, int count, BOOL verbose ); void gds_write_generations( int fd, short int gens ); void gds_read_pathtype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_pathtype( int fd, short int pt ); void gds_read_presentation( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_presentation( int fd, int font, int vp, int hp ); void gds_read_strans( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_strans( int fd, BOOL reflect, BOOL abs_angle, BOOL abs_mag ); void gds_read_xy( int fd, int count, float dbu_um, struct gds_itemtype **ci, BOOL verbose ); void gds_write_xy( int fd, int *x, int *y, int n ); void gds_read_colrow( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_colrow( int fd, int ncols, int nrows ); void gds_read_units( int fd, float *Pdbu_um, float *Pdbu_uu, float *Pdbu_m, BOOL verbose ); void gds_write_units( int fd, float dbu_uu, float dbu_m ); void gds_read_mag( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_mag( int fd, float mag ); void gds_read_angle( int fd, int count, struct gds_itemtype **ci, BOOL verbose ); void gds_write_angle( int fd, float angle ); void gds_create_lib( int fd, char *libname, float dbu_um ); void gds_create_lib_correctly( int fd, char *libname, double dbu_um, double dbu_uu ); void gds_create_text( int fd, char *str, int x, int y, int layer, int size ); libgds_dist/libgds.c0000644000175000017500000021014314003127277014035 0ustar rooksrooks/* GDSLIB 2.7 A library of C functions for reading and writing GDSII Stream format, following the specification of Release 6 from 1987. This library was written by M. Rooks, Yale University, and released under the GNU public license. GDSII was originally developed by the Calma Company, and later sold to General Electric. GE sold the format to Cadence Design Systems, which released GDSII format into the public domain in 1997 by allowing most of the specification to be reprinted in the SPIE Handbook of Microlithography, Micromachining and Microfabrication, vol 1, P. Rai-Choudhury ed. GDSII format is not compact. Lossless compression programs such as 'zip' and 'compress' can reduce file size by factors of three or more. Why use GDSII instead of a simple format like CIF? Indeed, CIF is quite adequate for most algorithmically generated patterns. GDSII is useful when you need also to generate cell names, arrays, doses (datatypes), text, and rotated cells. It also lets you skip the conversion step when combining patterns. Therefore GDS is just a tiny bit better. Diagonal arrays are not supported, because they are stupid. Arrays at angles other than 0, 90, 180, and 270 are not supported because it's too complicated and subject to misinterpretation. Besides, who really wants a rotated array? That's silly. You could simply rotate the cell in which the array appears. 2.1 Filters out degenerate vertices. 2.2 gds_read_double() by Hans Romijn replaces gds_read_float() 2.3 gds_write_xy no longer flips the bytes of x[] and y[] upon returning 2.4 Pad strings to make their length even (to conform to the silly gds spec) only because the python gds library enforces this rule. 2.5 Create the header with a specified user unit. I previously thought that this number did not matter. Sorry. Now you have the function gds_create_lib_correctly. The old version works fine if you are using 1000 db units per user unit, which is almost always the case. 2.6 gds_create_lib_correctly now gets it right for sure this time. 2.7 gds_create_lib_correctly needs doubles instead of floats, for some unknown reason. Floats were getting munched somehow. It can't possibly be a bug in c? Supported tokens: HEADER version number (6) BGNLIB creation date LIBNAME library name UNITS database units ENDLIB end of library BGNSTR begin structure (cell) STRNAME structure (cell) name ENDSTR end structure (cell) BOUNDARY polygon PATH path = line with width SREF structure reference = cell instance AREF array reference = matrix of cells TEXT text, not to be printed LAYER layer number DATATYPE datatype number (often used for dose assignment) WIDTH path width XY coordinates for cell placement or polygon verticies ENDEL end of element SNAME structure (cell) name COLROW number of columns and rows (for aref) TEXTTYPE just like datatype, for text PRESENTATION text justification STRING character string STRANS contains mirroring and other stuff MAG magnification ANGLE angle PATHTYPE describes ends of paths GENERATIONS how many generations to retain (useless) BOX boxes were originally intended as documentation only BOXTYPE boxes are often used like polygons, in practice which makes them redundant. They also require five vertices, which makes them stupid. Unsupported, discontinued, and unused tokens: REFLIBS SPACING STRCLASS PLEX ELFLAGS FONTS TEXTNODE RESERVED BGNEXTN PROPVALUE NODE UINTEGER FORMAT ENDEXTN ELKEY NODETYPE USTRING MASK LINKKEYS LINKTYPE PROPATTR STYPTABLE ENDMASKS TAPENUM SRFNAME ATTRTABLE STRTYPE LIBDIRSIZE TAPECODE LIBSECUR Token order: Library: Structure: Elements: HEADER BGNSTR BOUNDARY PATH SREF AREF TEXT BOX BGNLIB STRNAME LAYER LAYER SNAME SNAME LAYER LAYER LIBNAME DATATYPE DATATYPE STRANS* STRANS* TEXTTYPE BOXTYPE UNITS ENDSTR XY PATHTYPE* MAG* MAG* PRESENTATION* XY ENDEL WIDTH* ANGLE* ANGLE* PATHTYPE* ENDEL ENDLIB XY XY COLROW WIDTH* ENDEL ENDEL XY STRANS* ENDEL MAG* ANGLE* XY STRING ENDEL * optional */ #include "libgds.h" /*------------------------------------------------------------------------------------------*/ // UTILITY FUNCTIONS /*------------------------------------------------------------------------------------------*/ void gds_swap4bytes( BYTE *four ) { static BYTE temp; #if BYTESWAP temp = four[0]; four[0] = four[3]; four[3] = temp; temp = four[1]; four[1] = four[2]; four[2] = temp; #endif } /*------------------------------------------------------------------------------------------*/ void gds_swap2bytes( BYTE *two ) { static BYTE temp; #if BYTESWAP temp = two[0]; two[0] = two[1]; two[1] = temp; #endif } /*------------------------------------------------------------------------------------------*/ void gds_make_next_item( struct gds_itemtype **ci ) { // mag, angle and strans must be tallied // only when flattening the pattern. static struct gds_itemtype *current_item; current_item = *ci; current_item->nextitem = (struct gds_itemtype *) malloc( sizeof( struct gds_itemtype ) ); if ( ! current_item->nextitem ) BAILOUT( "UNABLE TO ALLOCATE NEXT ITEM" ); current_item = current_item->nextitem; // Each cell has a rotation, magnification and strans, but we do not need // to keep a running tally unless we are flattening the pattern. current_item->type = -2; // invalid current_item->width = 0; current_item->n = 0; current_item->layer = 0; current_item->dt = 0; current_item->cell_number = -1; // invalid current_item->path_end = 0; current_item->mag = 1.0; /* mag */ current_item->angle = 0.0; /* angle */ current_item->abs_angle = FALSE; /* from strans */ current_item->abs_mag = FALSE; /* from strans */ current_item->reflect = FALSE; /* from strans, reflect before rotation */ current_item->rows = 0; /* n cols */ current_item->cols = 0; /* n rows */ current_item->col_pitch = 0; /* column pitch */ current_item->row_pitch = 0; /* row pitch */ current_item->col_pitchy = 0; /* diagonal components are */ current_item->row_pitchx = 0; /* hopefully zero always */ current_item->nextitem = NULL; *ci = current_item; } // make_next_item /*------------------------------------------------------------------------------------------*/ double gds_read_double( int fd ) /* Real numbers are not represented in IEEE format. A floating point number is */ /* made up of three parts: the sign, the exponent, and the mantissa. The value */ /* of the number is defined to be (mantissa) (16) (exponent) . If "S" is the */ /* sign bit, "E" are exponent bits, and "M" are mantissa bits then an 8-byte */ /* real number has the format */ /* */ /* SEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM */ /* MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM */ /* */ /* The exponent is in "excess 64" notation; that is, the 7-bit field shows a */ /* number that is 64 greater than the actual exponent. The mantissa is always */ /* a positive fraction greater than or equal to 1/16 and less than 1. For an */ /* 8-byte real, the mantissa is in bits 8 to 63. The decimal point of the */ /* binary mantissa is just to the left of bit 8. Bit 8 represents the value */ /* 1/2, bit 9 represents 1/4, and so on. */ /* */ /* In order to keep the mantissa in the range of 1/16 to 1, the results of */ /* floating point arithmetic are normalized. Normalization is a process whereby */ /* the mantissa is shifted left one hex digit at a time until its left four */ /* bits represent a non-zero quantity. For every hex digit shifted, the */ /* exponent is decreased by one. Since the mantssa is shifted four bits at a */ /* time, it is possible for the left three bits of a normalized mantissa to be */ /* zero. A zero value is represented by a number with all bits zero. The */ /* representation of negative numbers is the same as that of positive numbers, */ /* except that the highest order bit is 1, not 0. */ /* Contributed by Hans Romijn (Raith/Vistec) */ { BYTE e, m[8]; int i, b, bit, sign, bitmask, exponent; long mant = 0; long bitm = 0x80000000000000; double mantissa, number; read( fd, &m, 8 ); if ( m[0] >> 7 ) sign = -1; else sign = 1; exponent = (m[0] % 128) - 64; for ( b = 1; b <8; b++ ) { bitmask = 0x80; for ( bit = 7; bit >= 0; bit-- ) { i = ( m[b] & bitmask ) >> bit; if (i) mant += bitm ; // mantissa = (double)mant/(double)(0x100000000000000); // number = sign * mantissa * pow( 16, exponent ); // printf("%d 0x%16lX: %.24lf %.24lf\n",i,bitm,number,(float)number); bitmask = bitmask >> 1 ; bitm = bitm >> 1; } } mantissa = (double)mant/(double)(0x100000000000000); number = sign * mantissa * pow( 16, exponent ); return( number ); } // read_double /*------------------------------------------------------------------------------------------*/ float gds_read_float( int fd ) /* Read 8 bytes and interpret the number as a wacky GDS float. The format must be */ /* the legacy of some very ancient General Electric computer, built before the */ /* establishment of IEEE floating point format. */ { BYTE e, m[8]; int i, b, bit, sign, bitmask, exponent; float value, mantissa, number; read( fd, &e, 1 ); if ( e >> 7 ) sign = -1; else sign = 1; exponent = (e % 128) - 64; read( fd, m, 7 ); value = 2.0; mantissa = 0.0; for ( b = 0; b <= 6; b++ ) { bitmask = 0x80; for ( bit = 7; bit >= 0; bit-- ) { i = ( m[b] & bitmask ) >> bit ; mantissa += i / value ; value = value + value ; bitmask = bitmask >> 1 ; } } number = sign * mantissa * pow( 16, exponent ); return( number ); } // read_float /*------------------------------------------------------------------------------------------*/ void gds_bindump( BYTE x ) // dump one byte in binary format { // way too clever hack from a forum post, sorry int z; static char b[9]; b[0] = '\0'; for ( z=128; z>0; z >>=1 ) strcat( b, ((x & z) == z) ? "1" : "0" ); printf( "%s ", b ); } /*------------------------------------------------------------------------------------------*/ void gds_write_float( int fd, float x ) /* Write 8 bytes after converting back to wacky GDS float format. */ { unsigned int b, sign, e64, bit[56]; int // important exponent, i; float fexponent, mantissa, mantita; BYTE by, stupid[8]; if ( ! BYTESWAP ) WARNING( "WRITING OF FLOATING POINT ON LITTLE-ENDIAN MACHINES HAS NOT BEEN TESTED" ); // printf( "\nencoding %g\n", x ); fflush( stdout ); for ( i=0; i<8; i++ ) stupid[i] = 0; if ( x != 0.0 ) { if ( x < 0.0 ) sign = 1; else sign = 0; x = fabsf( x ); exponent = 1 + floor( log( x ) / log( 16 ) ); if ( exponent < -64 ) BAILOUT( "A NUMBER IS TOO SMALL TO ENCODE AS A GDS FLOAT" ); fexponent = exponent; e64 = exponent + 64; mantissa = x / powf( 16.0, fexponent ); mantita = mantissa; for( i=0; i<=56; i++ ) { bit[i] = floor( pow(2,i+1) * mantita ); mantita = mantita - bit[i] / pow(2,i+1); } stupid[0] = pow(2,7) * sign + e64; for ( i=0; i<8; i++ ) stupid[1] = stupid[1] + bit[i] * pow(2, 7-i); for ( i=8; i<16; i++ ) stupid[2] = stupid[2] + bit[i] * pow(2,15-i); for ( i=16; i<24; i++ ) stupid[3] = stupid[3] + bit[i] * pow(2,23-i); for ( i=24; i<32; i++ ) stupid[4] = stupid[4] + bit[i] * pow(2,31-i); for ( i=32; i<40; i++ ) stupid[5] = stupid[5] + bit[i] * pow(2,39-i); for ( i=40; i<48; i++ ) stupid[6] = stupid[6] + bit[i] * pow(2,47-i); for ( i=48; i<56; i++ ) stupid[7] = stupid[7] + bit[i] * pow(2,55-i); } // printf( "\n" ); for ( i=0; i<8; i++ ) { by = stupid[i]; write( fd, &by, 1 ); // gds_bindump( by ); } // printf( "\n" ); fflush( stdout ); } // write_float /*------------------------------------------------------------------------------------------*/ // TOKEN I/O FUNCTIONS /*------------------------------------------------------------------------------------------*/ /* Contains GDS version number- we don't care */ void gds_read_header( int fd, int count, BOOL verbose ) { int i; SKIPOVER( fd, count ); } /*------------------------------------------------------------------------------------------*/ void gds_write_header( int fd ) { unsigned short int count, si, token; ssize_t w; count = 6; gds_swap2bytes( (BYTE *) &count ); w = write( fd, &count, 2 ); if ( w <= 0 ) BAILOUT( "UNABLE TO WRITE TO OUTPUT FILE - CHECK OPEN() CALL" ); token = 0x0002; // header gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); si = 600; // GDSII version 6 gds_swap2bytes( (BYTE *) &si ); write( fd, &si, 2 ); } // write_header /*------------------------------------------------------------------------------------------*/ /* Beginning of library. Allocate the first cell. */ /* Ignore the creation date. */ void gds_read_bgnlib( int fd, // file descriptor int count, // bytes in this record (always 4) int *cell_table_size, // cell table size struct gds_celltype **lib, // pointer to library (main anchor point) struct gds_celltype ***c, // pointer to the cell table struct gds_celltype **cc, // pointer to the current cell BOOL verbose ) { struct gds_celltype *library, **cell, *current_cell; int i; SKIPOVER( fd, count ); library = (struct gds_celltype *) malloc( sizeof( struct gds_celltype ) ); /* start of the list */ current_cell = library; /* top of the list */ library->nextcell = NULL; if ( ! library ) BAILOUT( "UNABLE TO ALLOCATE LIBRARY POINTER. THAT'S STRANGE." ); cell = (struct gds_celltype **) malloc( 1025 * sizeof( struct gds_celltype * ) ); /* table of pointers to cells */ *cell_table_size = 1024; if ( ! cell ) BAILOUT( "UNABLE TO ALLOCATE MEMORY FOR CELL TABLE." ); *lib = library; *c = cell; *cc = current_cell; } // read_bgnlib /*------------------------------------------------------------------------------------------*/ void gds_write_bgnlib( int fd ) { time_t *now; struct tm *date; short int year, month, day, hour, minute, second, token, count; now = (time_t *) malloc( sizeof( time_t ) ); date = (struct tm *) malloc( sizeof( struct tm ) ); time( now ); date = localtime( now ); count = 0x1C; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0102; // BGNLIB gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); year = 1900 + date->tm_year; // last modification time gds_swap2bytes( (BYTE *) &year ); write( fd, &year, 2 ); month = 1 + date->tm_mon; gds_swap2bytes( (BYTE *) &month ); write( fd, &month, 2 ); day = date->tm_mday; gds_swap2bytes( (BYTE *) &day ); write( fd, &day, 2 ); hour = date->tm_hour; gds_swap2bytes( (BYTE *) &hour ); write( fd, &hour, 2 ); minute = date->tm_min; gds_swap2bytes( (BYTE *) &minute ); write( fd, &minute, 2 ); second = date->tm_sec; gds_swap2bytes( (BYTE *) &second ); write( fd, &second, 2 ); write( fd, &year, 2 ); // last access time (same) write( fd, &month, 2 ); write( fd, &day, 2 ); write( fd, &hour, 2 ); write( fd, &minute, 2 ); write( fd, &second, 2 ); } // write_bgnlib /*------------------------------------------------------------------------------------------*/ /* Beginning of a cell. If this is after the first cell */ /* then allocate it. Ignore the creation date. */ void gds_read_bgnstr( int fd, int count, int *cell_table_size, int *num_cells, struct gds_celltype ***c, // cell table struct gds_celltype **cc, // current cell struct gds_itemtype **ci, // current item BOOL verbose ) { static BOOL first_cell = TRUE; int i; static struct gds_celltype **cell, *current_cell; static struct gds_itemtype *current_item; current_item = *ci; cell = *c; current_cell = *cc; SKIPOVER( fd, count ); if ( first_cell ) /* Then we already created the first cell in bgnlib */ { first_cell = FALSE; *num_cells = 0; } else /* allocate a new cell and move up the pointer */ { current_cell->nextcell = (struct gds_celltype *) malloc( sizeof( struct gds_celltype ) ); if ( ! current_cell->nextcell ) BAILOUT( "UNABLE TO ALLOCATE MEMORY FOR THE NEXT CELL." ); current_cell = current_cell->nextcell; current_cell->nextcell = NULL; *num_cells = *num_cells + 1; if ( *num_cells > *cell_table_size ) { *cell_table_size *= 2; cell = (struct gds_celltype **) realloc( cell, (1 + *cell_table_size) * sizeof( struct gds_celltype * ) ); if ( ! cell ) BAILOUT( "UNABLE TO REALLOCATE CELL TABLE. SORRY DUDE." ); } } current_cell->item = (struct gds_itemtype *) malloc( sizeof( struct gds_itemtype ) ); current_item = current_cell->item; current_item->type = -1; current_item->mag = 1.0; current_item->nextitem = NULL; // Now let's be careful to not use the first item. // Seems like a waste, but it makes the logic simpler. *c = cell; *cc = current_cell; *ci = current_item; } // read_bgnstr /*------------------------------------------------------------------------------------------*/ void gds_write_bgnstr( int fd ) { static time_t *now; static struct tm *date; static short int year, month, day, hour, minute, second, token, count; now = (time_t *) malloc( sizeof( time_t ) ); date = (struct tm *) malloc( sizeof( struct tm ) ); time( now ); date = localtime( now ); year = 1900 + date->tm_year; month = 1 + date->tm_mon; day = date->tm_mday; hour = date->tm_hour; minute = date->tm_min; second = date->tm_sec; gds_swap2bytes( (BYTE *) &year ); gds_swap2bytes( (BYTE *) &month ); gds_swap2bytes( (BYTE *) &day ); gds_swap2bytes( (BYTE *) &hour ); gds_swap2bytes( (BYTE *) &minute ); gds_swap2bytes( (BYTE *) &second ); count = 28; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0502; // BGNSTR gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, &year, 2 ); // creation time write( fd, &month, 2 ); write( fd, &day, 2 ); write( fd, &hour, 2 ); write( fd, &minute, 2 ); write( fd, &second, 2 ); write( fd, &year, 2 ); // access time write( fd, &month, 2 ); write( fd, &day, 2 ); write( fd, &hour, 2 ); write( fd, &minute, 2 ); write( fd, &second, 2 ); } // write_bgnstr /*------------------------------------------------------------------------------------------*/ /* Marks the end of a library */ void gds_read_endlib( int fd, int count, BOOL verbose ) { int i; SKIPOVER( fd, count ); } /*------------------------------------------------------------------------------------------*/ void gds_write_endlib( int fd ) { static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0400; // ENDLIB gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_endlib /*------------------------------------------------------------------------------------------*/ /* Marks the end of a structure */ void gds_read_endstr( int fd, int count, BOOL verbose ) { static int i; SKIPOVER( fd, count ); } /*------------------------------------------------------------------------------------------*/ void gds_write_endstr( int fd ) { static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0700; // ENDSTR gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_endstr /*------------------------------------------------------------------------------------------*/ /* Read the library name. */ char * gds_read_libname( int fd, int count, BOOL verbose ) { char *name; name = (char *) malloc( count - 3 ); read( fd, name, count-4 ); name[count-4] = '\0'; if ( verbose ) printf( " library \"%s\"\n", name ); return( name ); } // read_libname /*------------------------------------------------------------------------------------------*/ void gds_write_libname( int fd, char *s ) { short int // name should be null-terminated count, len, i, token; static BOOL pad; static char *ps; len = strlen( s ); pad = (len % 2) != 0; if ( pad ) len++; ps = (char *) malloc( len ); if ( pad ) { for ( i=0; i < len-1; i++ ) ps[i] = s[i]; ps[len-1] = 0; } else { for ( i=0; i < len; i++ ) ps[i] = s[i]; } count = 4 + len; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0206; // LIBNAME gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, ps, len ); } // write_libname /*------------------------------------------------------------------------------------------*/ /* Contains a structure name. */ void gds_read_strname( int fd, int count, int num_cells, struct gds_celltype ***c, struct gds_celltype **cc, BOOL verbose ) { static struct gds_celltype **cell, *current_cell; cell = *c; current_cell = *cc; current_cell->name = (char *) malloc( count - 3 ); if ( ! current_cell->name ) BAILOUT( "UNABLE TO ALLOCATE MEMORY FOR NEXT CELL NAME" ); read( fd, current_cell->name, count-4 ); current_cell->name[count-4] = '\0'; if ( verbose ) printf( " cell \"%s\"\n", current_cell->name ); cell[ num_cells ] = current_cell; /* save the pointer to this cell */ *c = cell; *cc = current_cell; } // read_strname /*------------------------------------------------------------------------------------------*/ void gds_write_strname( int fd, char *s ) { static short int // name should be null-terminated count, len, i, token; static BOOL pad; static char *ps; len = strlen( s ); pad = (len % 2) != 0; if ( pad ) len++; ps = (char *) malloc( len ); if ( pad ) { for ( i=0; i < len-1; i++ ) ps[i] = s[i]; ps[len-1] = 0; } else { for ( i=0; i < len; i++ ) ps[i] = s[i]; } count = 4 + len; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0606; // STRNAME gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, ps, len ); } // write_strname /*------------------------------------------------------------------------------------------*/ /* Contains a string for presentation, not for exposure. */ void gds_read_string( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { // A string should be saved as part of a text object // So hopefully the current item is TEXT. // gds_read_text generates a new text item. static struct gds_itemtype *current_item; static char str[513]; static int n, m, i; current_item = *ci; if ( current_item->type != 4 ) BAILOUT( "SYNTAX ERROR: STRING APPEARS OUTSIDE OF TEXT OBJECT" ); m = count - 4; n = m; if ( n > 512 ) n = 512; // that's the spec: maximum 512 characters read( fd, str, n ); if ( m > n ) { WARNING( "STRING HAS MORE THAN 512 CHARACTERS" ); printf( " [%s]\n", str ); fflush( stdout ); SKIPOVER( fd, m-n ); } str[n] = '\0'; if ( verbose ) printf( " %s\n", str ); current_item->n = count - 4; current_item->text = (char *) malloc( n+1 ); strcpy( current_item->text, str ); *ci = current_item; } // read_string /*------------------------------------------------------------------------------------------*/ void gds_write_string( int fd, char *s ) { // s must by null-terminated static short int count, token, i, len; static BOOL pad; static char *ps; len = strlen( s ); if ( len > 512 ) { WARNING( "ATTEMPT TO WRITE A STRING LONGER THAN 512 CHARACTERS. TRUNCATING." ); len = 512; ps[len] = '\0'; } pad = (len % 2) != 0; if ( pad ) len++; ps = (char *) malloc( len ); if ( pad ) { for ( i=0; i < len-1; i++ ) ps[i] = s[i]; ps[len-1] = 0; } else { for ( i=0; i < len; i++ ) ps[i] = s[i]; } count = 4 + len; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1906; // STRING gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, ps, len ); } // write_string /*------------------------------------------------------------------------------------------*/ // Contains the name of a referenced structure (cell). // Passes by reference (!) the 2D array of forward references. void gds_read_sname( int fd, int count, int num_cells, int *forward_num, char ***f, struct gds_celltype ***c, struct gds_itemtype **ci, BOOL verbose ) { static char name[256]; static int i; static BOOL forward_ref_init = FALSE; static int max_forward_refs = MAX_FORWARD_REFS; static char **forward_name; static struct gds_celltype **cell; static struct gds_itemtype *current_item; current_item = *ci; cell = *c; // cell table, passed in but not out if ( count > 254 ) BAILOUT( "CELL NAME IS WAY TOO LONG" ); read( fd, name, count-4 ); name[count-4] = '\0'; if ( verbose ) printf( " %s\n", name ); /* look this up in the cell table */ i = 0; while ( (strcmp( name, cell[i]->name ) != 0) && (i < num_cells) ) i++; if ( i >= num_cells ) { if ( verbose ) printf( " forward reference\n" ); current_item->cell_number = -1; /* indicates that we must look again on the second pass */ if ( ! forward_ref_init ) { forward_ref_init = TRUE; forward_name = (char **) malloc( max_forward_refs * sizeof( char * ) ); if ( ! forward_name ) BAILOUT( "UNABLE TO ALLOCATE ARRAY OF FORWARD REFERENCE NAMES" ); *forward_num = -1; } else // we use the array as it was passed in { forward_name = *f; } *forward_num = *forward_num + 1; if ( *forward_num >= max_forward_refs ) { max_forward_refs *= 2; forward_name = (char **) realloc( forward_name, max_forward_refs * sizeof( char * ) ); if ( ! forward_name ) BAILOUT( "UNABLE TO REALLOCATE ARRAY OF FORWARD REFERENCE NAMES" ); } forward_name[*forward_num] = (char *) malloc( 256 ); if ( ! forward_name[*forward_num] ) BAILOUT( "UNABLE TO ALLOCATE STRING FOR FORWARD NAME" ); strcpy( forward_name[*forward_num], name ); } else { if ( verbose ) printf( " this is cell [%d]\n", i ); current_item->cell_number = i; } *f = forward_name; // send it back out again. yikes. *ci = current_item; } // read_sname /*------------------------------------------------------------------------------------------*/ void gds_write_sname( int fd, char *s ) { static short int // s should be null-terminated count, len, i, token; static BOOL pad; static char *ps; len = strlen( s ); pad = (len % 2) != 0; if ( pad ) len++; ps = (char *) malloc( len ); if ( pad ) { for ( i=0; i < len-1; i++ ) ps[i] = s[i]; ps[len-1] = 0; } else { for ( i=0; i < len; i++ ) ps[i] = s[i]; } count = 4 + len; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1206; // SNAME gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, ps, len ); } // write_sname /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of a boundary (polygon) */ void gds_read_boundary( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static struct gds_itemtype *current_item; int i; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 0; /* meaning, this is a polygon */ *ci = current_item; } // read_boundary /*------------------------------------------------------------------------------------------*/ void gds_write_boundary( int fd ) { // just the token here. "xy" writes the actual polygon. static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0800; // BOUNDARY gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_boundary /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of a box */ void gds_read_box( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static struct gds_itemtype *current_item; int i; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 5; /* meaning, this is a box */ *ci = current_item; } // read_box /*------------------------------------------------------------------------------------------*/ void gds_write_box( int fd ) { // Boxes were orignally for documentation only, // but later, people started using them like polygons. // The spec says we need to store five points, // just like a boundary, which is so stupid. static short int count, token; WARNING( "BOXES ARE STUPID. USE BOUNDARIES INSTEAD." ); count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x2D00; // BOX gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_box /*------------------------------------------------------------------------------------------*/ void gds_read_boxtype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " %d\n", num ) ; if ( num < 0 ) WARNING( "NEGATIVE BOX TYPE NUMBER" ); if ( num > 255 ) WARNING( "BOX TYPE > 255 " ); current_item->dt = num; *ci = current_item; } // read_boxtype /*------------------------------------------------------------------------------------------*/ void gds_write_boxtype( int fd, short int dt ) { static short int count, token; if ( dt < 0 ) WARNING( "NEGATIVE BOXTYPE NUMBER" ); if ( dt > 255 ) WARNING( "BOXTYPE > 255 " ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x2E02; // BOXTYPE gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &dt ); write( fd, &dt, 2 ); } // write_boxtype /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of a path */ void gds_read_path( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { int i; static struct gds_itemtype *current_item; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 1; /* meaning, this is a path */ *ci = current_item; } // read_path /*------------------------------------------------------------------------------------------*/ void gds_write_path( int fd ) { // Just the token here. "xy" writes the actual path. static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0900; // PATH gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_path /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of a sref (structure reference) */ void gds_read_sref( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { int i; static struct gds_itemtype *current_item; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 3; /* meaning, this is a sref */ *ci = current_item; } // read_sref /*------------------------------------------------------------------------------------------*/ void gds_write_sref( int fd ) { // Only the token is written here. static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0A00; // SREF gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_sref /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of an aref (array reference) */ void gds_read_aref( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { int i; static struct gds_itemtype *current_item; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 2; /* meaning, this is an aref */ current_item->cell_number = -1; /* indicates not found yet */ *ci = current_item; } // read_aref /*------------------------------------------------------------------------------------------*/ void gds_write_aref( int fd ) { static short int // write the aref token only count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0B00; // AREF gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_aref /*------------------------------------------------------------------------------------------*/ /* Marks the beginning of a text element */ void gds_read_text( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { int i; static struct gds_itemtype *current_item; current_item = *ci; SKIPOVER( fd, count ); gds_make_next_item( ¤t_item ); current_item->type = 4; /* meaning, this is text */ *ci = current_item; } /*------------------------------------------------------------------------------------------*/ void gds_write_text( int fd ) { static short int // write the text token only count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0C00; // TEXT gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_text /*------------------------------------------------------------------------------------------*/ /* Marks the end of an element, pointlessly. */ void gds_read_endel( int fd, int count, BOOL verbose ) { int i; SKIPOVER( fd, count ); } /*------------------------------------------------------------------------------------------*/ void gds_write_endel( int fd ) { static short int count, token; count = 4; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1100; // ENDEL gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); } // write_endel /*------------------------------------------------------------------------------------------*/ /* Contains the layer number 0..255 */ void gds_read_layer( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " %d\n", num ); if ( num < 0 ) WARNING( "NEGATIVE LAYER NUMBER" ); if ( num > 255 ) WARNING( "LAYER > 255 " ); current_item->layer = num; *ci = current_item; } // read_layer /*------------------------------------------------------------------------------------------*/ void gds_write_layer( int fd, short int layer ) { static short int count, token; // Layers are actually supposed to go up to 64 only, but most programs allow // values up to 255, because 64 is stupid. Well 255 is also stupid, but less so. if ( layer < 0 || layer > 255 ) BAILOUT( "INVALID LAYER NUMBER" ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0D02; // LAYER gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &layer ); write( fd, &layer, 2 ); } // write_layer /*------------------------------------------------------------------------------------------*/ /* Contains the width of a path. Negative means that */ /* the width does not scale. */ void gds_read_width( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static int num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 4 ); gds_swap4bytes( (BYTE *) &num ); if ( verbose ) printf( " %d", num ); if ( num < 0 ) if ( verbose ) printf( " does not scale" ); if ( verbose ) printf( "\n" ); current_item->width = num; *ci = current_item; } // read_width /*------------------------------------------------------------------------------------------*/ void gds_write_width( int fd, int width ) { static short int count, token; count = 8; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0F03; // WIDTH gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap4bytes( (BYTE *) &width ); write( fd, &width, 4 ); } // write_width /*------------------------------------------------------------------------------------------*/ /* Contains the datatype number 0..255 */ void gds_read_datatype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " %d\n", num ); if ( num < 0 ) WARNING( "NEGATIVE DATATYPE NUMBER" ); if ( num > 255 ) WARNING( "DATATYPE > 255 " ); current_item->dt = num; *ci = current_item; } // read_datatype /*------------------------------------------------------------------------------------------*/ void gds_write_datatype( int fd, short int dt ) { static short int count, token; if ( dt < 0 ) WARNING( "NEGATIVE DATATYPE NUMBER" ); if ( dt > 255 ) WARNING( "DATATYPE > 255 " ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0E02; // DATATYPE gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &dt ); write( fd, &dt, 2 ); } // write_datatype /*------------------------------------------------------------------------------------------*/ /* Contains the text type. Should be 0..63, or whatever. */ void gds_read_texttype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " %d\n", num ) ; if ( num < 0 ) WARNING( "NEGATIVE TEXT TYPE NUMBER" ); if ( num > 255 ) WARNING( "TEXT TYPE > 255 " ); current_item->dt = num; *ci = current_item; } // read_texttype /*------------------------------------------------------------------------------------------*/ void gds_write_texttype( int fd, short int dt ) { static short int count, token; if ( dt < 0 ) WARNING( "NEGATIVE TEXT TYPE NUMBER" ); if ( dt > 255 ) WARNING( "TEXT TYPE > 255 " ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1602; // TEXTTYPE gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &dt ); write( fd, &dt, 2 ); } // write_texttype /*------------------------------------------------------------------------------------------*/ /* Number of generations to retain. Irrelevant. */ void gds_read_generations( int fd, int count, BOOL verbose ) { static short num; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " %d\n", num ) ; if ( num < 0 ) WARNING( "NEGATIVE NUMBER OF GENERATIONS TO RETAIN" ); if ( num > 99 ) WARNING( "NUMBER OF GENERATIONS > 99 " ); } // read_generations /*------------------------------------------------------------------------------------------*/ void gds_write_generations( int fd, short int gens ) { // most useless parameter ever static short int count, token; if ( gens < 0 ) WARNING( "NEGATIVE GENERATIONS NUMBER" ); if ( gens > 99 ) WARNING( "GENERATIONS > 99 " ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x2202; // GENERATIONS gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &gens ); write( fd, &gens, 2 ); } // write_generations /*------------------------------------------------------------------------------------------*/ /* Defines what the ends of paths should look like */ void gds_read_pathtype( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " [0x%x] ", num ) ; if ( num == 0 ) { if ( verbose ) printf( " flush square ends" ) ; } else if ( num == 1 ) { if ( verbose ) printf( " round ends" ) ; } else if ( num == 2 ) { if ( verbose ) printf( " extended square ends" ) ; } else if ( num == 4 ) { if ( verbose ) printf( " variable square end extensions ARE NOT SUPPORTED HERE" ) ; } else WARNING( "UNKNOWN PATH END TYPE" ); if ( verbose ) printf( "\n" ) ; if ( (num > 4) || (num < 0) ) { num = 0; WARNING( "INVALID PATH TYPE" ); } current_item->path_end = num; *ci = current_item; } // read_pathtype /*------------------------------------------------------------------------------------------*/ void gds_write_pathtype( int fd, short int pt ) { static short int count, token; if ( (pt < 0) || (pt > 4) ) BAILOUT( "INVALID PATH TYPE NUMBER" ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x2102; // PATHTYPE gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &pt ); write( fd, &pt, 2 ); } // write_pathtype /*------------------------------------------------------------------------------------------*/ /* Contains the font and orientation of text */ void gds_read_presentation( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { static short num, vp, hp, font; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " [0x%x] ", num ) ; /* extract font from bits "10" and "11", meaning actually bits 5 and 4. */ font = ( num >> 4 ) % 4; /* extract vertical presentation from bits "12" and "13", meaning actually bits 3 and 2. */ vp = ( num >> 2 ) % 4; /* extract horizontal presentation from bits "14" and "15", meaning acutally bits 1 and 0. */ hp = num % 4; if ( verbose ) printf( "font %d ", font ) ; if ( vp == 0 ) { if ( verbose ) printf( " vertical: top " ) ; } else if ( vp == 1 ) { if ( verbose ) printf( " vertical: middle " ) ; } else if ( vp == 2 ) { if ( verbose ) printf( " vertical: bottom " ) ; } else { if ( verbose ) printf( " ERROR: VERTICAL PRESENTATION BITS BOTH SET " ) ; } if ( hp == 0 ) { if ( verbose ) printf( " horizontal: left \n" ) ; } else if ( hp == 1 ) { if ( verbose ) printf( " horizontal: center \n" ) ; } else if ( hp == 2 ) { if ( verbose ) printf( " horizontal: right \n" ) ; } else { if ( verbose ) printf( " ERROR: HORIZONTAL PRESENTATION BITS BOTH SET \n" ); } current_item->font = font; current_item->mag = 1.0; current_item->hor_present = hp; current_item->ver_present = vp; *ci = current_item; } // read_presentation /*------------------------------------------------------------------------------------------*/ /* Contains the font and orientation of text */ void gds_write_presentation( int fd, // file descriptor int font, // font number 0, 1, 2, 3 int vp, // vertical presentation 0 = top 1 = middle 2 = bottom int hp ) // horizontal presentation 0 = left 1 = center 2 = right { static unsigned short token, count, num; if ( (font < 0) || (font > 3) ) { font = 0; WARNING( "INVALID FONT NUMBER" ); } if ( (vp < 0) || (vp > 2) ) { vp = 0; WARNING( "INVALID VERTICAL PRESENTATION SENT TO WRITE_PRESENTATION" ); } if ( (hp < 0) || (hp > 2) ) { hp = 0; WARNING( "INVALID HORIZONTAL PRESENTATION SENT TO WRITE_PRESENTATION" ); } num = hp + 4*vp + 16*font; gds_swap2bytes( (BYTE *) &num ); count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1701; gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); write( fd, &num, 2 ); } // write_presentation /*------------------------------------------------------------------------------------------*/ /* Contains information about transformations */ void gds_read_strans( int fd, // input file descriptor int count, // number of bytes in this record struct gds_itemtype **ci, BOOL verbose ) { static short num, bit0, bit13, bit14; static struct gds_itemtype *current_item; current_item = *ci; read( fd, &num, 2 ); gds_swap2bytes( (BYTE *) &num ); if ( verbose ) printf( " [0x%x] ", num ) ; /* bit "0" is really bit 15. It specifies reflection. */ bit0 = (num >> 15); /* bit "13" is really bit 2. It specifies absolute magnification. */ bit13 = (num >> 2) % 2; /* bit "14" is really bit 1. It specifies absolute angle. */ bit14 = (num >> 1) % 2; current_item->abs_angle = FALSE; if ( bit0 ) { if ( verbose ) printf( " apply reflection about X before rotation," ) ; current_item->reflect = TRUE; } else { if ( verbose ) printf( " no reflection," ) ; current_item->reflect = FALSE; } if ( bit13 ) { if ( verbose ) printf( " absolute magnification," ) ; current_item->abs_mag = TRUE; } else { if ( verbose ) printf( " relative magnification," ) ; current_item->abs_mag = FALSE; } if ( bit14 ) { if ( verbose ) printf( " absolute angle" ) ; current_item->abs_angle = TRUE; } else { if ( verbose ) printf( " relative angle" ) ; current_item->abs_angle = FALSE; } if ( verbose ) printf( "\n" ) ; *ci = current_item; } // read_strans /*------------------------------------------------------------------------------------------*/ void gds_write_strans( int fd, // output file descriptor BOOL reflect, // reflect about X axis before rotation (normally false) BOOL abs_angle, // angles are absolute (normally false) BOOL abs_mag ) // magnification (scale) is absolute (normally false) { static unsigned short int count, token, strans; strans = 32768 * reflect + 2 * abs_mag + abs_angle; count = 6; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1A01; // STRANS gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &strans ); write( fd, &strans, 2 ); } // write_strans /*------------------------------------------------------------------------------------------*/ void nag( char *message, int *count ) { *count += 1; if ( *count < 10 ) printf( "WARNING: %s\n", message ); else if ( *count == 10 ) printf( "*** REPEATED WARNING MESSAGES SUPPRESSED\n" ); } /*------------------------------------------------------------------------------------------*/ /* Contains X,Y coordinate pairs */ void gds_read_xy( int fd, int count, float dbu_um, struct gds_itemtype **ci, BOOL verbose ) { /* type 0 = polygon, 1 = path, 2 = aref, 3 = sref, 4 = text */ static int i, ii, num, x, y, px, py, degenerates, count_da=0, count_dv=0, count_dp=0; static float angle; static struct gds_itemtype *current_item; current_item = *ci; num = (count - 4) / 8; current_item->x = (int *) malloc( (num + 1) * sizeof( int ) ); current_item->y = (int *) malloc( (num + 1) * sizeof( int ) ); if ( ! current_item->x || ! current_item->y ) BAILOUT( "UNABLE TO ALLOCATE MEMORY FOR COORDINATES." ); degenerates = 0; ii = 0; for ( i=0; i < num; i++ ) { read( fd, &x, 4 ); gds_swap4bytes( (BYTE *) &x ); read( fd, &y, 4 ); gds_swap4bytes( (BYTE *) &y ); if ( verbose ) printf( " (%8d, %8d) = (%9.3f, %9.3f) um \n", x, y, x * dbu_um, y * dbu_um ) ; if ( current_item->type == 3 || /* sref */ current_item->type == 4 ) /* text */ { if ( num != 1 ) BAILOUT( "THERE SHOULD BE ONLY ONE COORDINATE FOR SREF OR TEXT." ); current_item->x[0] = x; current_item->y[0] = y; } else if ( current_item->type == 2 ) /* aref */ { if ( num != 3 ) BAILOUT( "THERE SHOULD BE THREE COORDINATES FOR AN AREF." ); if ( i == 0 ) { /* aref reference point */ current_item->x[0] = x; current_item->y[0] = y; } else if ( i == 1 ) /* aref column spacing */ { if ( current_item->cols <= 0 ) BAILOUT( "NUMBER OF COLUMNS IS <= 0" ); angle = current_item->angle; current_item->col_pitch = (x - current_item->x[0]) / current_item->cols; current_item->col_pitchy = (y - current_item->y[0]) / current_item->cols; // hopefully zero if ( verbose ) printf( " Column pitch (points): %d, (%d) \n", current_item->col_pitch, current_item->col_pitchy ); if ( current_item->col_pitchy != 0 ) nag( "DIAGONAL ARRAY - PROBABLY A MISTAKE", &count_da ); } else if ( i == 2 ) { if ( current_item->rows <= 0 ) BAILOUT( "NUMBER OF ROWS IS <= 0" ); angle = current_item->angle; current_item->row_pitch = (y - current_item->y[0]) / current_item->rows; current_item->row_pitchx = (x - current_item->x[0]) / current_item->rows; if ( verbose ) printf( " Row pitch (points): (%d), %d \n", current_item->row_pitchx, current_item->row_pitch ); if ( current_item->row_pitchx != 0 ) nag( "DIAGONAL ARRAY - PROBABLY A MISTAKE", &count_da ); } } else if ( current_item->type == 1 || // path current_item->type == 0 || // polygon current_item->type == 5 ) // box { current_item->x[ii] = x; current_item->y[ii] = y; if ( i == 0 ) { px = x; py = y; } else // look for degenerates { if ( x == px && y == py ) { ii--; degenerates++; nag( "degenerate vertex", &count_dv ); } else { px = x; py = y; } } } else BAILOUT( "INVALID ITEM TYPE FOUND IN XY FUNCTION." ); ii++; } current_item->n = num - degenerates; if ( current_item->n <= 0 ) nag( "DEGENERATE POLYGON, PATH, OR BOX. THERE IS ONLY ONE VERTEX.", &count_dp ); *ci = current_item; } // read_xy /*------------------------------------------------------------------------------------------*/ void gds_write_xy( int fd, int *x, int *y, int n ) { static short int // If this is a polygon, be sure to repeat the first vertex. count, // If this is a path, do not repeat. token; static int i, xx, yy; //if ( n > 200 ) WARNING( "OVER 200 VERTICIES" ); if ( n > 8200 ) BAILOUT( "WAY TOO MANY VERTICIES" ); count = 4 + 8 * n; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1003; // XY gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); for ( i=0; icols = ncols; current_item->rows = nrows; *ci = current_item; } // colrow /*------------------------------------------------------------------------------------------*/ void gds_write_colrow( int fd, int ncols, int nrows ) { static unsigned short int count, token, sicols, sirows; if ( (ncols < 0) || (ncols > 32767) ) BAILOUT( "NUMBER OF COLUMNS IS INVALID" ); if ( (nrows < 0) || (nrows > 32767) ) BAILOUT( "NUMBER OF ROWS IS INVALID" ); sicols = ncols; sirows = nrows; count = 8; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1302; // COLROW gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_swap2bytes( (BYTE *) &sicols ); write( fd, &sicols, 2 ); gds_swap2bytes( (BYTE *) &sirows ); write( fd, &sirows, 2 ); } // write_colrow /*------------------------------------------------------------------------------------------*/ void gds_read_units( int fd, float *Pdbu_um, float *Pdbu_uu, float *Pdbu_m, BOOL verbose ) /* Read the database UNIT in "user units" (typically 0.001), then read the database unit */ /* in units of meters. The first number doesn't really matter, unless you want a CAD */ /* program to display the data in convenient units (such as microns). */ /* The imporant number is the second one: meters per bit. */ { double uu_um, dbu_uu, /* database unit in user units, usually 0.001 */ dbu_m; /* database unit in meters, usually 1e-9 */ dbu_uu = gds_read_double( fd ); dbu_m = gds_read_double( fd ); if ( dbu_uu <= 0.0 ) BAILOUT( "INVALID DATABASE USER UNIT, < 0" ); if ( dbu_m <= 0.0 ) BAILOUT( "INVALID DATABASE UNIT, < 0" ); uu_um = dbu_uu / (dbu_m * 1e6); // user units per micron, usually 1 if ( verbose ) { printf( " Database units in user units: %f\n", dbu_uu ); printf( " User units per micron: %1.0f\n", uu_um ); printf( " Database units in microns: %f\n", dbu_m * 1e6 ); } *Pdbu_um = dbu_m * 1e6; // microns per database unit *Pdbu_uu = dbu_uu; // user units per database unit *Pdbu_m = dbu_m; // meters per database unit } // read_units /*------------------------------------------------------------------------------------------*/ void gds_write_units( int fd, float dbu_uu, float dbu_m ) { short int count, token; count = 20; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x0305; // UNITS gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_write_float( fd, dbu_uu ); gds_write_float( fd, dbu_m ); } // write_units /*------------------------------------------------------------------------------------------*/ void gds_read_mag( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { double magnification; static struct gds_itemtype *current_item; current_item = *ci; magnification = gds_read_double( fd ); if ( verbose ) printf( " %g \n", magnification ) ; current_item->mag = magnification; *ci = current_item; } // read_mag /*------------------------------------------------------------------------------------------*/ void gds_write_mag( int fd, float mag ) { static int count, token; count = 12; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1B05; // MAG gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_write_float( fd, mag ); } // write_mag /*------------------------------------------------------------------------------------------*/ void gds_read_angle( int fd, int count, struct gds_itemtype **ci, BOOL verbose ) { double a; static struct gds_itemtype *current_item; current_item = *ci; a = gds_read_double( fd ); if ( verbose ) printf( " %g \n", a ) ; current_item->angle = a; *ci = current_item; } // read_angle /*------------------------------------------------------------------------------------------*/ void gds_write_angle( int fd, float angle ) { static int count, token; count = 12; gds_swap2bytes( (BYTE *) &count ); write( fd, &count, 2 ); token = 0x1C05; // ANGLE gds_swap2bytes( (BYTE *) &token ); write( fd, &token, 2 ); gds_write_float( fd, angle ); } // write_angle /*------------------------------------------------------------------------------------------*/ // HIGHER LEVEL FUNCTIONS /*------------------------------------------------------------------------------------------*/ void gds_create_lib( int fd, char *libname, float dbu_um ) { // Write HEADER, BGNLIB, LIBNAME, and UNITS. // This older version works fine if there are 1000 user units per database unit. float dbu_uu, // database user units, 1 nm per bit dbu_m; // database unit in meters, usually 1e-9m printf( "\nGDS library %s created with deprecated function.", libname ); printf( "\nPlease use gds_create_lib_correctly() when the number \nof database units per user unit is not 1000.\n" ); dbu_uu = 0.001; dbu_m = dbu_uu * 1.0e-6; gds_write_header( fd ); gds_write_bgnlib( fd ); gds_write_libname( fd, libname ); gds_write_units( fd, dbu_uu, dbu_m ); } // create_lib /*------------------------------------------------------------------------------------------*/ void gds_create_lib_correctly( int fd, char *libname, double dbu_um, double dbu_uu ) { // Write HEADER, BGNLIB, LIBNAME, and UNITS. // OMG why can't we pass in floats instead of doubles? Wow that's really weird. double dbu_m; // dbu_m = 1.0e-6 * dbu_uu; is wrong. dbu_m = dbu_um * 1e-6; gds_write_header( fd ); gds_write_bgnlib( fd ); gds_write_libname( fd, libname ); gds_write_units( fd, dbu_uu, dbu_m ); } // create_lib /*------------------------------------------------------------------------------------------*/ void gds_create_text( int fd, char *str, int x, int y, int layer, int size ) { static int xx[1], yy[1]; // generate text centered at x,y gds_write_text( fd ); gds_write_layer( fd, layer ); gds_write_texttype( fd, 0 ); gds_write_presentation( fd, 0, 1, 0 ); // fd, font=0, vp=center, hp=left gds_write_width( fd, size ); gds_write_strans( fd, 0, 0, 0 ); // fd, reflect, abs_angle, abs_mag xx[0] = x; yy[0] = y; gds_write_xy( fd, xx, yy, 1 ); gds_write_string( fd, str ); gds_write_endel( fd ); } // create_text /*------------------------------------------------------------------------------------------*/ libgds_dist/write_gds_examples.c0000644000175000017500000001500014003626603016446 0ustar rooksrooks/* WRITE GDS EXAMPLES requires libgds.c and libgds.h, which should be in the same directory as write_gds_examples.c To compile, use a makefile containing the following (but not the dashes) -------------------------------------------- libgds libgds.a: libgds.c libgds.h rm libgds.a libgds.o gcc -g -c libgds.c -lc -lm -o libgds.o ar -cvq libgds.a libgds.o write_gds_examples: write_gds_examples.c libgds.a gcc -g -o write_gds_examples write_gds_examples.c -lm -lc libgds.a -------------------------------------------- then use the command "make write_gds_examples" Assuming that goes well, you can run the program by typing "write_gds_examples" */ #include "libgds.h" /*------------------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------------------*/ main( int argc, char *argv[] ) { int fd, // output gds file descriptor x[5], y[5]; fd = open( "stuff.gds", O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); if( fd <= 0 ) BAILOUT( "UNABLE TO OPEN OUTPUT FILE" ); // start the gds library with HEADER, BGNLIB, LIBNAME, and UNITS gds_create_lib_correctly( fd, "meats", 0.001, 0.001 ); // file-number, lib-name, dbu_um, dbu_user_units // create a cell called "hotdogs" gds_write_bgnstr( fd ); gds_write_strname( fd, "hotdogs" ); //----------------------------------------------------------------------------- // create a polygon gds_write_boundary( fd ); // write just the token gds_write_layer( fd, 0 ); // layer 0, for example gds_write_datatype( fd, 1 ); // datatype 1, for example x[0] = 0; y[0] = 0; // signed four-byte integers x[1] = 0; y[1] = 500; x[2] = 1000; y[2] = 500; // in this example 1 integer unit = 1 nm x[3] = 1000; y[3] = 0; x[4] = 0; y[4] = 0; // required repetition of first point (yup, that's stupid) gds_write_xy( fd, x, y, 5 ); // polygon, four vertices, first vertex repeated => 5 points gds_write_endel( fd ); // end of element //----------------------------------------------------------------------------- // create some text, reflected about the x axis gds_write_text( fd ); gds_write_layer( fd, 1 ); gds_write_texttype( fd, 0 ); gds_write_presentation( fd, 0, 1, 1 ); // fd, font, hp, vp gds_write_width( fd, 500 ); gds_write_strans( fd, 1, 0, 0 ); // fd, reflect, abs_angle, abs_mag x[0] = 2000; y[0] = 2000; gds_write_xy( fd, x, y, 1 ); gds_write_string( fd, "reflected" ); gds_write_endel( fd ); //----------------------------------------------------------------------------- // create some text, using the helper function instead. // arguments: file-descriptor, string, x, y, layer, size // where x, y, and size are in database units (nanometers, usually) gds_create_text( fd, "not reflected", 2000, 1500, 2, 500 ); //----------------------------------------------------------------------------- // create a path gds_write_path( fd ); gds_write_layer( fd, 3 ); // layer 3 gds_write_datatype( fd, 4 ); // datatype 4 gds_write_pathtype( fd, 2 ); // extended square ends gds_write_width( fd, 200 ); // 200 nm wide x[0] = 2000; y[0] = 3000; x[1] = 2000; y[1] = 4000; x[2] = 2500; y[2] = 3500; gds_write_xy( fd, x, y, 3 ); gds_write_endel( fd ); //----------------------------------------------------------------------------- // create a box, which is stupid gds_write_box( fd ); // write just the token gds_write_layer( fd, 6 ); // layer 6, for example gds_write_boxtype( fd, 12 ); // boxtype 12, for example same as datatype x[0] = 3000; y[0] = 0; // signed four-byte integers x[1] = 3000; y[1] = 500; x[2] = 4000; y[2] = 500; // in this example 1 integer unit = 1 nm x[3] = 4000; y[3] = 0; x[4] = 3000; y[4] = 0; // required repetition of first point (yup, that's stupid) gds_write_xy( fd, x, y, 5 ); // polygon, four vertices, first vertex repeated => 5 points gds_write_endel( fd ); // end of element // end the structure (the cell hotdogs) gds_write_endstr( fd ); //----------------------------------------------------------------------------- // Create a new cell, which will contain an instance of the previous cell gds_write_bgnstr( fd ); // new cell (structure) gds_write_strname( fd, "sausage" ); // called "sausage" gds_write_sref( fd ); // contains an instance of... gds_write_sname( fd, "hotdogs" ); // the cell hotdogs gds_write_mag( fd, 5.0 ); // which will be 5 times larger gds_write_angle( fd, 15.4 ); // and tilted at some weird angle x[0] = 2000; y[0] = -2000; gds_write_xy( fd, x, y, 1 ); // at these coordinates (database units) gds_write_endel( fd ); // end of element gds_write_endstr( fd ); // end of structure (cell) //----------------------------------------------------------------------------- // Create a new cell "meatball" containing an array of the cell "sausage" gds_write_bgnstr( fd ); // new cell gds_write_strname( fd, "meatball" ); // called "meatball" gds_write_aref( fd ); // containing an array of... gds_write_sname( fd, "sausage" ); // the cell "sausage" gds_write_colrow( fd, 2, 5 ); // 2 columns, 5 rows x[0] = 5000; y[0] = 5000; // array anchor point x[1] = 85000; y[1] = 5000; // displacement from anchor plus ncols*pitch // which makes the column pitch 40 um x[2] = 5000; y[2] = 205000; // displacement from anchor plus nrows*pitch // which makes the row pitch 40 um gds_write_xy( fd, x, y, 3 ); // See how you could have a diagonal matrix? // That would be so goofy! gds_write_endel( fd ); // end of element gds_write_endstr( fd ); // end of structure (cell) "meatball" // end of library gds_write_endlib( fd ); close( fd ); printf( "\nDone. Look at stuff.gds\n\n" ); } libgds_dist/write_gds_examples0000775000175000017500000017764014003627122016252 0ustar rooksrooksELF> @@@8 @#"@@@@@88@8@@@vv ~~`~` ~~`~`TT@T@DDPtd(j(j@(j@llQtdRtd~~`~`/lib64/ld-linux-x86-64.so.2GNU GNU Dܻ^ xHCH)^ H@H^ H^ H] FBH] H@pH] HEHH] HEHH] HEHHH[]UHH}H] 8 H] H] HH] HH] Hx] @flfr] Hc] @f`] HO] @ fQ] H>] @fB] H-] @f3] H] f%] H`J`L`N`P`R`f\ T`ET`Pf\ V`EV`)EH`EJ`EL`EN`EP`ER`EH`EJ`EL`uEN`aEP`MER`9UHH }uUEE`iEE;EUHH}f\[ X`CEX`f7[ Z`EZ`UHH}uUZ #E`Z Z EPZ 9UHH}fZ ``E``fZ b`oEb`UHH }uUEHHHEEHcHMEHΉEHHPHEH}tHEHƿu^@HEUHH }HuHEHqfEEfY Y t EfEHEHHY Y tZfE+HY HEHHMHEHEfEEU9|HSY HUHH=fE+H3Y HEHHMHEHEfEEf;E|EfEHEHHMEHΉPfEHEHHMEHΉ(HUH X EHΉUHSH(}uUHMLEDMHEHHqX HEHHkX HdX EHH|HHJX HHu-^@-]@HW HWEHcHX HEHΉHW HUHcHH}tHW HHƿ^@AHW UHcHHHW HHW HEHHW HEHH([]UHH}HuHEHf^W WW fIW CW t4W f*W #W HH7HW W tf W =HV V HHV HHEHV fV V V ҃9|HV V HHH[fV =H}V ~V HHpV HHEHYV fOV HV 1V f9|%V f-V `E`]fV `E`6U HH U EHΉUHSH(}uHUMHEHHU HU t-^@-]@HT HEjU dU bU \U =~ KU EU HcЋE`)U 'U 9_@4_@gH@T H`H_@DHT HV #E`UV V T T )‰ЍPV 9T Hƀ`}t`o_@HQT UPHAT GT HH6HChH#T H@h`H:H T HEHH([]UHH}HuHEH:f V V f=~D_@4_@"HR HfU HU U HHU fU U tU fU U HHKHtU vU tfmU =HXU ]U HHOU HHEH8U f.U 'U  U ҃9|HU T HHH[fT =HT T HHT HHEHT fT T T f9|T fT ރ`Eރ`qfhT `E`J+T HH (T EHΉ+UHSH8}uUHMLELMHEHHT HEHHS }~-_@-]@HP HEHcЋE`EHƀ`}t`o_@T T }T HfS pT HcHHHHHƿ`t IT ;E|>T ;E}t _@HS @T ujT O HHHHS HS Hu-`@-]@HO HiHEHEHHS HE؋PHE؉HE؋JO 9|p@O 8O 2O HHHYS HHHGS H@S Hu-8`@-]@HN HHS HE؋HHHHHR HE؋HHHHHu-p`@-]@HN HQHR HE؋HHHH`H1-}tcR ƿ`@RH3Q ER PHCR HEHHQ HEHH8[]UHH}HuHEHf R R fQ Q tQ fQ Q HHVHQ Q tfQ =HQ Q HHQ HHEHQ f}Q vQ ^Q ҃9|HUQ FQ HHH[f=Q =H,Q -Q HHQ HHEHQ fP P P f9|P fP "`E"`|fP $`E$`U~P HH {P EHΉ6UHH0}uHUMHEHHYP EE`TEE;Eݿ(`zHP HP HEHUHH}fO 0` E0`fO 2`E2`eUHH0}uHUMHEHHO EE`EE;Eݿ8`H[O HNO HEHUHH}`@4_@HJ HfO @`E@`fN -B`EB`qUHH }uHUMHEHHN EP`P`}tN ƿ`@/xN fy#`@4_@HI HIN f=~#a@4_@HI HHN N ҉P HM HEHUHH}fEEfy#$a@4_@~HWI HEf=~# HfC ҅`;E҅`fC ԅ`Eԅ`HEHHMEHΉuUHH}uUEօ`օ`}t-C ƿ`@EC fy#b@4_@%H= HB fc~#)b@4_@H= HUHH}fEEfy#Eb@4_@H= HWEfc~#ab@4_@Hb= H*fIB ؅`E؅`3f$B "څ`Eڅ` HEHiHMEHΉUHH }uHUMHEHHA E``}tA ƿsb@A fu}b@_A fu}t|b@\k;A fu}tXb@8GA fu}t4b@#b@4_@H; H}t @ f @ fy,f@ c@4_@H; HJHs@ t@ ҉P@H_@ HEHUHH}fEEfx Ef~-c@-]@>H; Hf@ `[E`f? !`4E`HEHHMEHΉUHH }uHUMHEHH? E``}t]? ƿsb@SD? f‰ffƒ)‰f&? ? f‰ffƒ)‰f? > ffЃ)f> }t> ƿ8c@> fu}tnAc@]> fu}tJQc@9u> fu}t&dc@^}txc@G>> fu}tZc@N > fu}t;c@/> fu}tc@}t c@H= = ҉PLH= z!BH= = ҉PDH= = ҉PHHx= HEHUHH}uUM}x}~*Ed@4_@DH8 H}x}~*E0d@4_@H7 H}x}~*Epd@4_@ؿH7 HyEUЍEf< `f< `E`Zfu< `E`3E`UHH }uHUMHEHH"< E`F`E}t; ƿsb@ݾ; ff; ; f‰ffƒ)‰f; ; f‰ffƒ)‰f; H; @{; ft%}td@OHP; @$#}td@*H+; @$); ft%}td@H: @ #}te@ֽH: @ : ft%}te@觽H: @#}t-e@肽H: @}t He: HEHUHH}uUME‹EЍEf<: f5: `ZE`ݼf: `3E`趼`E`蘼UHHH}HuHEPHEHE HEHƿ=e@vHE u Pe@/UHSH(}uEHU؉MHEHHT9 EPHE9 H69 89 HHH蟼HCXH9 9 HHH}HC`H8 H@XHtH8 H@`Hu-e@-]@襻H~3 HF|8 8 8 E8`蕻8`-E<`w<`}tG]8 *YEZȋD8 *YEZ38 )8 ƿe@H7 tH7 uc7 t-e@-]@襺H~2 HF|H7 H@X7 H7 H@`7 Hz7 q7 t-f@-]@0H 2 HѺE7 u+H&7 H@X47 H7 H@`%7 E7 H6 @(-Gf@-]@豹H1 HR舺H6 @6 H 6 6 H6 H@X)H6 X(A0H q6 6 Hd6 H@`)HS6 X(A8}t%H;6 P8H16 @0ƿhf@H6 @8ND`f@&:6 +H5 @,-f@-]@覸H0 HG}H5 @5 H 5 5 H5 H@`)Hx5 X,A4H f5 x5 HY5 H@X)HH5 X,A<}t%H05 P4H&5 @<ƿf@H 5 @<CD`f@/H4 tH4 tH4 H4 H@X4 HcHH‹4 H4 H@`4 HcHH‹4 4 u4 4 y4 4 ig4 q4 9u?[4 e4 9u/?4 64 ,4 #4 P`g@24 "4 4 4 /- g@-]@趶H. HW荷3 3 3 3 3 3 9H3 3 3 )щʉPHj3 @T`Hg@~HM3 HEHH([]UHH }HuHUM} ~-g@-]@H- H荶öEf3 X`EX`腵f2 Z`ۼEZ`^2 2 HHHEHЋ2 2 HHHEHЋ2 `` d`E``Ed`մK2 B2 <2 ;EhUHH }uHUMHEHH2 Ep`޴p`ݻEt`t`迻}t1 1 ƿg@S1 -g@-]@5H, Hִ 1 -g@-]@H+ H蟴մHF1 H1 P(H61 <1 P,H&1 HEHUHH}uU}x }~-g@-]@聳HZ+ H"X}x }~-h@-]@EH+ HEf0 Ef0 f0 |`NE|`Ѳff0 ~`'E~`課x` Ex`茲z`Ez`nUHHP}HuHUHMDE؋E܉舻EHEHEE܉qEHEHEfWf.Er-0h@-]@$H) HŲfWf.Er-Ph@-]@H) H荲òMYM^f(E}tXHEHEEph@莱HEHEEh@rMuYh@RMUYffZHEEfZHEEfZHEUHH }EMfEHEH/HMEHΉ谰fEHEHHMEHΉ舰EUEE葼EUEE|UHH0}uHUMHEHH- EpEHEHE}tHEHEEпi@ H- EfZ@H- HEHUHH}Ei- ` E`裯E- `E`{EUEE脻UHH0}uHUMHEHH, ExEHEHE}tHEHEEпi@(H, EfZ@H, HEHUHH}E, `(E`諮], `E`胮EUEE茺UHH0}HuEHEHƿ i@bXi@(jEEZ _YffZUExE:HUEH։mUEMUM܉EE܉UHH0}HuEMMYEEEHUEH։MfZEfZEjUHH }HuUMDEDMEuEЋE։;EEUE։tEE* E~* E``HUEH։KEgHHstuff.gdsUNABLE TO OPEN OUTPUT FILE ERROR: %s meatshotdogsreflectednot reflectedsausagemeatball Done. Look at stuff.gds @ffvAUNABLE TO ALLOCATE NEXT ITEM ERROR: %s 10%s A NUMBER IS TOO SMALL TO ENCODE AS A GDS FLOATUNABLE TO WRITE TO OUTPUT FILE - CHECK OPEN() CALLUNABLE TO ALLOCATE LIBRARY POINTER. THAT'S STRANGE.UNABLE TO ALLOCATE MEMORY FOR CELL TABLE.UNABLE TO ALLOCATE MEMORY FOR THE NEXT CELL.UNABLE TO REALLOCATE CELL TABLE. SORRY DUDE. library "%s" UNABLE TO ALLOCATE MEMORY FOR NEXT CELL NAME cell "%s" SYNTAX ERROR: STRING APPEARS OUTSIDE OF TEXT OBJECTSTRING HAS MORE THAN 512 CHARACTERS WARNING: %s [%s] %s ATTEMPT TO WRITE A STRING LONGER THAN 512 CHARACTERS. TRUNCATING.CELL NAME IS WAY TOO LONG forward referenceUNABLE TO ALLOCATE ARRAY OF FORWARD REFERENCE NAMESUNABLE TO REALLOCATE ARRAY OF FORWARD REFERENCE NAMESUNABLE TO ALLOCATE STRING FOR FORWARD NAME this is cell [%d] BOXES ARE STUPID. USE BOUNDARIES INSTEAD. %d NEGATIVE BOX TYPE NUMBERBOX TYPE > 255 NEGATIVE BOXTYPE NUMBERBOXTYPE > 255 NEGATIVE LAYER NUMBERLAYER > 255 INVALID LAYER NUMBER %d does not scaleNEGATIVE DATATYPE NUMBERDATATYPE > 255 NEGATIVE TEXT TYPE NUMBERTEXT TYPE > 255 NEGATIVE NUMBER OF GENERATIONS TO RETAINNUMBER OF GENERATIONS > 99 NEGATIVE GENERATIONS NUMBERGENERATIONS > 99 [0x%x] flush square ends round ends extended square ends variable square end extensions ARE NOT SUPPORTED HEREUNKNOWN PATH END TYPEINVALID PATH TYPEINVALID PATH TYPE NUMBERfont %d vertical: top vertical: middle vertical: bottom ERROR: VERTICAL PRESENTATION BITS BOTH SET horizontal: left horizontal: center horizontal: right ERROR: HORIZONTAL PRESENTATION BITS BOTH SET INVALID FONT NUMBERINVALID VERTICAL PRESENTATION SENT TO WRITE_PRESENTATIONINVALID HORIZONTAL PRESENTATION SENT TO WRITE_PRESENTATION apply reflection about X before rotation, no reflection, absolute magnification, relative magnification, absolute angle relative angleWARNING: %s *** REPEATED WARNING MESSAGES SUPPRESSEDUNABLE TO ALLOCATE MEMORY FOR COORDINATES. (%8d, %8d) = (%9.3f, %9.3f) um THERE SHOULD BE ONLY ONE COORDINATE FOR SREF OR TEXT.THERE SHOULD BE THREE COORDINATES FOR AN AREF.NUMBER OF COLUMNS IS <= 0 Column pitch (points): %d, (%d) DIAGONAL ARRAY - PROBABLY A MISTAKENUMBER OF ROWS IS <= 0 Row pitch (points): (%d), %d degenerate vertexINVALID ITEM TYPE FOUND IN XY FUNCTION.DEGENERATE POLYGON, PATH, OR BOX. THERE IS ONLY ONE VERTEX.WAY TOO MANY VERTICIES %d %d NEGATIVE OR ZERO NUMBER OF COLUMNSNEGATIVE OR ZERO NUMBER OF ROWSNUMBER OF COLUMNS IS INVALIDNUMBER OF ROWS IS INVALIDINVALID DATABASE USER UNIT, < 0INVALID DATABASE UNIT, < 0 Database units in user units: %f User units per micron: %1.0f Database units in microns: %f %g GDS library %s created with deprecated function. Please use gds_create_lib_correctly() when the number of database units per user unit is not 1000.?pC@9B.@?A`@.Ao:ư>;lLh؟ŠHH`!WR֪(H,h%G0Pmpȼ<ؿs@`UI(,Hh~O.(HZhG ( H h i E b %( YH h " {  #0 LP p \ T L 0 cP zRx H*zRx $pFJ w?;*3$"Dݝ{AC v Dd@eBEE E(H0H8M@l8A0A(B BBBhRgAC b 6AC q $AC E ,)AC  L(:AC 5 lBAC  AC  ?AC z AC  YAC    H-AC ( $,U"AC E TO:AC 5 ti?AC z [AC V öRAC M [AC V 0tAC o oAC j $4Ӹ-AC E# \عAC  $|AC E +AC  $'*AC E  )AC   vAC q ,*[AC V LevAC q l~AC y AC  AC  vAC q [AC V  )vAC q ,[AC V LAC  l[AC V YvAC q [AC V ?AC z  [AC V  DAC  ,AC  LAC  l7AC { AC  ZAC  AC  AC   AC  ,$AC  LAC  lRAC  4AC /  BAC = +AC  AC   rYAC T $,>AC E4 TJAC E t AC  )AC $ AC z SAC  AC |  %wAC r 4 |AC | T wAC r t 4AC   rAC m  AC   @ @ p@ \\@~`~`o@@@ ``@0@0 o@oo@~`@@@@@@ @ @& @6 @F @V @f @v @ @ @ @ @ @ @ @ @GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39), @{,U@zLQA @{8+int{ii5 Lbi)j >( 0 S8 @ FH P X ` U`  [h  bp bt px F 7T 7a q &{ / 0 1 2 3- #5b y7w c,UU[b$ q   bv #b @{ #b# fd&blx'Py( b \[T? `[ `N+A@zL28+int{ii53ii 3Lbi)j >( 0 S8 @ FH P X ` k`  qh  bp bt px F 7T 7w  &{ / 0 1 2 3- #5b y7 c,kkqb:  3   fbbv5Ktm8pb bnbZb Lb bbbAb i(0x!bn"b$bdt%b &bmag'( )b*b b+b$,b(-b,.b0:/b40b8y 1b<2b@<3bD<4bHU5bLN6bPx7Xy8`n9h :ppH>@A|B@g 5 hO ? `?I@6gtwo hO ? `@ciX ` κ!@|fdbe?m|ibHbblbitbhbdb`bLTiXiP@ ? Y(@@:[fd(be0?Km1|@i4bPb5blbit6bh7bd8b`9bT<\=X>L)ez@xe?\zgblbh `  v@fdvb}xv}b}M~Mle64MXbit}b`ibh\T#dby?}1|} M 7!@?fdb\bXDbTiblT@b fdb\FfsiFd Fbwh@# fdbLbH@lib# c) cc# Db`# PXibl#   @- fdbLnow hd  ` [^[\day[Zq[Xo[Vh[T [R[PNM!@" fdNbLNbHO@PcQ) ccR# ciSDTbWb ̀`iYb\\# (`] 0``  `o#@: fdblnow 8`d  @` [ H`[ J`day[ L`q[ N`o[ P`h[ R` [ V`[ T`%@?Y fdb\bXDbTibl/ %@[ fdbl[ X` [ Z`C&@RfdblbhDbdib \`"&@[jfdbl[ `` [ b`H&@tfdb\bXDbThd'@ogfdb\sP[jlen[ni[l [hpadb d`ps h`=(@-fd=b\>bX?bTc@) HccA# @DBbPE# p`F x`v^*@fd^bls^`a[ `lenb[ `ib[ ` c[ `padeb `psf `v+@fdb\bXciPDbL `str `nb `mb `ib ă` -@Pfdbls`[ ރ` [ `i[ ܃`len[ ȃ`padb ؃`ps Ѓ`/@*zfdb\bXbTYHfz@c) ciDb `ib `b `kb Ѐ` `# ` `  02@Qfd0bls0`3[ "`len4[ `i4[  ` 5[ $`pad6b `ps7 `*V4@vfdVb\VbXciVPDVbLY (`iZblsh"5@[&fdhblk[ 0` l[ 2`z}5@vfdzb\zbXcizPDzbL} 8`i~bl5@~fdbl[ @` [ B`Jq6@fdblbhci`Db\num[ P` H`T7@fdbldt[h[ R` [ T`08@vcfdb\bXciPDbLibl X`Y8@[fdbl[ `` [ b`:9@v8fdb\bXciPDbLibl h`@ w9@[fdbl [ p`  [ r`h9@ fdb\bXciPDbLibl x`(V:@[ffd(bl+[ ` ,[ `e;:@vfd;b\;bXci;PD;bLi=bl> `+I';@[;fdIblL[ ` M[ `\;@?fd\b\\bXD\bTi^blT e;@[fdeblh[ ` i[ `x<@qfdxblxbhcix`Dxb\numz[ `{ `<@fdbl[h[ ` [ `E=@^fdblbhci`Db\numb ` `1o>@fdblNbh[ ` [ `>@Kfdblbhci`Db\num[ ` `?@fdbldt[h[ …` [ ą`H @@7fd bl bhci `D b\num [ Ѕ`  ȅ`j"A@fd"bldt"[h%[ ҅` &[ ԅ`Z=mB@fd=bl=bhD=bdnum?[ օ`~QC@gfdQblQ[hT[ ؅` U[ څ`kC@fdkblkbhcik`Dkb\numm[ `n `}E@S fdblpt[h[ ` [ `MF@4!fdblbhci`Db\num[ `vp[ `hp[ `U[ ` `H@B!fdblUbhvpbdhpb` F `F `numF `[I@y"fdblbhci`Db\num[ `[ `[ `[ `! `[K@#fd[blb\bh ]bd^b`aF ` bF `dcF ` nagvJL@YR#' vhv`L@>$fdb\bX TciHDbPib 4`iib 0`numb (`xb 8`yb <`pxb H`pyb L`b ,`b D`b P`b T` @`  `8R@J%fdblx`yXnbh[ X` [ Z`ib \`xxb ``yyb d`+T@ (&fdblbhci`Db\Sb p`b t` h`v3KU@)&fd3blS3bh3bd6F |` 7F ~`8F x`9F z`oTtV@c'fdTbL Tc'@)Tc'Tc'DTbH^X*_h``i }W@'fd}b\*}X}T[n [lX@P(fdb\bXciPDbLh `Y@w(fdblmaghb ` b `|Y@4)fdb\bXciPDbLah `Y@w)fdblhb ` b `tZ@*fdb\QP X*lh[@rn*fdb\QP H*@ h [@ +fd blstr `x bhy b\ bX bTxx + `yy + ` b+ !\q"T? `"[ `% : ; I$ > $ >   I : ;  : ; I8 : ;I8 : ; I !I/ .?: ; 'I@B: ; I4: ; I4: ; I?<4: ; I?% : ; I$ > $ >   I : ;  : ; I8 : ;I8 : ; I !I/ &I : ;  : ; I8 .?: ; '@B: ; I4: ; I: ; I.?: ; '@B.?: ; 'I@B4: ; I4: ; I.?: ;'I@B: ;I4: ;I4: ;I.?: ;'@B4: ;I: ;I!I/ .?: ;'@B!4: ; I?<"4: ; I?. /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/usr/include/bits/usr/includewrite_gds_examples.cstddef.htypes.hlibio.hstdio.hlibgds.h  @#f-5guug%gg!!uug>h  /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/usr/include/bits/usr/includelibgds.cstddef.htypes.hlibio.hstdio.htime.hlibgds.h @!44L-%#t Zvug=uJJcJfh:L ZvZuu7JcJ fH>vtX0<i> .hv4f-2hPJb/J f .t4gt-gYgZ.t׃t-נt-4ػgYgYY׻YYYYZYYYYYZ. tL-!,-K!zZK==============>4t4=>4#4=>4>0fYL4 Y=+x+YgY .-fz /==1==6 X-u>#=#f>vz 0#w==1==. -uf@.=fؠ-)-$-(fgz/==1==5Ot4=>4Ot4#=>4M=f##=5##==Z4Mt3=>4Mt4=>4Mt4=>5Mt4=>5t4=>5M=f##=4-==Z5M=fhff4ۑ==Z5M=f##=4##==Z5M=f##=4##==Z5=f##4##==Z4M=f=fff#f#=4-==Z5R=f''fffffffff==> .Bfhu#fhu#fhu#ʟ==> . J=f"'&ؼffټffټfff .C==>4u4h""-==fG[-/v"-/v-00gs=s> >-00gs=s> ?L##pJ-<z`-=>=y< 4P==f--4f-f-===> .hh--#h4OgYgYKL4MhfK4==L4PhfL4==L . <Y6 Z5!write_gds_examples.c_IO_FILE_IO_save_endshort intsizetype_IO_write_ptr_flags_IO_buf_base_markers_IO_read_endlong long int_lockgdsword_cur_column_posargv_sbuf_old_offsetGNU C 4.8.5 20150623 (Red Hat 4.8.5-39) -mtune=generic -march=x86-64 -gunsigned charargclong long unsigned int_IO_marker_shortbuf/home/rooks/c/dogs/poly2trap/libgds_dist_IO_write_base_unused2_IO_read_ptr_IO_buf_endmain_next__pad1__pad2__pad3__pad4__pad5short unsigned int_IO_write_end__off64_t_fileno_chain__off_t_IO_backup_base_flags2_mode_IO_read_base_vtable_offset_IO_save_basegdsswapstdout_IO_lock_ttm_hourgds_write_colrow__ssize_tgds_read_boxcount_dacount_dpsigncurrent_cellcount_dvmagnificationdegeneratesgds_read_datatypegensgds_swap4bytesabs_anglegds_read_xygds_read_headergds_write_widthtm_isdstgds_read_boxtypegds_read_stransmax_forward_refsnextcelllibrarycell_table_sizegds_write_boxtypevaluegds_write_headergds_read_anglegds_write_stranscol_pitchfexponentgds_read_pathtypetm_mingds_read_presentationPdbu_uustupidgds_write_xygds_read_widthmantforward_numgds_read_textgds_write_boundarytm_secbitmaskgds_write_presentationgds_read_pathcell_numbergds_write_anglegds_read_layerlibgds.cbit13bit14nrowsgds_make_next_itemgds_write_snamemantitagds_write_textrow_pitchverbosetm_monncolsgds_write_pathsecondminutegds_write_strnameforward_ref_initcountgds_write_layerbit0gds_swap2bytesgds_read_bgnstrgds_write_magfirst_cellbitmforward_namenum_cellsgds_write_libnamegds_read_endstrgds_read_boundaryhor_presentgds_celltypefonttm_mdayreflectgds_write_texttypegds_write_pathtypegds_create_textgds_read_strnamegds_read_snamegds_create_lib_correctlygds_write_bgnstrcol_pitchygds_itemtypetm_wdaygds_read_doubletm_ydaygds_write_endstr__time_tver_presentgds_read_libnamegds_read_floatgds_read_arefgds_read_stringsirowsmonthgds_read_maggds_read_bgnlibmantissaPdbu_mgds_write_datatypetm_gmtoffgds_create_libgds_write_boxgds_read_endlibnextitemsicolsgds_read_endelgds_bindumpfourgds_read_srefgds_read_texttypegds_read_generationsgds_read_unitsgds_write_generationsgds_write_arefpath_endtm_zonegds_write_floatabs_maggds_write_stringgds_read_colrowcurrent_itemuu_umgds_write_bgnlibtokentm_yearPdbu_ummessagegds_write_endlibgds_write_sreftempgds_write_endeldategds_write_unitsrow_pitchx8@T@t@@@@@@ 0@ `@ p@ @ @\\@p\@(j@l@~`~`~`~```Ȁ`` ~` 0 @ ` @. @D`S~`z @~`````  `(` 0`̀`.8`7@`AH`KJ`VL`_N`iP`uR`T`V`X`Z`\```b`d`h`p`x``` ```#`.`@`G`N`Wă`^ȃ`gЃ`o؃`x܃`ރ```````Ѐ``` `` `!"`,$`7(`I0`T2`_8`q@`|B`H`P`R`T`X```b`h`p`r`x``%`0`B`M`X`c`n``````````…`ą`ȅ`Ѕ`҅`'ԅ`2օ`;؅`Fڅ`Q`c`l`w````````````````(`3 `E(`N,`_0`g4`n8`u<`|@`D`H`L`P`T`X`Z`\```d`h`p` t`x`"z`.|`9~`D`V`a`l`~````v@~`~`~`~`(j@` @$ @-5 q6@F -@Wl ;@? X@`& Ȁ` [@ C@ 8@[ ;@[   &@[/  tZ@>  !@N a  }5@vn Ԁ`u  &@t  +T@   Y@w  @@\\@  M!@"   C&@R  %@?   K@!  H@B8  T@I  KU@)Z  @m  I@}  +@  2@     I@6  4@v  $ Ȁ`1 E  ';@[T  @@:c  tV@r  @ ` x\@  08@v p\@  :@vq  E@  o#@:  A@  *@  d'@o,  p@e< N  L@>Z  @j ~   JL@Y  W@`  @?*  @  R@J  =@  5@~  9@v  >@  "5@[ ( Ԁ`4  o>@D  z@P  @{U  9@c `k  (@-|  V:@[  C@   @g  ?@   <@  mB@ T7@ |Y@) <@9K؀`6  p@W [@rp %@[ MF@4 Y@w w9@[ /@*crtstuff.c__JCR_LIST__deregister_tm_clones__do_global_dtors_auxcompleted.6355__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrywrite_gds_examples.clibgds.ctemp.5033temp.5037current_item.5041b.5087current_item.5195cell.5193current_cell.5194first_cell.5191now.5202date.5203year.5204month.5205day.5206hour.5207minute.5208second.5209count.5211token.5210count.5224token.5225i.5231count.5238token.5239pad.5254ps.5255cell.5270current_cell.5271len.5277pad.5280ps.5281i.5278count.5276token.5279current_item.5294m.5297n.5296str.5295i.5298len.5309ps.5311pad.5310i.5308count.5306token.5307current_item.5334cell.5333name.5328i.5329forward_ref_init.5330max_forward_refs.5331forward_name.5332len.5343pad.5346ps.5347i.5344count.5342token.5345current_item.5360count.5368token.5369current_item.5376count.5384token.5385current_item.5393num.5392count.5398token.5399current_item.5407count.5414token.5415current_item.5423count.5430token.5431current_item.5439count.5446token.5447current_item.5455count.5462token.5463count.5476token.5477current_item.5485num.5484count.5490token.5491current_item.5499num.5498count.5504token.5505current_item.5513num.5512count.5518token.5519current_item.5527num.5526count.5532token.5533num.5539count.5544token.5545current_item.5553num.5552count.5558token.5559current_item.5570num.5566font.5569vp.5567hp.5568num.5579count.5578token.5577current_item.5590num.5586bit0.5587bit13.5588bit14.5589strans.5599count.5597token.5598current_item.5623num.5613degenerates.5618ii.5612i.5611x.5614y.5615angle.5622count_da.5619px.5616py.5617count_dv.5620count_dp.5621count.5633token.5634i.5635xx.5636yy.5637current_item.5649ncols.5647nrows.5648sicols.5657sirows.5658count.5655token.5656current_item.5683count.5688token.5689current_item.5697count.5702token.5703xx.5726yy.5727__FRAME_END____JCR_END____init_array_end_DYNAMIC__init_array_start__GNU_EH_FRAME_HDR_GLOBAL_OFFSET_TABLE___libc_csu_finigds_write_bgnlibgds_read_boxtypegds_write_stringputchar@@GLIBC_2.2.5localtime@@GLIBC_2.2.5gds_read_endelgds_read_magstdout@@GLIBC_2.2.5strcpy@@GLIBC_2.2.5gds_create_textgds_write_generationsgds_write_pathgds_write_endelputs@@GLIBC_2.2.5gds_write_endstrgds_create_libgds_read_doublewrite@@GLIBC_2.2.5gds_read_box_edatagds_read_libnamegds_read_colrowgds_write_anglegds_read_texttypegds_read_bgnstrstrlen@@GLIBC_2.2.5gds_read_endstrgds_read_endlibprintf@@GLIBC_2.2.5gds_write_stransgds_write_presentationgds_write_headergds_write_colrowgds_make_next_itemgds_read_stransgds_read_stringgds_write_snamepow@@GLIBC_2.2.5log@@GLIBC_2.2.5close@@GLIBC_2.2.5gds_swap2bytesgds_read_boundaryread@@GLIBC_2.2.5__libc_start_main@@GLIBC_2.2.5__data_startstrcmp@@GLIBC_2.2.5gds_write_textgds_read_floatgds_read_unitsgds_write_floatgdsword__gmon_start____dso_handlegds_read_path_IO_stdin_usedgds_read_textgds_write_pathtypegds_write_bgnstrgds_write_texttypegds_write_strnamegds_write_libname__libc_csu_initpowf@@GLIBC_2.2.5gds_read_xygds_read_bgnlibmalloc@@GLIBC_2.2.5fflush@@GLIBC_2.2.5naggds_write_unitsgds_read_headergds_write_xygds_read_widthgds_write_boxgds_read_srefgds_read_datatypegds_write_boundaryrealloc@@GLIBC_2.2.5__bss_startgds_write_widthgds_bindumpmaingds_read_arefgdsswapgds_read_strnamegds_write_arefgds_read_pathtypeopen@@GLIBC_2.2.5gds_swap4bytesgds_write_datatypefloor@@GLIBC_2.2.5gds_read_layergds_read_generationsgds_write_boxtypegds_read_anglegds_write_layerexit@@GLIBC_2.2.5__TMC_END__gds_create_lib_correctlygds_write_endlibgds_read_presentationgds_write_maggds_write_srefgds_read_sname.symtab.strtab.shstrtab.interp.note.ABI-tag.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.init_array.fini_array.jcr.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_str8@8#T@T 1t@t$Do@$N @@V@^o@0ko@@z0@00B`@`p@p@p @ \R\\@\\ p\@p\ (j@(jll@l ~`~~`~~`~~`~``Ȁ`Ȁ `Ԁ 0Ԁ-`a.#1 =0¿ H! H