/* XTrkCad - Model Railroad CAD * Copyright (C) 2005 Dave Bullis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include int dumpUnknownRoadnames; int updateRoadnames; int newRoadnameCnt; #if _MSC_VER > 1300 #define stricmp _stricmp #define strnicmp _strnicmp #define strdup _strdup #endif #ifndef WIN32 #define stricmp strcasecmp #define strnicmp strncasecmp #endif // !WIN32 typedef struct { char * key; char * value; } map_element_t; typedef struct { int max; int cnt; map_element_t * map; } map_t; void readMap( char * mapFile, map_t * map ) { FILE * mapF; char line[256]; size_t len; mapF = fopen( mapFile, "r" ); if ( mapF == NULL ) { perror( mapFile ); exit(1); } while ( fgets( line, sizeof line, mapF ) != NULL ) { char *cp1; if ( map->cnt+1 > map->max ) { map->max += 10; map->map = (map_element_t*)realloc( map->map, map->max * sizeof *(map_element_t*)0 ); } cp1 = strchr( line, '\t' ); if ( cp1 == NULL ) { fprintf( stderr, "bad map line: %s\n", line ); continue; } while ( *cp1 == '\t' ) *cp1++ = '\0'; len = strlen( cp1 ); if ( cp1[len-1] == '\n' ) cp1[len-1] = '\0'; map->map[map->cnt].key = strdup( line ); map->map[map->cnt].value = strdup( cp1 ); map->cnt++; } fclose( mapF ); } struct roadname_t; typedef struct roadname_t * roadname_p; typedef struct roadname_t { roadname_p next; roadname_p alias; char * name; } roadname_t; roadname_p roadnames; roadname_p roadname_last; roadname_p alias_last; void readRoadnameMap( char * mapFile ) { FILE * mapF; char line[256]; roadname_p r_p; char * cp; mapF = fopen( mapFile, "r" ); if ( mapF == NULL ) { perror( mapFile ); exit(1); } while ( fgets( line, sizeof line, mapF ) != NULL ) { size_t len = strlen( line ); if ( line[len-1] == '\n' ) line[--len] = '\0'; if ( line[0] == '\0' || line[0] == '\n' || line[0] == '#' ) continue; r_p = (roadname_p)malloc( sizeof *r_p ); cp = line; if ( *cp != '\t' ) { cp = strchr( line, '\t' ); if ( cp != NULL ) *cp++ = '\0'; r_p->next = NULL; r_p->alias = NULL; r_p->name = strdup( line ); if ( roadnames == NULL ) roadnames = r_p; else roadname_last->next = r_p; roadname_last = r_p; alias_last = r_p; r_p = (roadname_p)malloc( sizeof *r_p ); } else { cp++; } r_p->next = NULL; r_p->alias = NULL; r_p->name = strdup(cp); alias_last->alias = r_p; alias_last = r_p; } fclose( mapF ); } char * lookupMap( map_t * map, char * key ) { int inx; for ( inx=0; inxcnt; inx++ ) if ( stricmp( key, map->map[inx].key ) == 0 ) return map->map[inx].value; return NULL; } map_t colorMap; map_t roadnameMap; long lookupColor( char * colorS ) { if ( colorS == NULL || colorS[0] == '\0' ) return 0x823F00; if ( !isdigit( colorS[0] ) ) colorS = lookupMap( &colorMap, colorS ); return strtol( colorS, &colorS, 10 ); } void capitalize( char * name ) { char * cp; if ( name[0] == '\0' ) return; name[0] = toupper( name[0] ); for ( cp=name+1; *cp; cp++ ) if ( ! isalpha(cp[-1]) ) *cp = toupper( *cp ); else *cp = tolower( *cp ); } void canonicalize( char * name ) { char * cp, * cq; for ( cp=cq=name; *cp; cp++ ) { if ( *cp== '.' || *cp == ',' || *cp == '-' ) { *cp = ' '; } else if ( strnicmp( cp, " and ", 5 ) == 0 ) { cp[1] = '&'; cp[2] = ' '; cp[3] = ' '; } if ( cp[0]!=' ' || ( cp!=name && cp[-1]!=' ' ) ) *cq++ = *cp; } while ( cq[-1] == ' ' ) cq--; *cq++ = '\0'; } void lookupRoadname( char * key, char * roadnameS, char * repmarkS ) { roadname_p r_p1, r_p2; canonicalize( key ); if ( key == NULL || key[0] == '\0' || strnicmp( key, "undec", 5 ) == 0 ) { roadnameS[0] = '\0'; repmarkS[0] = '\0'; return; } for ( r_p1 = roadnames; r_p1; r_p1 = r_p1->next ) { for ( r_p2 = r_p1; r_p2; r_p2 = r_p2->alias ) { if ( stricmp( key, r_p2->name ) == 0 ) { if ( r_p1->name[0] != '?' ) strcpy( repmarkS, r_p1->name ); else repmarkS[0] = '\0'; strcpy( roadnameS, r_p1->alias->name ); return; } } } newRoadnameCnt++; strcpy( roadnameS, key ); capitalize( roadnameS ); repmarkS[0] = '\0'; if ( dumpUnknownRoadnames ) fprintf( stderr, "unknown roadname: %s\n", roadnameS ); r_p2 = (roadname_p)malloc( sizeof *r_p2 ); r_p2->name = strdup(roadnameS); r_p2->next = NULL; r_p2->alias = NULL; r_p1 = (roadname_p)malloc( sizeof *r_p2 ); r_p1->next = NULL; r_p1->alias = r_p2; r_p1->name = ""; roadname_last->next = r_p1; roadname_last = r_p1; alias_last = r_p2; if ( updateRoadnames ) { FILE * roadF; roadF = fopen( "roadname.tab", "a" ); if ( roadF == NULL ) { perror( "roadname.tab" ); updateRoadnames = 0; return; } fprintf( roadF, "?\t%s\n", roadnameS ); fclose( roadF ); } } void processFile( char * inFile, char * outFile ) { FILE * inF, * outF; char line[1024]; char manuf[256]; char proto[256]; char desc[256]; long color; char scale[256]; double length = 0.0; double width = 0.0; double couplerLength = 0.0; double truckCenter = 0.0; double ratio = 0.0; int option = 0; int type = 30100; int lineNumber = 0; char roadnameS[256]; char repmarkS[256]; size_t len; int inx; char * cp, *cq; char * tab[20]; char blanks[10]; size_t partX = 1; size_t descX = 2; size_t roadX = 3; size_t numbX = 4; size_t colorX = 5; inF = fopen( inFile, "r" ); if ( inF == NULL ) { perror( inFile ); return; } outF = fopen( outFile, "w" ); if ( outF == NULL ) { perror( outFile ); fclose( inF ); return; } while ( fgets( line, sizeof line, inF ) != NULL ) { lineNumber++; if ( line[0] == '\n' || line[0] == '#' ) continue; len = strlen(line); if ( len >= 1 && line[len-1] == '\n' ) line[len-1] = '\0'; if ( len >= 2 && line[len-2] == '\r' ) line[len-2] = '\0'; if ( strnicmp( line, "scale=", 6 ) == 0 ) { strcpy( scale, line+6 ); if ( stricmp( scale, "N" ) == 0 ) ratio = 160.0; else if ( stricmp( scale, "HO" ) == 0 || stricmp(scale, "HOn3") == 0 ) ratio = 87.1; else if ( stricmp( scale, "S" ) == 0 || stricmp(scale, "Sn3") == 0 ) ratio = 64.0; else if ( stricmp(scale, "O") == 0 || stricmp(scale, "On3") == 0 || stricmp(scale, "On30") == 0 ) ratio = 48.0; else if ( stricmp(scale, "1") == 0 ) ratio = 32.0; else if ( stricmp(scale, "A") == 0 ) ratio = 29.0; else if ( stricmp(scale, "G") == 0 ) ratio = 22.5; else if ( stricmp(scale, "F") == 0 || stricmp(scale, "Fn2") == 0 || stricmp(scale, "Fn3") == 0 ) ratio = 20.32; else { fprintf( stderr, "%d: Unknown scale %s\n", lineNumber, scale ); ratio = 87.1; } width = 120.0/ratio; couplerLength = 16.0/ratio; } else if ( strnicmp( line, "contents=", 9 ) == 0 ) { fprintf( outF, "CONTENTS %s\n", line+9 ); printf( "Creating %s\n", line + 9 ); } else if ( strnicmp( line, "order=", 6 ) == 0 ) { partX = descX = roadX = numbX = colorX = 0; for ( cp=line+6; *cp; cp++ ) { switch (*cp) { case '#': partX = cp-(line+6)+1; break; case 'd': case 'D': descX = cp-(line+6)+1; break; case 'r': case 'R': roadX = cp-(line+6)+1; break; case 'n': case 'N': numbX = cp-(line+6)+1; break; case '0': break; } } } else if ( strnicmp( line, "manuf=", 6 ) == 0 ) { strcpy( manuf, line+6 ); } else if ( strnicmp( line, "type=", 5 ) == 0 ) { if ( stricmp( line+5, "diesel" ) == 0 ){ option = 1; type = 10101; } else if ( stricmp( line+5, "steam" ) == 0 ){ option = 1; type = 10201; } else if ( stricmp( line+5, "electric" ) == 0 ){ option = 1; type = 10301; } else if ( stricmp( line+5, "freight" ) == 0 ){ option = 0; type = 30100; } else if ( stricmp( line+5, "passenger" ) == 0 ){ option = 0; type = 50100; } else if ( stricmp( line+5, "m-o-w" ) == 0 ){ option = 0; type = 70100; } else if ( stricmp( line+5, "other" ) == 0 ){ option = 0; type = 90100; } else { fprintf( stderr, "%d: Unknown type: %s\n", lineNumber, line+5 ); } } else if ( strnicmp( line, "proto=", 6 ) == 0 ) { strcpy( proto, line+6 ); desc[0] = '\0'; } else if ( strnicmp( line, "desc=", 5 ) == 0 ) { strcpy( desc, line+5 ); } else if ( strnicmp( line, "length=", 7 ) == 0 ) { length = atof( line+7 ); truckCenter = length * 0.75; } else if ( strnicmp( line, "protolength=", 12 ) == 0 ) { length = atof( line+12 ); length = length / ratio; truckCenter = length * 0.75; } else if ( strnicmp( line, "width=", 6 ) == 0 ) { width = atof( line+6 ); } else if ( strnicmp( line, "protowidth=", 11 ) == 0 ) { width = atof( line+11 ); width = width * 12.0 / ratio; } else if ( strnicmp( line, "truckcenter=", 12 ) == 0 ) { truckCenter = atof( line+12 ); } else if ( strnicmp( line, "couplerlength=", 14 ) == 0 ) { couplerLength = atof( line+14 ); } else if ( strnicmp( line, "part=", 5 ) == 0 ) { if ( length == 0.000 ) continue; cp = line+5; memset( blanks, 0, sizeof blanks ); tab[0] = blanks; for ( inx=1; cp; inx++ ) { tab[inx] = cp; cp = strchr( cp, '%' ); if ( cp ) *cp++ = '\0'; while ( *tab[inx] == ' ' ) tab[inx]++; cq = tab[inx]+strlen(tab[inx]); while ( cq[-1] == ' ' ) cq--; *cq = '\0'; } for ( ; inx 0 && argv[0][0] == '-' ) { switch ( argv[0][1] ) { case 'r': dumpUnknownRoadnames++; break; case 'u': updateRoadnames++; break; } argv++; argc--; } if ( argc != 2 ) { fprintf( stderr, "Usage: %s [-r] .car .xtp\n", "mkcarpart" ); exit(1); } readMap( "color.tab", &colorMap ); readRoadnameMap( "roadname.tab" ); processFile( argv[0], argv[1] ); if ( newRoadnameCnt > 0 ) fprintf( stderr, "%d new roadnames\n", newRoadnameCnt ); return 0; }