]>
Commit | Line | Data |
---|---|---|
1 | /* s_fileio.c | |
2 | * | |
3 | * Micropolis, Unix Version. This game was released for the Unix platform | |
4 | * in or about 1990 and has been modified for inclusion in the One Laptop | |
5 | * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If | |
6 | * you need assistance with this program, you may contact: | |
7 | * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org. | |
8 | * | |
9 | * This program is free software: you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation, either version 3 of the License, or (at | |
12 | * your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. You should have received a | |
18 | * copy of the GNU General Public License along with this program. If | |
19 | * not, see <http://www.gnu.org/licenses/>. | |
20 | * | |
21 | * ADDITIONAL TERMS per GNU GPL Section 7 | |
22 | * | |
23 | * No trademark or publicity rights are granted. This license does NOT | |
24 | * give you any right, title or interest in the trademark SimCity or any | |
25 | * other Electronic Arts trademark. You may not distribute any | |
26 | * modification of this program using the trademark SimCity or claim any | |
27 | * affliation or association with Electronic Arts Inc. or its employees. | |
28 | * | |
29 | * Any propagation or conveyance of this program must include this | |
30 | * copyright notice and these terms. | |
31 | * | |
32 | * If you convey this program (or any modifications of it) and assume | |
33 | * contractual liability for the program to recipients of it, you agree | |
34 | * to indemnify Electronic Arts for any liability that those contractual | |
35 | * assumptions impose on Electronic Arts. | |
36 | * | |
37 | * You may not misrepresent the origins of this program; modified | |
38 | * versions of the program must be marked as such and not identified as | |
39 | * the original program. | |
40 | * | |
41 | * This disclaimer supplements the one included in the General Public | |
42 | * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS | |
43 | * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY | |
44 | * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF | |
45 | * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS | |
46 | * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES, | |
47 | * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY, | |
48 | * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY | |
49 | * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING, | |
50 | * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST | |
51 | * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL | |
52 | * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE | |
53 | * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE | |
54 | * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE | |
55 | * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR | |
56 | * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME | |
57 | * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED | |
58 | * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A | |
59 | * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY | |
60 | * NOT APPLY TO YOU. | |
61 | */ | |
62 | #include "sim.h" | |
63 | ||
64 | void DoSaveCityAs(void); | |
65 | void DidSaveCity(void); | |
66 | void DidntSaveCity(char *msg); | |
67 | void DidLoadCity(void); | |
68 | void DidntLoadCity(char *msg); | |
69 | void DidLoadScenario(void); | |
70 | ||
71 | ||
72 | #define SWAP_SHORTS(a,b) _swap_shorts(a,b) | |
73 | #define SWAP_LONGS(a,b) _swap_longs(a,b) | |
74 | #define HALF_SWAP_LONGS(a,b) _half_swap_longs(a,b) | |
75 | ||
76 | #define NOOP_ON_BE { int test = 1; if (!(*(unsigned char*) (&test))) return; } | |
77 | ||
78 | static void | |
79 | _swap_shorts(short *buf, int len) | |
80 | { | |
81 | int i; | |
82 | ||
83 | NOOP_ON_BE; | |
84 | ||
85 | /* Flip bytes in each short! */ | |
86 | for (i = 0; i < len; i++) { | |
87 | *buf = ((*buf & 0xFF) <<8) | ((*buf &0xFF00) >>8); | |
88 | buf++; | |
89 | } | |
90 | } | |
91 | ||
92 | #if 0 | |
93 | static void | |
94 | _swap_longs(long *buf, int len) | |
95 | { | |
96 | int i; | |
97 | ||
98 | NOOP_ON_BE; | |
99 | ||
100 | /* Flip bytes in each long! */ | |
101 | for (i = 0; i < len; i++) { | |
102 | long l = *buf; | |
103 | *buf = | |
104 | ((l & 0x000000ff) << 24) | | |
105 | ((l & 0x0000ff00) << 8) | | |
106 | ((l & 0x00ff0000) >> 8) | | |
107 | ((l & 0xff000000) >> 24); | |
108 | buf++; | |
109 | } | |
110 | } | |
111 | #endif | |
112 | ||
113 | static void | |
114 | _half_swap_longs(long *buf, int len) | |
115 | { | |
116 | int i; | |
117 | ||
118 | NOOP_ON_BE | |
119 | ||
120 | /* Flip bytes in each long! */ | |
121 | for (i = 0; i < len; i++) { | |
122 | long l = *buf; | |
123 | *buf = | |
124 | ((l & 0x0000ffff) << 16) | | |
125 | ((l & 0xffff0000) >> 16); | |
126 | buf++; | |
127 | } | |
128 | } | |
129 | ||
130 | static int | |
131 | _load_short(short *buf, int len, FILE *f) | |
132 | { | |
133 | if (fread(buf, sizeof(short), len, f) != len) | |
134 | return 0; | |
135 | ||
136 | SWAP_SHORTS(buf, len); /* to intel */ | |
137 | ||
138 | return 1; | |
139 | } | |
140 | ||
141 | ||
142 | #if 0 | |
143 | static int | |
144 | _load_long(long *buf, int len, FILE *f) | |
145 | { | |
146 | if (fread(buf, sizeof(long), len, f) != len) | |
147 | return 0; | |
148 | ||
149 | SWAP_LONGS(buf, len); /* to intel */ | |
150 | ||
151 | return 1; | |
152 | } | |
153 | #endif | |
154 | ||
155 | ||
156 | static int | |
157 | _save_short(short *buf, int len, FILE *f) | |
158 | { | |
159 | ||
160 | SWAP_SHORTS(buf, len); /* to MAC */ | |
161 | ||
162 | if (fwrite(buf, sizeof(short), len, f) != len) | |
163 | return 0; | |
164 | ||
165 | SWAP_SHORTS(buf, len); /* back to intel */ | |
166 | ||
167 | return 1; | |
168 | } | |
169 | ||
170 | ||
171 | #if 0 | |
172 | static int | |
173 | _save_long(long *buf, int len, FILE *f) | |
174 | { | |
175 | ||
176 | SWAP_LONGS(buf, len); /* to MAC */ | |
177 | ||
178 | if (fwrite(buf, sizeof(long), len, f) != len) | |
179 | return 0; | |
180 | ||
181 | SWAP_LONGS(buf, len); /* back to intel */ | |
182 | ||
183 | return 1; | |
184 | } | |
185 | #endif | |
186 | ||
187 | ||
188 | static | |
189 | int | |
190 | _load_file(char *filename, char *dir) | |
191 | { | |
192 | FILE *f; | |
193 | char path[512]; | |
194 | QUAD size; | |
195 | ||
196 | #ifdef MSDOS | |
197 | if (dir != NULL) { | |
198 | sprintf(path, "%s\\%s", dir, filename); | |
199 | filename = path; | |
200 | } | |
201 | if ((f = fopen(filename, "rb")) == NULL) { | |
202 | return 0; | |
203 | } | |
204 | #else | |
205 | if (dir != NULL) { | |
206 | sprintf(path, "%s/%s", dir, filename); | |
207 | filename = path; | |
208 | } | |
209 | if ((f = fopen(filename, "r")) == NULL) { | |
210 | return (0); | |
211 | } | |
212 | #endif | |
213 | ||
214 | fseek(f, 0L, SEEK_END); | |
215 | size = ftell(f); | |
216 | fseek(f, 0L, SEEK_SET); | |
217 | ||
218 | switch (size) { | |
219 | case 27120: /* Normal city */ | |
220 | break; | |
221 | ||
222 | case 99120: /* 2x2 city */ | |
223 | break; | |
224 | ||
225 | case 219120: /* 3x3 city */ | |
226 | break; | |
227 | ||
228 | default: | |
229 | return (0); | |
230 | } | |
231 | ||
232 | if ((_load_short(ResHis, HISTLEN / 2, f) == 0) || | |
233 | (_load_short(ComHis, HISTLEN / 2, f) == 0) || | |
234 | (_load_short(IndHis, HISTLEN / 2, f) == 0) || | |
235 | (_load_short(CrimeHis, HISTLEN / 2, f) == 0) || | |
236 | (_load_short(PollutionHis, HISTLEN / 2, f) == 0) || | |
237 | (_load_short(MoneyHis, HISTLEN / 2, f) == 0) || | |
238 | (_load_short(MiscHis, MISCHISTLEN / 2, f) == 0) || | |
239 | (_load_short((&Map[0][0]), WORLD_X * WORLD_Y, f) < 0)) { | |
240 | ||
241 | /* TODO: report error */ | |
242 | fclose(f); | |
243 | return(0); | |
244 | } | |
245 | ||
246 | fclose(f); | |
247 | return(1); | |
248 | } | |
249 | ||
250 | ||
251 | int loadFile(char *filename) | |
252 | { | |
253 | long l; | |
254 | ||
255 | if (_load_file(filename, NULL) == 0) | |
256 | return(0); | |
257 | ||
258 | /* total funds is a long..... MiscHis is array of shorts */ | |
259 | /* total funds is being put in the 50th & 51th word of MiscHis */ | |
260 | /* find the address, cast the ptr to a lontPtr, take contents */ | |
261 | ||
262 | l = *(QUAD *)(MiscHis + 50); | |
263 | HALF_SWAP_LONGS(&l, 1); | |
264 | SetFunds(l); | |
265 | ||
266 | l = *(QUAD *)(MiscHis + 8); | |
267 | HALF_SWAP_LONGS(&l, 1); | |
268 | CityTime = l; | |
269 | ||
270 | autoBulldoze = MiscHis[52]; /* flag for autoBulldoze */ | |
271 | autoBudget = MiscHis[53]; /* flag for autoBudget */ | |
272 | autoGo = MiscHis[54]; /* flag for autoGo */ | |
273 | UserSoundOn = MiscHis[55]; /* flag for the sound on/off */ | |
274 | CityTax = MiscHis[56]; | |
275 | SimSpeed = MiscHis[57]; | |
276 | // sim_skips = sim_skip = 0; | |
277 | ChangeCensus(); | |
278 | MustUpdateOptions = 1; | |
279 | ||
280 | /* yayaya */ | |
281 | ||
282 | l = *(QUAD *)(MiscHis + 58); | |
283 | HALF_SWAP_LONGS(&l, 1); | |
284 | policePercent = l / 65536.0; | |
285 | ||
286 | l = *(QUAD *)(MiscHis + 60); | |
287 | HALF_SWAP_LONGS(&l, 1); | |
288 | firePercent = l / 65536.0; | |
289 | ||
290 | l = *(QUAD *)(MiscHis + 62); | |
291 | HALF_SWAP_LONGS(&l, 1); | |
292 | roadPercent = l / 65536.0; | |
293 | ||
294 | policePercent = (*(QUAD*)(MiscHis + 58)) / 65536.0; /* and 59 */ | |
295 | firePercent = (*(QUAD*)(MiscHis + 60)) / 65536.0; /* and 61 */ | |
296 | roadPercent =(*(QUAD*)(MiscHis + 62)) / 65536.0; /* and 63 */ | |
297 | ||
298 | if (CityTime < 0) | |
299 | CityTime = 0; | |
300 | if ((CityTax > 20) || (CityTax < 0)) | |
301 | CityTax = 7; | |
302 | if ((SimSpeed < 0) || (SimSpeed > 3)) | |
303 | SimSpeed = 3; | |
304 | ||
305 | setSpeed(SimSpeed); | |
306 | setSkips(0); | |
307 | ||
308 | InitFundingLevel(); | |
309 | ||
310 | /* set the scenario id to 0 */ | |
311 | InitWillStuff(); | |
312 | ScenarioID = 0; | |
313 | InitSimLoad = 1; | |
314 | DoInitialEval = 0; | |
315 | DoSimInit(); | |
316 | InvalidateEditors(); | |
317 | InvalidateMaps(); | |
318 | ||
319 | return (1); | |
320 | } | |
321 | ||
322 | ||
323 | int saveFile(char *filename) | |
324 | { | |
325 | long l; | |
326 | FILE *f; | |
327 | ||
328 | #ifdef MSDOS | |
329 | if ((f = fopen(filename, "wb")) == NULL) { | |
330 | #else | |
331 | if ((f = fopen(filename, "w")) == NULL) { | |
332 | #endif | |
333 | /* TODO: report error */ | |
334 | return(0); | |
335 | } | |
336 | ||
337 | /* total funds is a long..... MiscHis is array of ints */ | |
338 | /* total funds is bien put in the 50th & 51th word of MiscHis */ | |
339 | /* find the address, cast the ptr to a lontPtr, take contents */ | |
340 | ||
341 | l = TotalFunds; | |
342 | HALF_SWAP_LONGS(&l, 1); | |
343 | (*(QUAD *)(MiscHis + 50)) = l; | |
344 | ||
345 | l = CityTime; | |
346 | HALF_SWAP_LONGS(&l, 1); | |
347 | (*(QUAD *)(MiscHis + 8)) = l; | |
348 | ||
349 | MiscHis[52] = autoBulldoze; /* flag for autoBulldoze */ | |
350 | MiscHis[53] = autoBudget; /* flag for autoBudget */ | |
351 | MiscHis[54] = autoGo; /* flag for autoGo */ | |
352 | MiscHis[55] = UserSoundOn; /* flag for the sound on/off */ | |
353 | MiscHis[57] = SimSpeed; | |
354 | MiscHis[56] = CityTax; /* post release */ | |
355 | ||
356 | /* yayaya */ | |
357 | ||
358 | l = (int)(policePercent * 65536); | |
359 | HALF_SWAP_LONGS(&l, 1); | |
360 | (*(QUAD *)(MiscHis + 58)) = l; | |
361 | ||
362 | l = (int)(firePercent * 65536); | |
363 | HALF_SWAP_LONGS(&l, 1); | |
364 | (*(QUAD *)(MiscHis + 60)) = l; | |
365 | ||
366 | l = (int)(roadPercent * 65536); | |
367 | HALF_SWAP_LONGS(&l, 1); | |
368 | (*(QUAD *)(MiscHis + 62)) = l; | |
369 | ||
370 | if ((_save_short(ResHis, HISTLEN / 2, f) == 0) || | |
371 | (_save_short(ComHis, HISTLEN / 2, f) == 0) || | |
372 | (_save_short(IndHis, HISTLEN / 2, f) == 0) || | |
373 | (_save_short(CrimeHis, HISTLEN / 2, f) == 0) || | |
374 | (_save_short(PollutionHis, HISTLEN / 2, f) == 0) || | |
375 | (_save_short(MoneyHis, HISTLEN / 2, f) == 0) || | |
376 | (_save_short(MiscHis, MISCHISTLEN / 2, f) == 0) || | |
377 | (_save_short((&Map[0][0]), WORLD_X * WORLD_Y, f) < 0)) { | |
378 | ||
379 | /* TODO: report error */ | |
380 | fclose(f); | |
381 | return(0); | |
382 | } | |
383 | ||
384 | fclose(f); | |
385 | return(1); | |
386 | } | |
387 | ||
388 | ||
389 | void | |
390 | LoadScenario(short s) | |
391 | { | |
392 | char *name = NULL, *fname = NULL; | |
393 | ||
394 | if (CityFileName != NULL) { | |
395 | ckfree(CityFileName); | |
396 | CityFileName = NULL; | |
397 | } | |
398 | ||
399 | SetGameLevel(0); | |
400 | ||
401 | if ((s < 1) || (s > 8)) s = 1; | |
402 | ||
403 | switch (s) { | |
404 | case 1: | |
405 | name = "Dullsville"; | |
406 | fname = "snro.111"; | |
407 | ScenarioID = 1; | |
408 | CityTime = ((1900 - 1900) * 48) + 2; | |
409 | SetFunds(5000); | |
410 | break; | |
411 | case 2: | |
412 | name = "San Francisco"; | |
413 | fname = "snro.222"; | |
414 | ScenarioID = 2; | |
415 | CityTime = ((1906 - 1900) * 48) + 2; | |
416 | SetFunds(20000); | |
417 | break; | |
418 | case 3: | |
419 | name = "Hamburg"; | |
420 | fname = "snro.333"; | |
421 | ScenarioID = 3; | |
422 | CityTime = ((1944 - 1900) * 48) + 2; | |
423 | SetFunds(20000); | |
424 | break; | |
425 | case 4: | |
426 | name = "Bern"; | |
427 | fname = "snro.444"; | |
428 | ScenarioID = 4; | |
429 | CityTime = ((1965 - 1900) * 48) + 2; | |
430 | SetFunds(20000); | |
431 | break; | |
432 | case 5: | |
433 | name = "Tokyo"; | |
434 | fname = "snro.555"; | |
435 | ScenarioID = 5; | |
436 | CityTime = ((1957 - 1900) * 48) + 2; | |
437 | SetFunds(20000); | |
438 | break; | |
439 | case 6: | |
440 | name = "Detroit"; | |
441 | fname = "snro.666"; | |
442 | ScenarioID = 6; | |
443 | CityTime = ((1972 - 1900) * 48) + 2; | |
444 | SetFunds(20000); | |
445 | break; | |
446 | case 7: | |
447 | name = "Boston"; | |
448 | fname = "snro.777"; | |
449 | ScenarioID = 7; | |
450 | CityTime = ((2010 - 1900) * 48) + 2; | |
451 | SetFunds(20000); | |
452 | break; | |
453 | case 8: | |
454 | name = "Rio de Janeiro"; | |
455 | fname = "snro.888"; | |
456 | ScenarioID = 8; | |
457 | CityTime = ((2047 - 1900) * 48) + 2; | |
458 | SetFunds(20000); | |
459 | break; | |
460 | } | |
461 | ||
462 | setAnyCityName(name); | |
463 | // sim_skips = sim_skip = 0; | |
464 | InvalidateMaps(); | |
465 | InvalidateEditors(); | |
466 | setSpeed(3); | |
467 | CityTax = 7; | |
468 | gettimeofday(&start_time, NULL); | |
469 | ||
470 | _load_file(fname, ResourceDir); | |
471 | ||
472 | InitWillStuff(); | |
473 | InitFundingLevel(); | |
474 | UpdateFunds(); | |
475 | InvalidateEditors(); | |
476 | InvalidateMaps(); | |
477 | InitSimLoad = 1; | |
478 | DoInitialEval = 0; | |
479 | DoSimInit(); | |
480 | DidLoadScenario(); | |
481 | Kick(); | |
482 | } | |
483 | ||
484 | ||
485 | void | |
486 | DidLoadScenario(void) | |
487 | { | |
488 | Eval("UIDidLoadScenario"); | |
489 | } | |
490 | ||
491 | ||
492 | int LoadCity(char *filename) | |
493 | { | |
494 | char *cp; | |
495 | char msg[256]; | |
496 | ||
497 | if (loadFile(filename)) { | |
498 | if (CityFileName != NULL) | |
499 | ckfree(CityFileName); | |
500 | CityFileName = (char *)ckalloc(strlen(filename) + 1); | |
501 | strcpy(CityFileName, filename); | |
502 | ||
503 | if ((cp = (char *)rindex(filename, '.'))) | |
504 | *cp = 0; | |
505 | #ifdef MSDOS | |
506 | if ((cp = (char *)rindex(filename, '\\'))) | |
507 | #else | |
508 | if ((cp = (char *)rindex(filename, '/'))) | |
509 | #endif | |
510 | cp++; | |
511 | else | |
512 | cp = filename; | |
513 | filename = (char *)ckalloc(strlen(cp) + 1); | |
514 | strcpy(filename, cp); | |
515 | setCityName(filename); | |
516 | gettimeofday(&start_time, NULL); | |
517 | ||
518 | InvalidateMaps(); | |
519 | InvalidateEditors(); | |
520 | DidLoadCity(); | |
521 | return (1); | |
522 | } else { | |
523 | sprintf(msg, "Unable to load a city from the file named \"%s\". %s", | |
524 | filename ? filename : "(null)", | |
525 | errno ? strerror(errno) : ""); | |
526 | DidntLoadCity(msg); | |
527 | return (0); | |
528 | } | |
529 | } | |
530 | ||
531 | ||
532 | void | |
533 | DidLoadCity(void) | |
534 | { | |
535 | Eval("UIDidLoadCity"); | |
536 | } | |
537 | ||
538 | ||
539 | void | |
540 | DidntLoadCity(char *msg) | |
541 | { | |
542 | char buf[1024]; | |
543 | sprintf(buf, "UIDidntLoadCity {%s}", msg); | |
544 | Eval(buf); | |
545 | } | |
546 | ||
547 | ||
548 | void | |
549 | SaveCity(void) | |
550 | { | |
551 | char msg[256]; | |
552 | ||
553 | if (CityFileName == NULL) { | |
554 | DoSaveCityAs(); | |
555 | } else { | |
556 | if (saveFile(CityFileName)) | |
557 | DidSaveCity(); | |
558 | else { | |
559 | sprintf(msg, "Unable to save the city to the file named \"%s\". %s", | |
560 | CityFileName ? CityFileName : "(null)", | |
561 | errno ? strerror(errno) : ""); | |
562 | DidntSaveCity(msg); | |
563 | } | |
564 | } | |
565 | } | |
566 | ||
567 | ||
568 | void | |
569 | DoSaveCityAs(void) | |
570 | { | |
571 | Eval("UISaveCityAs"); | |
572 | } | |
573 | ||
574 | ||
575 | void | |
576 | DidSaveCity(void) | |
577 | { | |
578 | Eval("UIDidSaveCity"); | |
579 | } | |
580 | ||
581 | ||
582 | void | |
583 | DidntSaveCity(char *msg) | |
584 | { | |
585 | char buf[1024]; | |
586 | sprintf(buf, "UIDidntSaveCity {%s}", msg); | |
587 | Eval(buf); | |
588 | } | |
589 | ||
590 | ||
591 | void | |
592 | SaveCityAs(char *filename) | |
593 | { | |
594 | char msg[256]; | |
595 | char *cp; | |
596 | ||
597 | if (CityFileName != NULL) | |
598 | ckfree(CityFileName); | |
599 | CityFileName = (char *)ckalloc(strlen(filename) + 1); | |
600 | strcpy(CityFileName, filename); | |
601 | ||
602 | if (saveFile(CityFileName)) { | |
603 | if ((cp = (char *)rindex(filename, '.'))) | |
604 | *cp = 0; | |
605 | #ifdef MSDOS | |
606 | if ((cp = (char *)rindex(filename, '\\'))) | |
607 | #else | |
608 | if ((cp = (char *)rindex(filename, '/'))) | |
609 | #endif | |
610 | cp++; | |
611 | else | |
612 | cp = filename; | |
613 | filename = (char *)ckalloc(strlen(cp) + 1); | |
614 | strcpy(filename, cp); | |
615 | setCityName(cp); | |
616 | DidSaveCity(); | |
617 | } else { | |
618 | sprintf(msg, "Unable to save the city to the file named \"%s\". %s", | |
619 | CityFileName ? CityFileName : "(null)", | |
620 | errno ? strerror(errno) : ""); | |
621 | DidntSaveCity(msg); | |
622 | } | |
623 | } | |
624 | ||
625 |