/* loadsave.c - Created by Giampiero Caprino This file is part of Train Director Train Director 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, or (at your option) any later version. Train Director 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 Train Director; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #if !defined(__unix__) #include #endif #include #include #include "trsim.h" #include "ask.h" #include "html.h" extern void *w_train_pmap_default[4], *w_train_pmap[4]; extern void *e_train_pmap_default[4], *e_train_pmap[4]; extern void *w_car_pmap_default[4], *w_car_pmap[4]; extern void *e_car_pmap_default[4], *e_car_pmap[4]; Path *paths; Vector *findPath(Track *t, int dir); void *Vector_elementAt(Vector *v, int i); void Vector_delete(Vector *v); pxmap *pixmaps; int npixmaps, maxpixmaps; pxmap *carpixmaps; int ncarpixmaps, maxcarpixmaps; extern char current_project[]; static int curtype = 0; int save_prefs; /* localized strings support (1.19) */ char *locale_name = "en"; struct lstring { struct lstring *next; int hash; char *en_string; char *loc_string; }; struct lstring *local_strings; static char *linebuff; static int maxline; static char *getline(FILE *fp) { int i; int c; if(!linebuff) { maxline = 256; linebuff = (char *)malloc(maxline); } i = 0; while((c = getc(fp)) != '\n' && c != EOF) { if(c == '\r') continue; if(i + 1 >= maxline) { maxline += 256; linebuff = (char *)realloc(linebuff, maxline); } linebuff[i++] = c; } linebuff[i] = 0; if(!i && c == EOF) return 0; return linebuff; } void set_full_file_name(char *fullpath, char *filename) { char *p; #if !defined(__unix__) strcpy(fullpath, "C:"); #else strcpy(fullpath, "/tmp"); #endif if((p = getenv("HOME"))) strcpy(fullpath, p); strcat(fullpath, "/.traindir/"); strcat(fullpath, filename); } /* localized strings support (1.19) */ int strhash(char *s) { int h; for(h = 0; *s; h += *s++); /* very poor man's hash algorithm */ return h; } /* convert "\n" into newline characters */ void convert_newlines(char *buff) { int i, j; for(i = j = 0; buff[i]; ++i, ++j) if(buff[i] == '\\' && buff[i+1] == 'n') { buff[j] = '\n'; ++i; } else buff[j] = buff[i]; buff[j] = 0; } char *localize(char *s) { struct lstring *ls; int h; if(!strcmp(locale_name, "en")) return s; h = strhash(s); for(ls = local_strings; ls; ls = ls->next) { if(ls->hash == h && !strcmp(ls->en_string, s)) return ls->loc_string; } return s; } /* Load all localized strings for 'locale'. * Locale values should be in the standard * 2-character international country codes. * By default, ".en" is ignored, since * built-in strings are always in English. */ void load_localized_strings(char *locale) { char buff[512]; char name[64]; FILE *fp; struct lstring *ls; char *p, *p1; int i, j; if(!strcmp(locale, ".en")) return; #if defined (__unix__) sprintf(name, ".traindir%s", locale); #else sprintf(name, "traindir%s", locale); #endif set_full_file_name(buff, name); if(!(fp = fopen(buff, "r"))) return; while((p = getline(fp))) { if(*p == '#') /* comment */ continue; if(!(p1 = strstr(p, "@@"))) continue; strcpy(buff, p1); /* isolate English string */ while(--p1 > p && (*p1 == ' ' || *p1 == '\t')); p1[1] = 0; convert_newlines(p); p1 = strstr(buff, "@@") + 2; while(*p1 == ' ' || *p1 == '\t') ++p1; convert_newlines(p1); ls = (struct lstring *)malloc(sizeof(struct lstring)); ls->hash = strhash(p); ls->en_string = strdup(p); ls->loc_string = strdup(p1); ls->next = local_strings; local_strings = ls; } fclose(fp); } FILE *file_create(char *name) { FILE *fp; char buff[256]; extern int errno; if((fp = fopen(name, "w"))) return fp; sprintf(buff, "%s '%s' - %s %d.", L("Can't create file"), name, L("Error"), errno); error(buff); return 0; } const char *locase(char *s) { char *p; for(p = s; *p; ++p) *p = tolower(*p); return s; } char *skipblk(char *p) { while(*p == ' ' || *p == '\t') ++p; return p; } void clean_field(Track *layout) { Track *t; while(layout) { t = layout->next; if(layout->station) free(layout->station); free(layout); layout = t; } } void add_itinerary(Itinerary *it, int x, int y, int sw) { int i; for(i = 0; i < it->nsects; ++i) if(it->sw[i].x == x && it->sw[i].y == y) { it->sw[i].switched = sw; return; } if(it->nsects >= it->maxsects) { it->maxsects += 10; if(!it->sw) { it->sw = (struct switin *)malloc(sizeof(struct switin) * it->maxsects); } else { it->sw = (struct switin *)realloc(it->sw, sizeof(struct switin) * it->maxsects); } } it->sw[it->nsects].x = x; it->sw[it->nsects].y = y; it->sw[it->nsects].switched = sw; ++it->nsects; } Track *load_field_tracks(char *name) { Track *layout, *t; TextList *tl, *tlast; Itinerary *it; char buff[1024]; FILE *fp; int l; int ttype; int x, y, sw; char *p, *p1; if(!strstr(name, ".trk") && !strstr(name, ".TRK")) sprintf(buff, "%s.trk", name); else strcpy(buff, name); if(!(fp = fopen(buff, "r"))) return 0; tlast = 0; layout = 0; while(fgets(buff, sizeof(buff), fp)) { l = strlen(buff); if(l && buff[l - 1] == '\n') --l; if(l && buff[l - 1] == '\r') --l; buff[l] = 0; t = (Track *)malloc(sizeof(Track)); memset(t, 0, sizeof(Track)); t->fgcolor = fieldcolors[COL_TRACK]; ttype = buff[0]; p = buff + 1; if(*p == ',') ++p; t->x = strtol(p, &p, 10); if(*p == ',') ++p; t->y = strtol(p, &p, 10); if(t->x >= (XMAX / HGRID) || t->y >= (YMAX / VGRID)) continue; if(*p == ',') ++p; t->direction = strtol(p, &p, 10); if(*p == ',') ++p; t->next = layout; layout = t; switch(ttype) { case '0': t->type = TRACK; t->isstation = (char)strtol(p, &p, 10); if(*p == ',') ++p; t->length = strtol(p, &p, 10); if(!t->length) t->length = 1; if(*p == ',') ++p; t->wlinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->wlinky = strtol(p, &p, 10); if(*p == ',') ++p; t->elinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->elinky = strtol(p, &p, 10); if(*p == ',') ++p; if(*p == '@') { t->speed[0] = strtol(++p, &p, 10); if(*p == '/') { t->speed[1] = strtol(++p, &p, 10); if(*p == '/') { t->speed[2] = strtol(++p, &p, 10); if(*p == '/') t->speed[3] = strtol(++p, &p, 10); } } if(*p == ',') ++p; } if(!*p || !strcmp(p, "noname")) break; if(*p == '>') { p = parse_km(t, ++p); if(*p == ',') ++p; } t->station = strdup(p); break; case '1': t->type = SWITCH; t->length = 1; t->wlinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->wlinky = strtol(p, &p, 10); break; /* 2, x, y, type, linkx, linky [itinerary] */ case '2': t->type = TSIGNAL; if((l = t->direction) & 2) { t->fleeted = 1; l &= ~2; } if(l & 0x100) t->fixedred = 1; if(l & 0x200) t->nopenalty = 1; if(l & 0x400) t->signalx = 1; l &= ~0x700; t->direction &= ~0x700; switch(l) { case 0: t->direction = E_W; break; case 1: t->direction = W_E; break; case N_S: case S_N: case signal_SOUTH_FLEETED: case signal_NORTH_FLEETED: /* already there */ t->direction = l; break; } t->wlinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->wlinky = strtol(p, &p, 10); if(*p == ',') ++p; if(*p) /* for itinerary definition */ t->station = strdup(p); break; case '3': t->type = PLATFORM; if(t->direction == 0) t->direction = W_E; else t->direction = N_S; break; case '4': t->type = TEXT; t->station = strdup(p); for(l = 0; t->station[l] && t->station[l] != ','; ++l); t->station[l] = 0; while(*p && *p != ',') ++p; if(*p == ',') ++p; t->wlinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->wlinky = strtol(p, &p, 10); if(*p == ',') ++p; t->elinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->elinky = strtol(p, &p, 10); if(*p == '>') p = parse_km(t, ++p); break; case '5': t->type = IMAGE; t->station = strdup(p); break; case '6': /* territory information */ tl = (TextList *)malloc(sizeof(TextList)); strcat(p, "\n"); /* put it back, since we removed it */ tl->txt = strdup(p); if(!track_info) track_info = tl; else tlast->next = tl; tl->next = 0; tlast = tl; break; case '7': /* itinerary */ for(p1 = p; *p && *p != ','; ++p); if(!*p) break; *p++ = 0; it = (Itinerary *)calloc(sizeof(Itinerary), 1); it->name = strdup(p1); for(p1 = p, l = 0; *p && (*p != ',' || l); ++p) { if(*p == '(') ++l; else if(*p == ')') --l; } if(!*p) break; *p++ = 0; it->signame = strdup(p1); for(p1 = p, l = 0; *p && (*p != ',' || l); ++p) { if(*p == '(') ++l; else if(*p == ')') --l; } if(!*p) break; *p++ = 0; it->endsig = strdup(p1); if(*p == '@') { for(p1 = ++p, l = 0; *p && (*p != ',' || l); ++p) { if(*p == '(') ++l; else if(*p == ')') --l; } if(!*p) break; *p++ = 0; it->nextitin = strdup(p1); } l = 0; while(*p) { x = strtol(p, &p, 0); if(*p != ',') break; y = strtol(++p, &p, 0); if(*p != ',') break; sw = strtol(++p, &p, 0); add_itinerary(it, x, y, sw); if(*p == ',') ++p; } it->next = itineraries; /* all ok, add to the list */ itineraries = it; break; case '8': /* itinerary placement */ t->type = ITIN; t->station = strdup(p); break; case '9': t->type = TRIGGER; t->wlinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->wlinky = strtol(p, &p, 10); if(*p == ',') ++p; t->elinkx = strtol(p, &p, 10); if(*p == ',') ++p; t->elinky = strtol(p, &p, 10); if(*p == ',') ++p; t->speed[0] = strtol(p, &p, 10); if(*p == '/') ++p; t->speed[1] = strtol(p, &p, 10); if(*p == '/') ++p; t->speed[2] = strtol(p, &p, 10); if(*p == '/') ++p; t->speed[3] = strtol(p, &p, 10); if(*p == ',') ++p; if(!*p || !strcmp(p, "noname")) break; t->station = strdup(p); break; } } fclose(fp); return layout; } Track *load_field(char *name) { int l; TextList *tl; Itinerary *it; for(l = 0; l < 4; ++l) { e_train_pmap[l] = e_train_pmap_default[l]; w_train_pmap[l] = w_train_pmap_default[l]; e_car_pmap[l] = e_car_pmap_default[l]; w_car_pmap[l] = w_car_pmap_default[l]; } while((tl = track_info)) { track_info = tl->next; free(tl->txt); free(tl); } while((it = itineraries)) { if(it->signame) free(it->signame); if(it->endsig) free(it->endsig); if(it->sw) free(it->sw); itineraries = it->next; free(it); } return load_field_tracks(name); } Track *find_track(Track *layout, int x, int y) { while(layout) { if(layout->x == x && layout->y == y) return(layout); layout = layout->next; } return 0; } void link_signals(Track *layout) { Track *t; for(t = layout; t; t = t->next) /* in case signal was relinked during edit */ t->esignal = t->wsignal = 0; for(t = layout; t; t = t->next) { /* link signals with the track they control */ if(t->type == TSIGNAL) { if(!(t->controls = findTrack(t->wlinkx, t->wlinky))) continue; if(t->direction == W_E || t->direction == S_N) t->controls->esignal = t; else t->controls->wsignal = t; } } } void clean_pixmap_cache(void) { int i; for(i = 0; i < npixmaps; ++i) if(pixmaps[i].name) free(pixmaps[i].name); npixmaps = 0; for(i = 0; i < ncarpixmaps; ++i) if(carpixmaps[i].name) free(carpixmaps[i].name); ncarpixmaps = 0; } int get_pixmap_index(const char *mapname) { int i; for(i = 0; i < npixmaps; ++i) if(!strcmp(mapname, pixmaps[i].name)) return i; if(npixmaps >= maxpixmaps) { maxpixmaps += 10; if(!pixmaps) pixmaps = (pxmap *)malloc(sizeof(pxmap) * maxpixmaps); else pixmaps = (pxmap *)realloc(pixmaps, sizeof(pxmap) * maxpixmaps); } if(!(pixmaps[npixmaps].pixels = (char *)get_pixmap_file(mapname))) return -1; /* failed! file does not exist */ pixmaps[npixmaps].name = strdup(mapname); return npixmaps++; } int get_carpixmap_index(const char *mapname) { int i; for(i = 0; i < ncarpixmaps; ++i) if(!strcmp(mapname, carpixmaps[i].name)) return i; if(ncarpixmaps >= maxcarpixmaps) { maxcarpixmaps += 10; if(!carpixmaps) carpixmaps = (pxmap *)malloc(sizeof(pxmap) * maxcarpixmaps); else carpixmaps = (pxmap *)realloc(carpixmaps, sizeof(pxmap) * maxcarpixmaps); } if(!(carpixmaps[ncarpixmaps].pixels = (char *)get_pixmap_file(mapname))) return -1; /* failed! file does not exist */ carpixmaps[ncarpixmaps].name = strdup(mapname); return ncarpixmaps++; } void clean_trains(Train *sched) { Train *t; TrainStop *ts, *ts1; clean_pixmap_cache(); while(sched) { if(sched->path) Vector_delete(sched->path); if(sched->name) free(sched->name); if(sched->entrance) free(sched->entrance); if(sched->exit) free(sched->exit); for(ts = sched->stops; ts; ts = ts1) { ts1 = ts->next; if(ts->station) free(ts->station); free(ts); } t = sched->next; free(sched); sched = t; } } int trcmp(const Train **a, const Train **b) { if(a[0]->timein < b[0]->timein) return -1; if(a[0]->timein > b[0]->timein) return 1; return 0; } Train *sort_schedule(Train *sched) { Train **qb, *t; int ntrains; int l; for(t = sched, ntrains = 0; t; t = t->next) ++ntrains; if(!ntrains) return sched; qb = (Train **)malloc(sizeof(Train *) * ntrains); for(t = sched, l = 0; l < ntrains; ++l, t = t->next) qb[l] = t; qsort(qb, ntrains, sizeof(Train *), trcmp); for(l = 0; l < ntrains - 1; ++l) qb[l]->next = qb[l + 1]; qb[ntrains - 1]->next = 0; t = qb[0]; free(qb); return t; } char *convert_station(char *p) { return(p); } Train *cancelTrain(char *p, Train *sched) { Train *t, *t1; t1 = 0; for(t = sched; t && strcmp(t->name, p); t = t->next) t1 = t; if(!t) return sched; if(t == sched) sched = t->next; else t1->next = t->next; free(t->name); free(t); return sched; } static Train *sched; Train *parse_newformat(FILE *fp) { Train *t, *t1; TrainStop *stp; char buff[1024]; int l; char *p; char fileinc[256]; char *nw, *ne; FILE *f1; t = 0; while(fgets(buff, sizeof(buff), fp)) { l = strlen(buff); if(l && buff[l - 1] == '\n') --l; if(l && buff[l - 1] == '\r') --l; while(l && (buff[l - 1] == ' ' || buff[l - 1] == '\t')) --l; buff[l] = 0; if(!l) continue; if(buff[0] == '.') { t = 0; continue; } for(l = 0; buff[l]; ++l) if(buff[l] == '\t') buff[l] = ' '; if(!strncmp(buff, "Include: ", 9)) { for(p = buff + 9; *p == ' '; ++p); if(!*p) continue; if(!(f1 = fopen(p, "r"))) { sprintf(fileinc, "%s/%s", curpath, locase(p)); if(!(f1 = fopen(fileinc, "r"))) { sprintf(fileinc, "%s/%s", curpath, p); if(!(f1 = fopen(fileinc, "r"))) continue; } } parse_newformat(f1); fclose(f1); #if 0 if(!sched) { sched = t; continue; } for(t1 = t; t->next; t = t->next); t->next = sched; sched = t1; #endif t = 0; continue; } if(!strncmp(buff, "Cancel: ", 8)) { for(p = buff + 8; *p == ' '; ++p); if(!*p) continue; sched = cancelTrain(p, sched); t = 0; continue; } if(!strncmp(buff, "Today: ", 7)) { for(p = buff + 7; *p == ' '; ++p); for(l = 0; *p >= '0' && *p <= '9'; ++p) l |= 1 << (*p - '1'); run_day = l; continue; } if(!strncmp(buff, "Start: ", 7)) { p = buff + 7; current_time = start_time = parse_time(&p); continue; } if(!strncmp(buff, "Train: ", 7)) { for(t = sched; t; t = t->next) if(!strcmp(t->name, buff + 7)) break; if(t) continue; t = (Train *)malloc(sizeof(Train)); memset(t, 0, sizeof(Train)); t->name = strdup(buff + 7); t->next = sched; t->type = curtype; t->epix = t->wpix = -1; t->ecarpix = t->wcarpix = -1; sched = t; continue; } if(!t) { if(!strncmp(buff, "Type: ", 6)) { if((l = strtol(buff + 6, &p, 0) - 1) >= 4 || l < 0) continue; curtype = l; if(!p) continue; while(*p == ' ' || *p == '\t') ++p; if(!*p) continue; nw = p; while(*p && *p != ' ' && *p != '\t') ++p; if(!*p) continue; *p++ = 0; while(*p == ' ' || *p == '\t') ++p; ne = p; while(*p && *p != ' ' && *p != '\t') ++p; l = *p; *p++ = 0; if(!(nw = (char *)get_pixmap_file(locase(nw)))) continue; if(!(ne = (char *)get_pixmap_file(locase(ne)))) continue; w_train_pmap[curtype] = nw; e_train_pmap[curtype] = ne; if(!l) continue; while(*p == ' ' || *p == '\t') ++p; ne = p; while(*p && *p != ' ' && *p != '\t') ++p; l = *p; *p++ = 0; if(!(nw = (char *)get_pixmap_file(locase(ne)))) continue; w_car_pmap[curtype] = nw; e_car_pmap[curtype] = nw; if(!l) continue; while(*p == ' ' || *p == '\t') ++p; if(!*p) continue; if(!(ne = (char *)get_pixmap_file(locase(p)))) continue; e_car_pmap[curtype] = ne; } continue; } p = buff; while(*p == ' ' || *p == '\t') ++p; if(!strncmp(p, "Wait: ", 6)) { p += 6; while(*p == ' ' || *p == '\t') ++p; for(nw = p; *nw && *nw != ' '; ++nw); if(*nw) *nw++ = 0; else nw = 0; t->waitfor = strdup(p); t->waittime = nw ? atoi(nw) : 60; continue; } if(!strncmp(p, "When: ", 6)) { for(p += 6; *p == ' '; ++p); for(l = 0; *p >= '0' && *p <= '9'; ++p) l |= 1 << (*p - '1'); t->days = l; continue; } if(!strncmp(p, "Speed: ", 7)) { t->maxspeed = atoi(p + 7); continue; } if(!strncmp(p, "Type: ", 6)) { if((l = strtol(p + 6, &p, 0)) - 1 < 4) t->type = l - 1; if(!p || !*p) continue; while(*p == ' ' || *p == '\t') ++p; if(!*p) continue; nw = p; while(*p && *p != ' ' && *p != '\t') ++p; if(!*p) continue; *p++ = 0; while(*p == ' ' || *p == '\t') ++p; if((t->wpix = get_pixmap_index(locase(nw))) < 0) continue; t->epix = get_pixmap_index(locase(p)); continue; } if(!strncmp(p, "Stock: ", 7)) { t->stock = strdup(p + 7); continue; } if(!strncmp(p, "Length: ", 8)) { t->length = strtol(p + 8, &p, 0); t->tail = (Train *)calloc(sizeof(Train), 1); t->ecarpix = t->wcarpix = -1; while(*p == ' ' || *p == '\t') ++p; if(!*p) continue; ne = p; while(*p && *p != ' ' && *p != '\t') ++p; l = *p; *p++ = 0; t->ecarpix = t->wcarpix = get_carpixmap_index(locase(ne)); if(!l) continue; while(*p == ' ' || *p == '\t') ++p; if(!*p) continue; t->wcarpix = get_carpixmap_index(locase(p)); continue; } if(!strncmp(p, "Enter: ", 7)) { p += 7; t->timein = parse_time(&p); if(*p == ',') ++p; while(*p == ' ' || *p == '\t') ++p; t->entrance = strdup(convert_station(p)); continue; } if(!strncmp(p, "Notes: ", 7)) { p += 7; if(t->nnotes < MAXNOTES) t->notes[t->nnotes++] = strdup(p); continue; } stp = (TrainStop *)malloc(sizeof(TrainStop)); memset(stp, 0, sizeof(TrainStop)); stp->minstop = 30; if(*p == '-') { /* doesn't stop */ while(*++p == ' ' || *p == '\t'); stp->minstop = 0; } else l = parse_time(&p); /* arrival */ if(*p == ',') ++p; while(*p == ' ' || *p == '\t') ++p; if(*p == '-') { free(stp); if(t->exit) /* already processed exit point! */ continue; t->timeout = l; while(*++p == ' ' || *p == '\t'); if(*p == ',') ++p; while(*p == ' ' || *p == '\t') ++p; t->exit = strdup(convert_station(p)); continue; } stp->departure = parse_time(&p); stp->arrival = stp->minstop ? l : stp->departure; if(*p == ',') ++p; while(*p == ' ' || *p == '\t') ++p; stp->station = strdup(convert_station(p)); if(!t->stops) t->stops = stp; else t->laststop->next = stp; t->laststop = stp; } return(sched); } void check_delayed_entries(Train *sched) { Train *t, *t1; Track *trk, *tk1; int firsttime = 1; int i; char buff[256]; /* Check entrance conflicts */ for(t = sched; t; t = t->next) { for(t1 = t->next; t1; t1 = t1->next) { if(t->timein != t1->timein) continue; if(t->days && t1->days && run_day) if(!(t->days & t1->days)) continue; if(strcmp(t->entrance, t1->entrance)) continue; for(trk = layout; trk; trk = trk->next) if(trk->type == TRACK && trk->isstation && !strcmp(t->entrance, trk->station)) break; if(trk) continue; if(firsttime) { layout_error(L("These trains will be delayed on entry:")); layout_error("\n"); } firsttime = 0; sprintf(buff, L("%s and %s both enter at %s on %s"), t->name, t1->name, t->entrance, format_time(t->timein)); strcat(buff, "\n"); layout_error(buff); } } firsttime = 1; for(t = sched; t; t = t->next) { trk = findStationNamed(t->entrance); if(!trk) { strcpy(buff, t->entrance); for(i = 0; buff[i] && buff[i] != ' '; ++i); buff[i] = 0; trk = findStationNamed(buff); } tk1 = findStationNamed(t->exit); if(!tk1) { strcpy(buff, t->exit); for(i = 0; buff[i] && buff[i] != ' '; ++i); buff[i] = 0; tk1 = findStationNamed(buff); } if(trk && tk1) continue; if(firsttime) { layout_error(L("These trains have unknown entry or exit points:")); layout_error("\n"); } firsttime = 0; sprintf(buff, L("%s enters from '%s', exits at '%s'"), t->name, t->entrance, t->exit); strcat(buff, "\n"); layout_error(buff); } end_layout_error(); } static Path *find_path(char *from, char *to) { Path *pt; for(pt = paths; pt; pt = pt->next) { if(!pt->from || !pt->to || !pt->enter) continue; if(sameStation(from, pt->from) && sameStation(to, pt->to)) return pt; } return 0; } static void resolve_path(Train *t) { Path *pt, *pth; TrainStop *ts, *tt; long t0; int f1; if(findStationNamed(t->entrance)) { f1 = 1; goto xit; } f1 = 0; for(ts = t->stops; ts; ts = ts->next) { if((pt = find_path(t->entrance, ts->station))) { t->entrance = strdup(pt->enter); t->timein = ts->arrival - pt->times[t->type]; f1 = 1; goto xit; } } for(tt = t->stops; tt; tt = tt->next) { for(ts = tt->next; ts; ts = ts->next) { if((pt = find_path(tt->station, ts->station))) { t->entrance = strdup(pt->enter); t->timein = ts->arrival - pt->times[t->type]; f1 = 1; goto xit; } } } xit: if(findStation(t->exit)) { if(f1) /* both entrance and exit in layout */ return; pth = 0; for(tt = t->stops; tt; tt = tt->next) if((pt = find_path(tt->station, t->exit))) pth = pt; if(!pth) pth = find_path(t->entrance, t->exit); if(!pth) return; t->entrance = strdup(pth->enter); t->timein = t->timeout - pth->times[t->type]; return; } pth = 0; for(tt = t->stops; tt; tt = tt->next) { for(ts = tt->next; ts; ts = ts->next) { if((pt = find_path(tt->station, ts->station))) { t0 = tt->departure; pth = pt; } } } for(ts = t->stops; ts; ts = ts->next) if((pt = find_path(ts->station, t->exit))) { t0 = ts->departure; pth = pt; } if(pth) { t->exit = strdup(pth->enter); t->timeout = t0 + pth->times[t->type]; return; } if(!f1) return; for(ts = t->stops; ts; ts = ts->next) if((pt = find_path(t->entrance, ts->station))) { t->exit = strdup(pt->enter); t->timeout = t->timein + pt->times[t->type]; return; } if((pt = find_path(t->entrance, t->exit))) { t->exit = strdup(pt->enter); t->timeout = t->timein + pt->times[t->type]; } } void resolve_paths(Train *schedule) { Train *t; if(!paths) return; for(t = schedule; t; t = t->next) resolve_path(t); } void load_paths(char *name) { Path *pt; char buff[1024]; FILE *fp; int l; char *p, *p1; int errors; while(paths) { pt = paths->next; if(paths->from) free(paths->from); if(paths->to) free(paths->to); if(paths->enter) free(paths->enter); free(paths); paths = pt; } sprintf(buff, "%s.pth", name); if(!(fp = fopen(buff, "r"))) return; pt = 0; errors = 0; while(fgets(buff, sizeof(buff), fp)) { l = strlen(buff); if(l && buff[l - 1] == '\n') --l; if(l && buff[l - 1] == '\r') --l; buff[l] = 0; p = skipblk(buff); if(!*p || *p == '#') continue; if(!strcmp(p, "Path:")) { if(pt) { /* end previous entry */ if(!pt->from || !pt->to || !pt->enter) { ++errors; paths = pt->next; /* ignore last entry */ free(pt); } } p += 5; pt = (Path *)calloc(sizeof(Path), 1); pt->next = paths; paths = pt; continue; } if(!strncmp(p, "From: ", 6)) pt->from = strdup(skipblk(p + 6)); if(!strncmp(p, "To: ", 4)) pt->to = strdup(skipblk(p + 4)); if(!strncmp(p, "Times: ", 7)) { p += 7; for(p1 = p; *p1 && *p1 != ' '; ++p1); if(!*p1) /* no entry point! */ continue; *p1++ = 0; for(l = 0; l < 4; ++l) { pt->times[l] = strtol(p, &p, 10) * 60; if(*p == '/' || *p == ',') ++p; } p = skipblk(p1); pt->enter = strdup(p); } } fclose(fp); } Train *load_trains(char *name) { Train *t; TrainStop *stp; char buff[1024]; FILE *fp; int l; char *p, *p1; int newformat; if(strstr(name, ".sch") || strstr(name, ".SCH")) { strcpy(buff, name); strcpy(buff + strlen(buff) - 4, ".sch"); } else sprintf(buff, "%s.sch", name); if(!(fp = fopen(buff, "r"))) return 0; curpath = g_dirname(buff); sched = 0; newformat = 0; start_time = 0; curtype = 0; while(fgets(buff, sizeof(buff), fp)) { l = strlen(buff); if(l && buff[l - 1] == '\n') --l; if(l && buff[l - 1] == '\r') --l; buff[l] = 0; if(!l) continue; if(newformat || !strcmp(buff, "#!trdir")) { newformat = 1; t = parse_newformat(fp); if(!t) continue; sched = t; continue; } if(buff[0] == '#') continue; t = (Train *)malloc(sizeof(Train)); memset(t, 0, sizeof(Train)); t->next = sched; sched = t; for(p = buff; *p && *p != ','; ++p); if(!*p) continue; *p++ = 0; t->name = strdup(buff); t->status = train_READY; t->direction = t->sdirection = strtol(p, &p, 10); if(*p == ',') ++p; t->timein = parse_time(&p); if(*p == ',') ++p; p1 = p; while(*p && *p != ',') ++p; if(!*p) continue; *p++ = 0; t->entrance = strdup(p1); t->timeout = parse_time(&p); if(*p == ',') ++p; p1 = p; while(*p && *p != ',') ++p; if(!*p) continue; *p++ = 0; t->exit = strdup(p1); t->maxspeed = strtol(p, &p, 10); if(*p == ',') ++p; while(*p) { for(p1 = p; *p && *p != ','; ++p); if(!*p) continue; *p++ = 0; stp = (TrainStop *)malloc(sizeof(TrainStop)); memset(stp, 0, sizeof(TrainStop)); if(!t->stops) t->stops = stp; else t->laststop->next = stp; t->laststop = stp; stp->station = strdup(p1); stp->arrival = parse_time(&p); if(*p == ',') ++p; stp->departure = parse_time(&p); if(*p == ',') ++p; stp->minstop = strtol(p, &p, 10); if(*p == ',') ++p; } } fclose(fp); /* check correctness of schedule */ l = 0; for(t = sched; t; t = t->next) { if(!t->exit) { t->exit = strdup("?"); ++l; } if(!t->entrance) { t->entrance = strdup("?"); ++l; } } if(l) error(L("Some train has unknown entry/exit point!")); load_paths(name); resolve_paths(sched); sched = sort_schedule(sched); return sched; } /* ================================= */ int save_layout(char *name, Track *layout) { FILE *fp; char buff[256]; Track *t; TextList *tl; Itinerary *it; int i; sprintf(buff, "%s.trk", name); if(!(fp = file_create(buff))) return 0; for(t = layout; t; t = t->next) { switch(t->type) { case TRACK: fprintf(fp, "0,%d,%d,%d,", t->x, t->y, t->direction); fprintf(fp, "%d,%d,", t->isstation, t->length); fprintf(fp, "%d,%d,%d,%d,", t->wlinkx, t->wlinky, t->elinkx, t->elinky); if(t->speed[0]) fprintf(fp, "@%d/%d/%d/%d,", t->speed[0], t->speed[1], t->speed[2], t->speed[3]); if(t->km) fprintf(fp, ">%d.%d,", t->km / 1000, t->km % 1000); if(t->isstation && t->station) fprintf(fp, "%s\n", t->station); else fprintf(fp, "noname\n"); break; case SWITCH: fprintf(fp, "1,%d,%d,%d,", t->x, t->y, t->direction); fprintf(fp, "%d,%d\n", t->wlinkx, t->wlinky); break; case TSIGNAL: fprintf(fp, "2,%d,%d,%d,", t->x, t->y, t->direction + t->fleeted * 2 + (t->fixedred << 8) + (t->nopenalty << 9) + (t->signalx << 10)); fprintf(fp, "%d,%d", t->wlinkx, t->wlinky); if(t->station && *t->station) /* for itineraries */ fprintf(fp, ",%s", t->station); fprintf(fp, "\n"); break; case PLATFORM: fprintf(fp, "3,%d,%d,%d\n", t->x, t->y, t->direction == W_E ? 0 : 1); break; case TEXT: fprintf(fp, "4,%d,%d,%d,%s,", t->x, t->y, t->direction, t->station); fprintf(fp, "%d,%d,%d,%d", t->wlinkx, t->wlinky, t->elinkx, t->elinky); if(t->km) fprintf(fp, ">%d.%d", t->km / 1000, t->km % 1000); fprintf(fp, "\n"); break; case IMAGE: if(!t->station) t->station = strdup(""); for(i = strlen(t->station); i >= 0; --i) if(t->station[i] == '/' || t->station[i] == '\\') break; fprintf(fp, "5,%d,%d,0,%s\n", t->x, t->y, t->station + i + 1); break; case ITIN: fprintf(fp, "8,%d,%d,%d,%s\n", t->x, t->y, t->direction, t->station); break; case TRIGGER: fprintf(fp, "9,%d,%d,%d,", t->x, t->y, t->direction); fprintf(fp, "%d,%d,%d,%d,", t->wlinkx, t->wlinky, t->elinkx, t->elinky); fprintf(fp, "%d/%d/%d/%d,", t->speed[0], t->speed[1], t->speed[2], t->speed[3]); fprintf(fp, "%s\n", t->station); break; } } for(tl = track_info; tl; tl = tl->next) fprintf(fp, "6,0,0,0,%s\n", tl->txt); for(it = itineraries; it; it = it->next) { fprintf(fp, "7,0,0,0,%s,%s,%s,", it->name, it->signame, it->endsig); if(it->nextitin) fprintf(fp, "@%s,", it->nextitin); for(i = 0; i < it->nsects; ++i) fprintf(fp, "%d,%d,%d,", it->sw[i].x, it->sw[i].y, it->sw[i].switched); fprintf(fp, "\n"); } fclose(fp); return 1; } #define MAXSHORTNAME 10 static void short_station_name(char *d, char *s) { int i; for(i = 0; *s && *s != ' ' && i < MAXSHORTNAME - 1; ++i) *d++ = *s++; *d = 0; } void format_schedule(Train *t, char *dst) { TrainStop *ts; char entr[MAXSHORTNAME]; char ext[MAXSHORTNAME]; print_train_info(t); short_station_name(entr, t->entrance); short_station_name(ext, t->exit); sprintf(dst, "%-8s : %-6s %6s : %-6s %6s : %6s : %6s : %s\n", t->name, entr, entering_time, ext, leaving_time, current_delay, current_late, current_status); for(ts = t->stops; ts; ts = ts->next) { if(!ts->delay) continue; dst += strlen(dst); sprintf(dst, "\t\t\t%c%-3d min. %s %s\n", ts->delay > 0 ? '+' : ' ', ts->delay, L("at"), ts->station); } } void schedule_status_print(void) { FILE *fp; static char buff[256]; Train *t; TrainStop *ts; char buffs[9][80]; char *cols[9]; strcpy(buff, "results.htm"); if(!openFileDialog(buff)) return; remove_ext(buff); strcat(buff, ".htm"); if(!(fp = file_create(buff))) return; sprintf(buff, L("Simulation results")); html_startpage(fp, buff); fprintf(fp, "
\n"); //fprintf(fp, "
\n"); fprintf(fp, "%s : %s
\n", L("Time"), format_time(current_time)); fprintf(fp, "%s : %ld
\n", L("Total points"), run_points); fprintf(fp, "%s : %d
\n", L("Total min. of delayed entry"), total_delay / 60); fprintf(fp, "%s : %ld
\n", L("Total min. trains arrived late"), total_late); fprintf(fp, "%s : %ld\n", L("Total performance penalties"), performance()); //fprintf(fp, "
\n"); fprintf(fp, "
\n"); fprintf(fp, "\n", L("Wrong destinations")); fprintf(fp, "", perf_tot.wrong_dest, perf_vals.wrong_dest); fprintf(fp, "\n", perf_tot.wrong_dest * perf_vals.wrong_dest); fprintf(fp, "\n", L("Late trains")); fprintf(fp, "", perf_tot.late_trains, perf_vals.late_trains); fprintf(fp, "\n", perf_tot.late_trains * perf_vals.late_trains); fprintf(fp, "\n", L("Wrong platforms")); fprintf(fp, "", perf_tot.wrong_platform, perf_vals.wrong_platform); fprintf(fp, "\n", perf_tot.wrong_platform * perf_vals.wrong_platform); fprintf(fp, "\n", L("Commands denied")); fprintf(fp, "", perf_tot.denied, perf_vals.denied); fprintf(fp, "\n", perf_tot.denied * perf_vals.denied); fprintf(fp, "\n", L("Trains waiting at signals")); fprintf(fp, "", perf_tot.waiting_train, perf_vals.waiting_train); fprintf(fp, "\n", perf_tot.waiting_train * perf_vals.waiting_train); fprintf(fp, "
%s%d x%d =%d
%s%d x%d =%d
%s%d x%d =%d
%s%d x%d =%d
%s%d x%d =%d
"); fprintf(fp, "\n", L("Thrown switches")); fprintf(fp, "", perf_tot.thrown_switch, perf_vals.thrown_switch); fprintf(fp, "\n", perf_tot.thrown_switch * perf_vals.thrown_switch); fprintf(fp, "\n", L("Cleared signals")); fprintf(fp, "", perf_tot.cleared_signal, perf_vals.cleared_signal); fprintf(fp, "\n", perf_tot.cleared_signal * perf_vals.cleared_signal); fprintf(fp, "\n", L("Wrong stock assignments")); fprintf(fp, "", perf_tot.wrong_assign, perf_vals.wrong_assign); fprintf(fp, "\n", perf_tot.wrong_assign * perf_vals.wrong_assign); fprintf(fp, "\n", L("Reversed trains")); fprintf(fp, "", perf_tot.turned_train, perf_vals.turned_train); fprintf(fp, "\n", perf_tot.turned_train * perf_vals.turned_train); fprintf(fp, "
%s%d x%d =%d
%s%d x%d =%d
%s%d x%d =%d
%s%d x%d =%d
\n"); cols[0] = L("Train"); cols[1] = L("Enters"); cols[2] = L("At"); cols[3] = L("Exits"); cols[4] = L("Before"); cols[5] = L("Delay"); cols[6] = L("Late"); cols[7] = L("Status"); cols[8] = 0; html_table(cols); cols[0] = buffs[0]; cols[1] = buffs[1]; cols[2] = buffs[2]; cols[3] = buffs[3]; cols[4] = buffs[4]; cols[5] = buffs[5]; cols[6] = buffs[6]; cols[7] = buffs[7]; cols[8] = 0; for(t = schedule; t; t = t->next) { print_train_info(t); cols[0] = t->name; strcpy(buffs[1], t->entrance); cols[1] = buffs[1]; cols[2] = entering_time; strcpy(buffs[3], t->exit); cols[3] = buffs[3]; cols[4] = leaving_time; cols[5] = current_delay; cols[6] = current_late; cols[7] = current_status; html_row(cols); cols[0] = " "; cols[1] = " "; cols[2] = " "; cols[3] = " "; cols[4] = " "; cols[5] = " "; for(ts = t->stops; ts; ts = ts->next) { if(!ts->delay) continue; sprintf(buffs[6], "%c%d", ts->delay > 0 ? '+' : ' ', ts->delay); cols[6] = buffs[6]; cols[7] = ts->station; html_row(cols); } } html_endtable(); html_endpage(); fclose(fp); } void save_schedule_status(void) { FILE *fp; Train *t; char entr[MAXSHORTNAME]; char ext[MAXSHORTNAME]; schedule_status_print(); #if 0 if(!(fp = file_create("results"))) return; fprintf(fp, "Total points : %ld\n", run_points); fprintf(fp, "Total min. of delayed entry : %d\n", total_delay / 60); fprintf(fp, "Total min. trains arrived late : %ld\n", total_late); fprintf(fp, "TRAIN : ENTRANCE @ : EXIT @ : DELAY : LATE : STATUS\n"); for(t = schedule; t; t = t->next) { print_train_info(t); short_station_name(entr, t->entrance); entr[6] = 0; short_station_name(ext, t->exit); ext[6] = 0; fprintf(fp, "%-8s : %-6s %6s : %-6s %6s : %6s : %6s : %s\n", t->name, entr, entering_time, ext, leaving_time, current_delay, current_late, current_status); } fclose(fp); sprintf(status_line, "Saved file 'results'.\n"); repaint_labels(); #endif } void train_print(Train *t) { TrainStop *ts; char buff[64]; FILE *fp; int i; char *beg, *end; int status; char buffs[7][80]; char *cols[7]; sprintf(buff, "%s.htm", t->name); if(!openFileDialog(buff)) return; remove_ext(buff); strcat(buff, ".htm"); if(!(fp = file_create(buff))) return; sprintf(buff, "%s %s", L("Train"), t->name); html_startpage(fp, buff); cols[0] = L("Station"); cols[1] = L("Arrival"); cols[2] = L("Departure"); cols[3] = L("Min.stop"); cols[4] = 0 /*"Stopped"; cols[5] = "Delay"; cols[6] = 0*/; html_table(cols); cols[0] = buffs[0]; cols[1] = buffs[1]; cols[2] = buffs[2]; cols[3] = buffs[3]; cols[4] = 0 /*buffs[4]; cols[5] = buffs[5]; cols[6] = 0 */; status = 0; beg = "", end = ""; for(ts = t->stops; ts; ts = ts->next) { if(ts->arrival >= t->timein/* && findStation(ts->station)*/) { if(status == 0) { sprintf(cols[0], "%s", t->entrance); sprintf(cols[1], " "); sprintf(cols[2], "%s", format_time(t->timein)); sprintf(cols[3], " "); cols[4] = 0; html_row(cols); status = 1; } } if(ts->arrival > t->timeout && status == 1) { sprintf(cols[0], "%s", t->exit); sprintf(cols[1], "%s", format_time(t->timeout)); sprintf(cols[2], " "); sprintf(cols[3], " "); cols[4] = 0; html_row(cols); status = 2; } strcpy(cols[0], ts->station); if((beg = strchr(cols[0], '@'))) *beg = 0; if(findStation(cols[0])) beg = "", end = ""; else beg = "", end = ""; sprintf(cols[0], "%s%s%s", beg, ts->station, end); if(!ts->arrival) strcpy(cols[1], " "); else sprintf(cols[1], "%s%s%s", beg, format_time(ts->arrival), end); sprintf(cols[2], "%s%s%s", beg, format_time(ts->departure), end); if(status != 1) strcpy(cols[3], " "); else sprintf(cols[3], "%ld", ts->minstop); /* sprintf(cols[4], ts->stopped ? "Yes" : "No"); sprintf(cols[5], "%s%ld%s", beg, (long)ts->delay, end); */ cols[4] = 0; html_row(cols); } if(status < 1) { sprintf(cols[0], "%s", t->entrance); sprintf(cols[1], " "); sprintf(cols[2], "%s", format_time(t->timein)); sprintf(cols[3], " "); cols[4] = 0; html_row(cols); ++status; } if(status < 2) { sprintf(cols[0], "%s", t->exit); sprintf(cols[1], "%s", format_time(t->timeout)); sprintf(cols[2], " "); sprintf(cols[3], " "); cols[4] = 0; html_row(cols); } html_endtable(); fprintf(fp, "
\n"); if(t->days) { sprintf(buff, "%s : ", L("Runs on")); for(i = 0; i < 7; ++i) if(t->days & (1 << i)) sprintf(buff + strlen(buff), "%d", i+1); fprintf(fp, "%s\n", buff); } if(t->nnotes) { fprintf(fp, "%s: ", L("Notes")); for(status = 0; status < t->nnotes; ++status) fprintf(fp, "%s.
\n", t->notes[status]); } fprintf(fp, "
\n"); html_endpage(); fclose(fp); } int save_game(char *name) { FILE *fp; Track *t; Train *tr; TrainStop *ts; int i; char buff[256]; sprintf(buff, "%s.sav", name); if(!(fp = file_create(buff))) return 0; fprintf(fp, "%s\n", current_project); fprintf(fp, "%d,%ld,%d,%d,%d,%d,%d,%d,%d,%ld\n", cur_time_mult, start_time, show_speeds, show_blocks, beep_on_alert, run_points, total_delay, total_late, time_mult, current_time); /* Save the state of every switch */ for(t = layout; t; t = t->next) { if(t->type != SWITCH || !t->switched) continue; fprintf(fp, "%d,%d,%d\n", t->x, t->y, t->switched); } fprintf(fp, "\n"); /* Save the state of every signal */ for(t = layout; t; t = t->next) { if(t->type != TSIGNAL) continue; if(t->status != ST_GREEN && !t->nowfleeted) continue; fprintf(fp, "%d,%d,%d,%d\n", t->x, t->y, t->status == ST_GREEN, t->nowfleeted != 0); } fprintf(fp, "\n"); /* Save the position of every train */ for(tr = schedule; tr; tr = tr->next) { if(tr->status == train_READY) continue; fprintf(fp, "%s\n", tr->name); fprintf(fp, " %d,%d,%s\n", tr->status, tr->direction, tr->exited ? tr->exited : ""); fprintf(fp, " %d,%d,%d,%d,%d,%d,%d,%d,%d\n", tr->timeexited, tr->wrongdest, tr->curspeed, tr->maxspeed, tr->curmaxspeed, tr->trackpos, tr->timelate, tr->timedelay, tr->timered); fprintf(fp, " %ld,%d,%ld,%ld\n", tr->timedep, tr->pathpos, tr->pathtravelled, tr->disttostop); if(!tr->stoppoint) fprintf(fp, " 0,0,0,"); else fprintf(fp, " %d,%d,%ld,", tr->stoppoint->x, tr->stoppoint->y, tr->disttoslow); if(!tr->slowpoint) fprintf(fp, "0,0"); else fprintf(fp, "%d,%d", tr->slowpoint->x, tr->slowpoint->y); fprintf(fp, ",%d\n", tr->needfindstop); if(tr->fleet && tr->fleet->size) { /* fprintf(fp, " %d,%d\n", tr->fleet->x, tr->fleet->y); */ fprintf(fp, " "); for(i = 0; i < tr->fleet->size; ++i) { t = Vector_elementAt(tr->fleet, i); if(i) fputc(',', fp); fprintf(fp, "%d,%d", t->x, t->y); } fputc('\n', fp); } else fprintf(fp, " 0,0\n"); /* length has fleet info at end */ if(tr->position) fprintf(fp, " %d,%d", tr->position->x, tr->position->y); else fprintf(fp, " 0,0"); fprintf(fp, ",%d\n", tr->waittime); fprintf(fp, " %d,%s\n", tr->oldstatus, tr->outof ? tr->outof->station : ""); /* Save status of each stop */ for(ts = tr->stops; ts; ts = ts->next) if(ts->stopped || ts->delay) fprintf(fp, " %s,%d,%d\n", ts->station, ts->stopped, ts->delay); if(tr->tail && tr->tail->path) { Train *tail = tr->tail; fprintf(fp, ".\n"); /* marks beginning of tail path */ fprintf(fp, " %s\n", tr->stopping ? tr->stopping->station : ""); if(tail->fleet && tail->fleet->size) { for(i = 0; i < tail->fleet->size; ++i) { t = Vector_elementAt(tail->fleet, i); fprintf(fp, "%c%d,%d", i ? ',' : '!', t->x, t->y); } fputc('\n', fp); } fprintf(fp, " %d,%d,%d,%d", !tail->position ? -1 : tail->pathpos, tail->trackpos, tail->tailentry, tail->tailexit); for(i = 0; i < tail->path->size; ++i) { t = Vector_elementAt(tail->path, i); fprintf(fp, ",%d,%d,%d", t->x, t->y, Vector_flagAt(tail->path, i)); } } fprintf(fp, "\n"); } fprintf(fp, ".\n"); fprintf(fp, "%d,%d,%d,%d,%d\n", run_day, terse_status, status_on_top, show_seconds, signal_traditional); fprintf(fp, "%d,%d\n", auto_link, show_grid); fprintf(fp, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", perf_tot.wrong_dest, perf_tot.late_trains, perf_tot.thrown_switch, perf_tot.cleared_signal, perf_tot.denied, perf_tot.turned_train, perf_tot.waiting_train, perf_tot.wrong_platform, perf_tot.ntrains_late, perf_tot.ntrains_wrong, perf_tot.nmissed_stops, perf_tot.wrong_assign); fprintf(fp, "%d\n", hard_counters); fprintf(fp, "%d\n", show_canceled); fprintf(fp, "%d\n", show_links); fprintf(fp, "%d\n", beep_on_enter); fclose(fp); return 1; } void restore_game(char *name) { FILE *fp, *fp1; char *buffptr; char buff[1024]; char *p; int x, y; Track *t; Train *tr, *tail; TrainStop *ts; sprintf(buff, "%s.sav", name); if(!(fp = fopen(buff, "r"))) { perror(buff); return; } strcpy(buff, "load "); buffptr = getline(fp); strncat(buff, buffptr, sizeof(buff) - 6); if(!strstr(buff, ".trk") && !strstr(buff, ".TRK")) strcat(buff, ".trk"); if(!(fp1 = fopen(buffptr, "r"))) { p = buffptr + strlen(buffptr); while(--p > buffptr && *p != '\\' && *p != '/' && *p != ':'); if(p > buffptr) strcpy(buff + 5, p + 1); } else fclose(fp1); trainsim_cmd(buff); buffptr = getline(fp); sscanf(buffptr, "%d,%ld,%d,%d,%d,%d,%d,%d,%d,%ld", &cur_time_mult, &start_time, &show_speeds, &show_blocks, &beep_on_alert, &run_points, &total_delay, &total_late, &time_mult, ¤t_time); /* reload state of all switches */ while((buffptr = getline(fp))) { if(!buffptr[0]) break; x = strtol(buffptr, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(*p == ',') ++p; if(!(t = findSwitch(x, y))) continue; t->switched = atoi(p); if(t->switched) change_coord(t->x, t->y); } /* reload state of all signals */ while((buffptr = getline(fp))) { if(!buffptr[0]) break; x = strtol(buffptr, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(*p == ',') ++p; if(!(t = findSignal(x, y))) continue; t->status = strtol(p, &p, 0) == 1 ? ST_GREEN : ST_RED; if(*p == ',') ++p; t->nowfleeted = atoi(p); if(t->status == ST_GREEN) signal_unlock(t); change_coord(t->x, t->y); } /* reload state of all trains */ while((buffptr = getline(fp))) { if(!buffptr[0] || buffptr[0] == '.') break; /* end of file */ tr = findTrainNamed(buffptr); if(!tr) { /* the train could not be found in the schedule. * Warn the user, and ignore all lines up to the * next empty line. */ do { buffptr = getline(fp); } while(buffptr[0] && buffptr[0] != '.'); continue; } buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); tr->status = strtol(p, &p, 0); if(*p == ',') ++p; tr->direction = strtol(p, &p, 0); if(*p == ',') ++p; if(*p) tr->exited = strdup(p); buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); tr->timeexited = strtol(p, &p, 0); if(*p == ',') ++p; tr->wrongdest = strtol(p, &p, 0); if(*p == ',') ++p; tr->curspeed = strtol(p, &p, 0); if(*p == ',') ++p; tr->maxspeed = strtol(p, &p, 0); if(*p == ',') ++p; tr->curmaxspeed = strtol(p, &p, 0); if(*p == ',') ++p; tr->trackpos = strtol(p, &p, 0); if(*p == ',') ++p; tr->timelate = strtol(p, &p, 0); if(*p == ',') ++p; tr->timedelay = strtol(p, &p, 0); if(*p == ',') ++p; tr->timered = strtol(p, &p, 0); buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); tr->timedep = strtol(p, &p, 0); if(*p == ',') ++p; tr->pathpos = strtol(p, &p, 0); if(*p == ',') ++p; tr->pathtravelled = strtol(p, &p, 0); if(*p == ',') ++p; tr->disttostop = strtol(p, &p, 0); buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); x = strtol(p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(*p == ',') ++p; if(!(tr->stoppoint = findTrack(x, y))) tr->stoppoint = findSwitch(x, y); tr->disttoslow = strtol(p, &p, 0); if(*p == ',') ++p; x = strtol(p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(!(tr->slowpoint = findTrack(x, y))) tr->slowpoint = findSwitch(x, y); if(*p == ',') { ++p; tr->needfindstop = strtol(p, &p, 0); } buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); while(*p) { /* list of fleeting signals */ x = strtol(p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); /* tr->fleet = findSignal(x, y); */ if(x && y) { if(!tr->fleet) tr->fleet = new_Vector(); Vector_addElement(tr->fleet, findSignal(x, y), 0); } } buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); x = strtol(p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(!(tr->position = findTrack(x, y))) tr->position = findSwitch(x, y); if(*p == ',') ++p; tr->waittime = strtol(p, &p, 0); /* reset paths!!! */ if(tr->position) { tr->path = findPath(tr->position, tr->direction); tr->pathpos = 1; colorPath(tr->path, ST_GREEN); tr->position->fgcolor = conf.fgcolor; } buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); tr->oldstatus = strtol(p, &p, 0); if(*p == ',') ++p; if(*p) tr->outof = findStation(p); while((buffptr = getline(fp))) { if(!buffptr[0] || buffptr[0] == '.') break; if(!(p = strchr(buffptr, ','))) continue; *p++ = 0; for(ts = tr->stops; ts; ts = ts->next) if(!strcmp(ts->station, buffptr + 4)) break; if(!ts) continue; ts->stopped = strtol(p, &p, 0); if(*p == ',') ++p; ts->delay = atoi(p); } if(!buffptr) break; if(buffptr[0] == '.') { /* tail path info present */ buffptr = getline(fp); if(!buffptr[0] || buffptr[0] == '.') break; if(!(tail = tr->tail)) /* maybe length was removed in .sch */ continue; for(p = buffptr; *p == ' '; ++p); if(*p) /* stopping at station name present */ tr->stopping = findStation(p); buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); if(*p == '!') { ++p; while(*p) { /* list of fleeting signals */ x = strtol(p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(x && y) { if(!tail->fleet) tail->fleet = new_Vector(); Vector_addElement(tail->fleet, findSignal(x, y), 0); } if(*p == ',') ++p; } buffptr = getline(fp); for(p = buffptr; *p == ' '; ++p); } tail->pathpos = strtol(p, &p, 0); if(*p == ',') ++p; tail->trackpos = strtol(p, &p, 0); if(*p == ',') ++p; tail->tailentry = strtol(p, &p, 0); if(*p == ',') ++p; tail->tailexit = strtol(p, &p, 0); while(*p == ',') { x = strtol(++p, &p, 0); if(*p == ',') ++p; y = strtol(p, &p, 0); if(!tail->path) tail->path = new_Vector(); if(!(t = findTrack(x, y))) if(!(t = findSwitch(x, y))) t = findText(x, y); if(!t) { /* maybe layout changed? */ if(tail->path) /* disable length for this train */ Vector_delete(tail->path); tail->path = 0; tr->tail = 0; tr->length = 0; break; } if(*p == ',') ++p; Vector_addElement(tail->path, t, strtol(p, &p, 0)); } if(tail->path) { tail->position = 0; if(tr->status == train_ARRIVED) { Vector_delete(tail->path); tail->path = 0; } else { colorPartialPath(tail->path, ST_RED, tail->pathpos + 1); if(tr->path) { colorPath(tr->path, ST_GREEN); tr->position->fgcolor = conf.fgcolor; } if(tail->pathpos >= 0 && tail->pathpos < tail->path->size) tail->position = Vector_elementAt(tail->path, tail->pathpos); else tail->pathpos = 0; } } } update_schedule(tr); } if((buffptr = getline(fp))) sscanf(buffptr, "%d,%d,%d,%d,%d", &run_day, &terse_status, &status_on_top, &show_seconds, &signal_traditional); if((buffptr = getline(fp))) sscanf(buffptr, "%d,%d", &auto_link, &show_grid); memset(&perf_tot, 0, sizeof(perf_tot)); if((buffptr = getline(fp))) sscanf(buffptr, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &perf_tot.wrong_dest, &perf_tot.late_trains, &perf_tot.thrown_switch, &perf_tot.cleared_signal, &perf_tot.denied, &perf_tot.turned_train, &perf_tot.waiting_train, &perf_tot.wrong_platform, &perf_tot.ntrains_late, &perf_tot.ntrains_wrong, &perf_tot.nmissed_stops, &perf_tot.wrong_assign); if((buffptr = getline(fp)) && *buffptr) hard_counters = atoi(buffptr); if((buffptr = getline(fp)) && *buffptr) show_canceled = atoi(buffptr); if((buffptr = getline(fp)) && *buffptr) show_links = atoi(buffptr); if((buffptr = getline(fp)) && *buffptr) beep_on_enter = atoi(buffptr); compute_train_numbers(); fclose(fp); } void print_track_info(void) { FILE *fp; char buff[256]; TextList *tl; sprintf(buff, "%s.htm", current_project); if(!openFileDialog(buff)) return; remove_ext(buff); strcat(buff, ".htm"); if(!(fp = file_create(buff))) return; sprintf(buff, "%s : %s", L("Territory"), current_project); html_startpage(fp, buff); fprintf(fp, "
\n"); fprintf(fp, "
\n"); for(tl = track_info; tl; tl = tl->next) fprintf(fp, "%s\n", tl->txt); html_endpage(); fclose(fp); } struct optList { char *name; int *ptr; } opt_list[] = { { "fullstatus", &terse_status }, { "statusontop", &status_on_top }, { "alertsound", &beep_on_alert }, { "entersound", &beep_on_enter }, { "viewspeed", &show_speeds }, { "autolink", &auto_link }, { "showgrid", &show_grid }, { "showblocks", &show_blocks }, { "showsecs", &show_seconds }, { "standardsigs", &signal_traditional }, { "hardcounters", &hard_counters }, { "showlinks", &show_links }, { "saveprefs", &save_prefs }, { 0 }, }; #if defined(__unix__) #define INITFILE ".traindir.ini" #define LASTFILE ".traindir.l" #else #define INITFILE "traindir.ini" #define LASTFILE "traindir.mru" /* most recently used scenarios */ #endif char last_file[NLASTFILES][256]; /* NLASTFILES last scenario used */ /* Note that from 1.19 this is called BEFORE setting up * the user interface. As such, it must not call drawing * routines! * This is because the locale must be set before creating * menus, buttons and dialogs, so that we can use the * localized strings. */ void load_ini_file(void) { char buff[256]; char *p, *buffptr; struct optList *opt; FILE *fp; set_full_file_name(buff, INITFILE); if(!(fp = fopen(buff, "r"))) return; while((buffptr = getline(fp))) { if(!buffptr[0] || buffptr[0] == '#') break; /* end of file */ for(p = buffptr; *p && *p != ' '; ++p); if(*p) *p++ = 0; for(opt = opt_list; opt->name; ++opt) if(!strcmp(buffptr, opt->name)) { *opt->ptr = strtol(p, (char **)0, 0); break; } else if(!strcmp(buffptr, "locale")) locale_name = strdup(p); } fclose(fp); load_localized_strings(locale_name); } void save_ini_file(void) { char buff[256]; struct optList *opt; FILE *fp; if(!save_prefs) return; set_full_file_name(buff, INITFILE); if(!(fp = fopen(buff, "w"))) return; for(opt = opt_list; opt->name; ++opt) { fprintf(fp, "%s %d\n", opt->name, *opt->ptr); } fprintf(fp, "locale %s\n", locale_name); fclose(fp); } /* Set default preferences */ void default_prefs(void) { terse_status = 1; status_on_top = 1; beep_on_alert = 1; beep_on_enter = 0; show_speeds = 1; auto_link = 1; show_grid = 0; show_blocks = 1; show_seconds = 0; signal_traditional = 0; hard_counters = 0; save_prefs = 0; } void load_last(void) { char buff[256]; FILE *fp; char *p; int i; set_full_file_name(buff, LASTFILE); if(!(fp = fopen(buff, "r"))) return; i = 0; for(i = 0; (p = getline(fp)) && i < NLASTFILES; ++i) { strcpy(last_file[i], p); } fclose(fp); } void save_last(void) { char buff[256]; FILE *fp; int i; set_full_file_name(buff, LASTFILE); if(!(fp = fopen(buff, "w"))) return; for(i = 0; i < NLASTFILES; ++i) fprintf(fp, "%s\n", last_file[i]); fclose(fp); } /* reorder and update the "last file used" array */ void update_last_file(const char *flname) { char file[256]; int i; for(i = 0; i < NLASTFILES; i++) if(!strcmp(last_file[i], flname)) { switch(i) { case 0: return; case 1: strcpy(last_file[1], last_file[0]); strcpy(last_file[0], flname); break; case 2: strcpy(file, last_file[1]); strcpy(last_file[1], last_file[0]); strcpy(last_file[2], file); strcpy(last_file[0], flname); } return; } strcpy(file, last_file[0]); strcpy(last_file[2], last_file[1]); strcpy(last_file[1], file); strcpy(last_file[0], flname); }