1 #ifndef CMDLINE_ONLY
2 #  include <gtk/gtk.h>
3 #endif
4 #include <stdlib.h>
5 #include <string.h>
6 #ifndef CMDLINE_ONLY
7 #  include "support.h"
8 #endif
9 #include "parser.h"
10 #include "misc.h"
11 
12 #ifdef CMDLINE_ONLY
13 
14 extern const char *unitdb;
15 extern const char *reinfrc;
16 extern const char *reinf_output;
17 
18 #else /* !CMDLINE_ONLY */
19 
20 extern GtkWidget *window;
21 const char unitdb[] = "../../src/units/pg.udb";
22 const char reinfrc[] = "reinf.rc";
23 const char reinf_output[] = "../../lgc-pg/convdata/reinf";
24 
25 #endif /* !CMDLINE_ONLY */
26 
27 const char *unit_classes[] = {
28     "inf",      "Infantry",
29     "tank",     "Tank",
30     "recon",    "Recon",
31     "antitank", "Anti-Tank",
32     "art",      "Artillery",
33     "antiair",  "Anti-Aircraft",
34     "airdef",   "Air-Defense",
35 #ifdef CMDLINE_ONLY
36     "fort",	"Fortification",
37 #endif
38     "fighter",  "Fighter",
39     "tacbomb",  "Tactical Bomber",
40     "levbomb",  "Level Bomber",
41     "sub",      "Submarine",
42     "dest",     "Destroyer",
43     "cap",      "Capital Ship",
44     "carrier",  "Aircraft Carrier",
45 #ifdef CMDLINE_ONLY
46     "landtrp",	"Land Transport",
47     "airtrp",	"Air Transport",
48     "seatrp",	"Sea Transport",
49 #else
50     /* landtrp is supportive to classes
51        listed above */
52 #endif
53 };
54 #define NUM_UNIT_CLASSES (sizeof unit_classes/sizeof unit_classes[0])
55 const int num_unit_classes = NUM_UNIT_CLASSES;
56 
57 const char *target_types[] = {
58     "soft",  "Soft Target",
59     "hard",  "Hard Target",
60     "air",   "Air Target",
61     "naval", "Naval Target",
62 };
63 #define NUM_TARGET_TYPES (sizeof target_types/sizeof target_types[0])
64 const int num_target_types = NUM_TARGET_TYPES;
65 
66 const char *sides[] = {
67     "axis",    "Axis Forces",
68     "allied",  "Allied Forces",
69 };
70 #define NUM_SIDES (sizeof sides/sizeof sides[0])
71 const int num_sides = NUM_SIDES;
72 
73 const char *nation_table[] = {
74     "aus", "Austria",
75     "bel", "Belgia",
76     "bul", "Bulgaria",
77     "lux", "Luxemburg",
78     "den", "Denmark",
79     "fin", "Finnland",
80     "fra", "France",
81     "ger", "Germany",
82     "gre", "Greece",
83     "usa", "USA",
84     "hun", "Hungary",
85     "tur", "Turkey",
86     "it",  "Italy",
87     "net", "Netherlands",
88     "nor", "Norway",
89     "pol", "Poland",
90     "por", "Portugal",
91     "rum", "Rumania",
92     "esp", "Spain",
93     "so",  "Sovjetunion",
94     "swe", "Sweden",
95     "swi", "Switzerland",
96     "eng", "Great Britain",
97     "yug", "Yugoslavia",
98 };
99 #define NUM_NATION_TABLE (sizeof nation_table/sizeof nation_table[0])
100 const int num_nation_table = NUM_NATION_TABLE;
101 
102 const char *scenarios[] = {
103     "Poland", "Warsaw", "Norway", "LowCountries", "France",
104     "Sealion40", "NorthAfrica", "MiddleEast", "ElAlamein",
105     "Caucasus", "Sealion43", "Torch", "Husky", "Anzio",
106     "D-Day", "Anvil", "Ardennes", "Cobra", "MarketGarden",
107     "BerlinWest", "Balkans", "Crete", "Barbarossa", "Kiev",
108     "Moscow41", "Sevastapol", "Moscow42", "Stalingrad",
109     "Kharkov", "Kursk", "Moscow43", "Byelorussia",
110     "Budapest", "BerlinEast", "Berlin", "Washington",
111     "EarlyMoscow", "SealionPlus"
112 };
113 
114 /* while axis reinforcements are always
115    supplied to Germany the Allied side
116    depends on the scenario */
117 const char *nations[] = {
118     "pol", "pol", "eng", "eng", "fra", "eng", "eng", "eng",
119     "eng", "so", "eng", "usa", "usa", "usa", "usa", "usa",
120     "usa", "usa", "usa", "usa", "eng", "eng", "so", "so",
121     "so", "so", "so", "so", "so", "so", "so", "so", "so",
122     "so", "usa", "usa", "so", "eng"
123 };
124 
125 /*
126 ====================================================================
127 Icon indices that must be mirrored terminated by -1
128 ====================================================================
129 */
130 int mirror_ids[] = {
131     83, 84, 85, 86, 87, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
132     102, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
133     115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
134     127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
135     139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
136     151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162,
137     163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
138     175, 176, 177, 178, 179, 180, 181 ,182, 183, 184, 185, 186,
139     187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
140     199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 221,
141     232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
142     244, 250, -1
143 };
144 
145 /*
146 ====================================================================
147 UnitLib entries separated to their classes (axis/allies)
148 ====================================================================
149 */
150 List *unitlib[2][CLASS_COUNT];
151 List *trplib[2]; /* transporters */
152 /*
153 ====================================================================
154 Reinforcements for each scenario (axis/allies)
155 ====================================================================
156 */
157 List *reinf[2][SCEN_COUNT];
158 /*
159 ====================================================================
160 Current selections
161 ====================================================================
162 */
163 int cur_scen = 0, cur_player = AXIS, cur_class = 0;
164 int cur_unit = -1, cur_trp = -1, cur_pin = 1;
165 int cur_reinf = -1; /* row selection id */
166 
167 /*
168 ====================================================================
169 Load/save reinforcement resources
170 ====================================================================
171 */
load_reinf()172 int load_reinf()
173 {
174     char *line;
175     Unit *unit;
176     int i, j, k, count;
177     FILE *file = fopen( reinfrc, "rb" );
178     List *list, *args;
179     if ( file )
180         list = file_read_lines( file );
181     else
182         return 0;
183     fclose( file );
184     cur_pin = 1;
185     for ( i = 0; i < SCEN_COUNT; i++ )
186     {
187         line = list_next( list );
188         for ( j = 0; j < 2; j++ ) {
189             list_clear( reinf[j][i] );
190             count = atoi( list_next( list ) );
191             for ( k = 0; k < count; k++ ) {
192                 line = list_next( list );
193                 if ( ( args = parser_explode_string( line, ',' ) ) ) {
194                     if ( ( unit = calloc( 1, sizeof( Unit ) ) ) ) {
195                         const char *arg;
196                         unit->pin = cur_pin++;
197                         unit->delay = atoi( list_next( args ) );
198                         strcpy_lt( unit->id, list_next( args ), 7 );
199                         unit->uid = atoi( unit->id );
200                         strcpy_lt( unit->trp, list_next( args ), 7 );
201                         unit->tid = strcmp( unit->trp, "none" ) == 0 ? -1 : atoi( unit->trp );
202                         unit->str = atoi( list_next( args ) );
203                         unit->exp = atoi( list_next( args ) );
204                         unit->class_id = atoi( list_next( args ) );
205                         unit->unit_id = atoi( list_next( args ) );
206                         unit->trp_id = atoi( list_next( args ) );
207                         if ( (arg = list_next( args )) )
208                             unit->nation = atoi( arg );
209                         else
210                             unit->nation = -1;
211                         build_unit_info( unit, j );
212                         list_add( reinf[j][i], unit );
213                     }
214                     list_delete( args );
215                 }
216             }
217         }
218     }
219     list_delete( list );
220 #ifndef CMDLINE_ONLY
221     /* update */
222     update_reinf_list( cur_scen, cur_player );
223 #endif
224     return 1;
225 }
save_reinf()226 int save_reinf()
227 {
228     Unit *unit;
229     int i, j;
230     FILE *file = fopen( reinfrc, "wb" );
231     if ( file == 0 ) return 0;
232     for ( i = 0; i < SCEN_COUNT; i++ )
233     {
234         fprintf( file, "%s\n", scenarios[i] );
235         for ( j = 0; j < 2; j++ ) {
236             fprintf( file, "%i\n", reinf[j][i]->count );
237             list_reset( reinf[j][i] );
238             while ( ( unit = list_next( reinf[j][i] ) ) )
239                 fprintf( file, "%i,%s,%s,%i,%i,%i,%i,%i,%i\n", unit->delay,
240                          unit->id, unit->trp, unit->str,
241                          unit->exp,
242                          unit->class_id, unit->unit_id, unit->trp_id,
243                          unit->nation );
244         }
245     }
246     fclose( file );
247     printf( "Reinforcements saved to %s\n", reinfrc );
248     return 1;
249 }
250 
get_nation_id_by_table_id(int id)251 char *get_nation_id_by_table_id( int id )
252 {
253     static char nat[4];
254     strcpy(nat,"---");
255     if (id<0||id>=num_nation_table/2)
256         return nat;
257     else
258     {
259         snprintf(nat,4,"%s",nation_table[id*2]);
260         return nat;
261     }
262 }
263 int determine_nation_for_unit(const UnitLib_Entry *entry);
264 
265 /*
266 ====================================================================
267 Build LGC-PG reinforcements file in ../../src/convdata
268 ====================================================================
269 */
build_reinf()270 void build_reinf()
271 {
272     Unit *unit;
273     int i, j, nat;
274     FILE *file = fopen( reinf_output, "wb" );
275     if ( file ) {
276         for ( i = 0; i < SCEN_COUNT; i++ ) {
277             if ( reinf[AXIS][i]->count == 0 )
278                 if ( reinf[ALLIES][i]->count == 0 )
279                     continue;
280             fprintf( file, "%s {\n", scenarios[i] );
281             for ( j = 0; j < 2; j++ ) {
282                 if ( reinf[j][i]->count == 0 )
283                     continue;
284                 list_reset( reinf[j][i] );
285                 while ( ( unit = list_next( reinf[j][i] ) ) ) {
286                     nat = unit->nation;
287                     if (nat==-1)
288                     {
289                         UnitLib_Entry *entry = find_unit_by_id( unit->uid );
290                         nat = determine_nation_for_unit(entry);
291                     }
292                     fprintf( file, "  unit { nation = %s id = %s trsp = %s "
293                                               "delay = %i str = %i "
294                                               "exp = %i }\n",
295                              get_nation_id_by_table_id(nat),
296                              unit->id, unit->trp, unit->delay,
297                              unit->str, unit->exp );
298                 }
299             }
300             fprintf( file, "}\n\n" );
301         }
302         fclose( file );
303         printf( "Reinforcements built to %s\n", reinf_output );
304     }
305     else
306         printf( "%s not found!\n", reinf_output );
307 }
308 
309 /*
310 ====================================================================
311 Convert string to scenario id. Returns -1 if invalid.
312 ====================================================================
313 */
to_scenario(const char * str)314 int to_scenario(const char *str) {
315     int i = SCEN_COUNT;
316     for (; i > 0; ) {
317         i--;
318         if (strcasecmp(str, scenarios[i]) == 0) return i;
319     }
320     return -1;
321 }
322 
323 /*
324 ====================================================================
325 Convert string to side id. Returns -1 if invalid.
326 ====================================================================
327 */
to_side(const char * str)328 int to_side(const char *str) {
329     int i = NUM_SIDES;
330     for (; i > 0; ) {
331         i -= 2;
332         if (strcasecmp(str, sides[i]) == 0) return i >> 1;
333     }
334     return -1;
335 }
336 
337 /*
338 ====================================================================
339 Convert string to nation id. Returns -1 if invalid.
340 ====================================================================
341 */
to_nation(const char * str)342 int to_nation(const char *str) {
343     int i = NUM_NATION_TABLE;
344     for (; i > 0; ) {
345         i -= 2;
346         if (strcasecmp(str, nation_table[i]) == 0) return i >> 1;
347     }
348     return -1;
349 }
350 
351 /*
352 ====================================================================
353 Convert string to target type id. Returns -1 if invalid.
354 ====================================================================
355 */
to_target_type(const char * str)356 int to_target_type(const char *str) {
357     int i = NUM_TARGET_TYPES;
358     for (; i > 0; ) {
359         i -= 2;
360         if (strcasecmp(str, target_types[i]) == 0) return i >> 1;
361     }
362     return -1;
363 }
364 
365 /*
366 ====================================================================
367 Convert string to unit class id. Returns -1 if invalid.
368 ====================================================================
369 */
to_unit_class(const char * str)370 int to_unit_class(const char *str) {
371     int i = NUM_UNIT_CLASSES;
372     for (; i > 0; ) {
373         i -= 2;
374         if (strcasecmp(str, unit_classes[i]) == 0) return i >> 1;
375     }
376     return -1;
377 }
378 
379 /*
380 ====================================================================
381 Returns the side this nation typically belongs to.
382 0 is axis, 1 is allied.
383 ====================================================================
384 */
nation_to_side(int nation)385 int nation_to_side(int nation) {
386    switch (nation) {
387        case 0: case 2: case 4: case 5: case 7: case 10: case 11: case 12: case 20: case 21:
388            return 0;
389        default:
390            return 1;
391    }
392 }
393 
394 /*
395 ====================================================================
396 Returns the total count of units.
397 ====================================================================
398 */
unit_count()399 int unit_count() {
400 
401     int cnt = 0;
402     int side, cls;
403     for (side = 0; side < 2; side++) {
404         for (cls = 0; cls < CLASS_COUNT; cls++) {
405             cnt += unitlib[side][cls]->count;
406         }
407         cnt += trplib[side]->count;
408     }
409     return cnt;
410 }
411 
412 /*
413 ====================================================================
414 Determines the nation the given unit belongs to. Returns -1 if
415 no nation could be determined.
416 ====================================================================
417 */
determine_nation_for_unit(const UnitLib_Entry * entry)418 int determine_nation_for_unit(const UnitLib_Entry *entry) {
419     static const struct {
420         const char * const prefix;
421         const char nat[4];
422     } prefix_xlate[] = {
423         { "ST ", "so" },
424         { "US ", "usa" },
425         { "GB ", "eng" },
426         { "FR ", "fra" },
427         { "FFR ", "fra" },
428         { "FPO ", "pol" },
429         { "IT ", "it" },
430         { "PO ", "pol" },
431         { "NOR ", "nor" },
432         { "LC ", "?" },
433         { "AF ", "?" },
434         { "AD ", "?" },
435         { "Rumanian ", "rum" },
436         { "Bulgarian ", "bul" },
437         { "Hungarian ", "hun" },
438         { "Greek ", "gre" },
439         { "Yugoslav ", "yug" },
440     };
441     int i;
442     const char *nat = 0;
443 
444     for (i = 0; i < sizeof prefix_xlate/sizeof prefix_xlate[0]; i++) {
445         int prefix_len = strlen(prefix_xlate[i].prefix);
446         if (strncmp(entry->name, prefix_xlate[i].prefix, prefix_len) == 0) {
447             nat = prefix_xlate[i].nat;
448             break;
449         }
450     }
451 
452     /* the Stalinorgeln miss their ST prefix */
453     if (entry->nid == 422 || entry->nid == 423) nat = "so";
454     else if (!nat) nat = "ger";	/* everything else is German */
455 
456     return to_nation(nat);
457 
458 }
459 
460 /*
461 ====================================================================
462 Returns the unit with the given id or 0 if not found.
463 Don't call this while iterating all units by iterate_units_next()
464 ====================================================================
465 */
find_unit_by_id(int id)466 UnitLib_Entry *find_unit_by_id(int id) {
467     UnitLib_Entry *entry;
468     iterate_units_begin();
469     while ((entry = iterate_units_next())) {
470         if (entry->nid == id) return entry;
471     }
472     return 0;
473 }
474 
475 /** opaque data structure for maintaining iterator state */
476 struct UdbIteratorState {
477     enum { AxisSide, AlliedSide, SidesTraversed } side;
478     enum { UnitArray, TransportArray, ArraysTraversed } ary;
479     int cls;
480     struct UnitLib_Entry *cur;
481 } udb_it;
482 
483 /*
484 ====================================================================
485 Starts iterating the unit database.
486 ====================================================================
487 */
iterate_units_begin(void)488 void iterate_units_begin(void) {
489     udb_it.side = AxisSide;
490     udb_it.ary = UnitArray;
491     udb_it.cls = 0;
492     list_reset(unitlib[udb_it.side][udb_it.cls]);
493 }
494 
495 /*
496 ====================================================================
497 Returns the next unit or 0 if end reached.
498 ====================================================================
499 */
iterate_units_next(void)500 UnitLib_Entry *iterate_units_next(void) {
501     List *lst = udb_it.ary == UnitArray ? unitlib[udb_it.side][udb_it.cls] : trplib[udb_it.side];
502     UnitLib_Entry *item = list_next(lst);
503     if (item) return item;
504 
505     switch (udb_it.ary) {
506         case UnitArray:
507 
508             udb_it.cls++;
509 
510             if (udb_it.cls == CLASS_COUNT) {
511                 udb_it.ary++;
512                 list_reset(trplib[udb_it.side]);
513             } else
514                 list_reset(unitlib[udb_it.side][udb_it.cls]);
515             item = iterate_units_next();
516             break;
517 
518         case TransportArray:
519 
520             udb_it.ary++;
521             /* fall through */
522 
523         case ArraysTraversed:
524 
525             udb_it.side++;
526 
527             if (udb_it.side < SidesTraversed) {
528                 udb_it.ary = UnitArray;
529                 udb_it.cls = 0;
530                 list_reset(unitlib[udb_it.side][udb_it.cls]);
531                 item = iterate_units_next();
532             }
533     }
534 
535     return item;
536 }
537 
538 /*
539 ====================================================================
540 Inititate application and load resources.
541 ====================================================================
542 */
init()543 void init()
544 {
545 #ifndef CMDLINE_ONLY
546     gchar *row[1];
547     GtkWidget *clist = 0;
548 #endif
549     UnitLib_Entry *entry = 0;
550     PData *pd = 0, *units = 0, *unit = 0;
551     int i, j;
552     char *str;
553     /* create lists */
554     for ( j = 0; j < 2; j++ ) {
555         for ( i = 0; i < CLASS_COUNT; i++ )
556             unitlib[j][i] = list_create( LIST_AUTO_DELETE,
557                                          LIST_NO_CALLBACK );
558         trplib[j] = list_create( LIST_AUTO_DELETE,
559                                  LIST_NO_CALLBACK );
560         if ( ( entry = calloc( 1, sizeof( UnitLib_Entry ) ) ) ) {
561             strcpy( entry->name, "NONE" );
562             list_add( trplib[j], entry );
563         }
564         for ( i = 0; i < SCEN_COUNT; i++ )
565             reinf[j][i] = list_create( LIST_AUTO_DELETE,
566                                        LIST_NO_CALLBACK );
567     }
568     /* load unit lib */
569     if ( ( pd = parser_read_file( "unitlib", unitdb ) ) == 0 )
570         goto failure;
571     if ( !parser_get_pdata( pd, "unit_lib", &units ) )
572         goto failure;
573     /* load and categorize unit entries */
574     list_reset( units->entries );
575     while ( ( unit = list_next( units->entries ) ) ) {
576         /* id, name and side */
577         if ( ( entry = calloc( 1, sizeof( UnitLib_Entry ) ) ) == 0 )
578             goto failure;
579         strcpy_lt( entry->id, unit->name, 7 );
580         entry->nid = atoi(entry->id);
581         if ( parser_get_value( unit, "name", &str, 0 ) )
582             strcpy_lt( entry->name, str, 23 );
583         if ( parser_get_value( unit, "icon_id", &str, 0 ) )
584              j = atoi( str );
585         i = 0; entry->side = 0;
586         while ( 1 ) {
587             if ( mirror_ids[i++] == j ) {
588                 entry->side = 1;
589                 break;
590             }
591             if ( mirror_ids[i] == -1 )
592                 break;
593         }
594         /* get class and add to list */
595         if ( parser_get_value( unit, "class", &str, 0 ) ) {
596             int class_id = to_unit_class(str);
597 #ifdef CMDLINE_ONLY
598             entry->class = class_id;
599 #endif
600             if ( STRCMP( "landtrp", str ) )
601                 /* ground transporters are special */
602                 list_add( trplib[entry->side], entry );
603             else if (class_id >= 0)
604                 list_add( unitlib[entry->side][class_id], entry );
605         }
606 #ifdef CMDLINE_ONLY
607         if ( parser_get_value( unit, "target_type", &str, 0 ) )
608              entry->tgttype = to_target_type( str );
609         if ( parser_get_value( unit, "start_year", &str, 0 ) )
610             entry->start_year = atoi( str );
611         if ( parser_get_value( unit, "start_month", &str, 0 ) )
612             entry->start_month = atoi( str );
613         if ( parser_get_value( unit, "last_year", &str, 0 ) )
614             entry->last_year = atoi( str );
615         entry->nation = determine_nation_for_unit(entry);
616 #endif
617     }
618     /* load reinforcements */
619     load_reinf();
620 #ifndef CMDLINE_ONLY
621     /* add scenarios to list l_scenarios */
622     if ( ( clist = lookup_widget( window, "scenarios" ) ) ) {
623         for ( i = 0; i < SCEN_COUNT; i++ ) {
624             row[0] = (char *)scenarios[i];
625             gtk_clist_append( GTK_CLIST (clist), row );
626         }
627     }
628     /* show unit list */
629     update_unit_list( cur_player, cur_class );
630     update_trp_list( cur_player );
631 #endif
632     /* we're done */
633     parser_free( &pd );
634     return;
635 failure:
636     parser_free( &pd );
637     finalize();
638     fprintf( stderr, "Aborted: %s\n", parser_get_error() );
639     exit( 1 );
640 }
641 
642 /*
643 ====================================================================
644 Cleanup
645 ====================================================================
646 */
finalize()647 void finalize()
648 {
649     int i, j;
650     for ( j = 0; j < 2; j++ ) {
651         for ( i = 0; i < CLASS_COUNT; i++ )
652             if ( unitlib[j][i] )
653                 list_delete( unitlib[j][i] );
654         if ( trplib[j] )
655             list_delete( trplib[j] );
656         for ( i = 0; i < SCEN_COUNT; i++ )
657             if ( reinf[j][i] )
658                 list_delete( reinf[j][i] );
659     }
660 }
661 
662 /*
663 ====================================================================
664 Copy source to dest and at maximum limit chars. Terminate with 0.
665 ====================================================================
666 */
strcpy_lt(char * dest,char * src,int limit)667 void strcpy_lt( char *dest, char *src, int limit )
668 {
669     int len = strlen( src );
670     if ( len > limit ) {
671         strncpy( dest, src, limit );
672         dest[limit] = 0;
673     }
674     else
675         strcpy( dest, src );
676 }
677 
678 #ifndef CMDLINE_ONLY
679 /*
680 ====================================================================
681 Update unit/transporters list
682 ====================================================================
683 */
update_unit_list(int player,int unit_class)684 void update_unit_list( int player, int unit_class )
685 {
686     UnitLib_Entry *entry;
687     gchar *row[1];
688     GtkWidget *clist;
689     if ( ( clist = lookup_widget( window, "units" ) ) ) {
690         gtk_clist_clear( GTK_CLIST(clist) );
691         list_reset( unitlib[player][unit_class] );
692         while ( ( entry = list_next( unitlib[player][unit_class] ) ) ) {
693             row[0] = entry->name;
694             gtk_clist_append( GTK_CLIST(clist), row );
695         }
696     }
697 }
update_trp_list(int player)698 void update_trp_list( int player )
699 {
700     UnitLib_Entry *entry;
701     gchar *row[1];
702     GtkWidget *clist;
703     if ( ( clist = lookup_widget( window, "transporters" ) ) ) {
704         gtk_clist_clear( GTK_CLIST(clist) );
705         list_reset( trplib[player] );
706         while ( ( entry = list_next( trplib[player] ) ) ) {
707             row[0] = entry->name;
708             gtk_clist_append( GTK_CLIST(clist), row );
709         }
710     }
711 }
update_reinf_list(int scen,int player)712 void update_reinf_list( int scen, int player )
713 {
714     Unit *entry;
715     gchar *row[1];
716     GtkWidget *clist;
717     if ( ( clist = lookup_widget( window, "reinforcements" ) ) ) {
718         gtk_clist_clear( GTK_CLIST(clist) );
719         list_reset( reinf[player][scen] );
720         while ( ( entry = list_next( reinf[player][scen] ) ) ) {
721             row[0] = entry->info;
722             gtk_clist_append( GTK_CLIST(clist), row );
723         }
724         gtk_clist_sort( GTK_CLIST(clist) );
725     }
726 }
727 #endif
728 
729 /*
730 ====================================================================
731 Read all lines from file.
732 ====================================================================
733 */
file_read_lines(FILE * file)734 List* file_read_lines( FILE *file )
735 {
736     List *list;
737     char buffer[1024];
738 
739     if ( !file ) return 0;
740 
741     list = list_create( LIST_AUTO_DELETE, LIST_NO_CALLBACK );
742 
743     /* read lines */
744     while( !feof( file ) ) {
745         if ( !fgets( buffer, 1023, file ) ) break;
746         if ( buffer[0] == 10 ) continue; /* empty line */
747         buffer[strlen( buffer ) - 1] = 0; /* cancel newline */
748         list_add( list, strdup( buffer ) );
749     }
750     return list;
751 }
752 
753 /*
754 ====================================================================
755 Build unit's info string.
756 ====================================================================
757 */
build_unit_info(Unit * unit,int player)758 void build_unit_info( Unit *unit, int player )
759 {
760     UnitLib_Entry *entry = find_unit_by_id( unit->uid );
761     UnitLib_Entry *trp_entry = find_unit_by_id( unit->tid );
762 
763 #ifndef CMDLINE_ONLY
764     if ( trp_entry ) {
765         snprintf( unit->info, sizeof unit->info,
766                   "T %02i: '%s' (Strength: %i, Exp: %i, Nation: %s) [%s]   #%i",
767                   unit->delay + 1, entry ? entry->name : "<invalid>",
768                   unit->str, unit->exp,
769                   (unit->nation==-1)?"auto":get_nation_id_by_table_id(unit->nation),
770                   trp_entry->name, unit->pin );
771     }
772     else
773         snprintf( unit->info, sizeof unit->info,
774                   "T %02i: '%s' (Strength: %i, Exp: %i, Nation: %s)   #%i",
775                   unit->delay + 1, entry ? entry->name : "<invalid>",
776                   unit->str, unit->exp,
777                   (unit->nation==-1)?"auto":get_nation_id_by_table_id(unit->nation),
778                   unit->pin );
779 #endif
780     unit->entry = entry;
781     unit->trp_entry = trp_entry;
782 }
783 
784 /*
785 ====================================================================
786 Insert a new reinforcement unit into the reinforcements array.
787 ====================================================================
788 */
insert_reinf_unit(Unit * unit,int player,int scenario)789 void insert_reinf_unit( Unit *unit, int player, int scenario ) {
790     /* insert into list, but grouped by nation */
791     {
792         Unit *item;
793         int i = 0;
794         list_reset( reinf[player][scenario] );
795         for (i = 0; (item = list_next( reinf[player][scenario] )); i++) {
796             if ( unit->nation == item->nation ) break;
797         }
798 
799         list_insert( reinf[player][scenario], unit, i );
800     }
801 }
802 
803 #ifdef CMDLINE_ONLY
804 
805 #include "util/paths.h"
806 
807 /*
808 ====================================================================
809 Return the directory the game data is installed under.
810 ====================================================================
811 */
get_gamedir(void)812 const char *get_gamedir(void)
813 {
814 #ifdef DISABLE_INSTALL
815     return ".";
816 #else
817     const char *prefix;
818     static char *gamedir;
819     static const char suffix[] = "/share/games/lgeneral";
820     unsigned len;
821     if (gamedir) return gamedir;
822     prefix = paths_prefix();
823     len = strlen(prefix);
824     gamedir = malloc(len + sizeof suffix);
825     strcpy(gamedir, prefix);
826     strcpy(gamedir + len, suffix);
827     return gamedir;
828 #endif
829 }
830 #endif
831