6f60a644270b437fa54fc64553cafa7eef329307
[rodin/chimara.git] / interpreters / nitfol / opt2glkc.pl
1 #!/usr/local/bin/perl -w
2 use strict;
3
4 my $header = "nitfol.h";
5 my $appname = "nitfol";
6 my $appmajor = "NITFOL_MAJOR";
7 my $appminor = "NITFOL_MINOR";
8 my $texinfo = "nitfol.texi";
9 my $author = "Evin Robertson";
10 my $email = "nitfol\@my-deja.com";
11 my $search_path = "INFOCOM_PATH";
12 my @man_see_also = ( "frotz (6)", "txd (1)" );
13 my $mac_creator = "niTf";
14 my $mac_savefile = "IFZS";
15 my $mac_datafile = "ZipD";
16 my @mac_gamefile = ( "ZCOD", "IFRS", $mac_savefile );
17
18 # The following are modified by make_glk_* as appropriate
19 my $dirsep = "/";
20 my $configdir = "configdir = n_strdup(getenv(\"HOME\"));";
21 my $configname = "configname = \"${dirsep}.${appname}rc\";";
22
23
24 # opt2glkc.pl - Generates Glk startup code and some documentation
25 # Copyright (C) 1999  Evin Robertson
26 #
27 #  This program is free software; you can redistribute it and/or modify
28 #  it under the terms of the GNU General Public License as published by
29 #  the Free Software Foundation; either version 2 of the License, or
30 #  (at your option) any later version.
31 #
32 #  This program is distributed in the hope that it will be useful,
33 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
34 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35 #  GNU General Public License for more details.
36 #
37 #  You should have received a copy of the GNU General Public License
38 #  along with this program; if not, write to the Free Software
39 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
40 #
41 #  The author can be reached at nitfol@my-deja.com
42
43 my @LoL;
44 my $argtype;
45 my $systemtype;
46
47 my %optionlist = ( unix => [ "startunix.c",  \&make_glk_unix ],
48                    dos  => [ "startdos.c",   \&make_glk_dos ],
49                    win  => [ "startwin.c",   \&make_glk_win ],
50                    mac  => [ "startmac.c",   \&make_glk_mac ],
51                    info => [ "options.texi", \&make_info ],
52                    man  => [ "$appname.6",   \&make_man ]
53                    );
54
55 $_ = $ARGV[0];
56
57 if(/^-(.*)$/) {
58     $systemtype = $1;
59     shift;
60 } else {
61     $systemtype = "unix";
62 }
63
64 read_in_optfile();
65
66 $optionlist{$systemtype} || die "Unknown switch '-$systemtype'\n";
67
68 open("MYOUTPUT", ">$optionlist{$systemtype}[0]") || die "cannot write to $optionlist{$systemtype}[0]\n";
69
70 select "MYOUTPUT";
71 &{ $optionlist{$systemtype}[1] }();
72
73 close "MYOUTPUT";
74
75
76
77
78 sub read_in_optfile
79 {
80     my $longdesc;
81     my $i = 1;
82     while(<>) {
83         if(/^\#/ || /^$/) {
84             ;
85         }
86         #             1          2      3         4         5       6                     9
87         elsif(/^\s*\"(.*?)\"\s+(\S+)\s+(\S)\s+\"(.*?)\"\s+(\S+)\s+((\S+)|(\".*?\"))\s+(\{.*)$/) {
88             $longdesc = <>;
89             push @LoL, [ ( $1, $2, $3, $4, $5, $6, $9, $i, $ARGV, $longdesc ) ];
90             $i++;
91         } else {
92             die "Error in file $ARGV line $i.";
93         }
94         $i++;
95     }
96 }
97
98
99
100 sub make_info
101 {
102     foreach my $soption (@LoL) {
103         my @option = @{ $soption };
104         if($option[4] eq "flag") {
105             print "\@item -$option[1]\n";
106             print "\@itemx -no-$option[1]\n";
107             if($option[2] ne "-") {
108                 print "\@itemx -$option[2]\n";
109             }
110         } else {
111             print "\@item -$option[1] \@var{$option[4]}\n";
112             if($option[2] ne "-") {
113                 print "\@itemx -$option[2] \@var{$option[4]}\n";
114             }
115         }
116         print "$option[3].  $option[9]\n";
117     }
118 }
119
120 sub texi2roff
121 {
122     $_ = $_[0];
123     s/\@itemize \@minus\n//;
124     s/\@end itemize/.PP/;
125     s/\@item /.IP \\\(bu\n/;
126
127     s/\@code\{(.*?)\}/\\fB$1\\fP/g;
128     s/\@samp\{(.*?)\}/\`$1\'/g;
129     s/\@var\{(.*?)\}/\\fI$1\\fP/g;
130     s/\@kbd\{(.*?)\}/\`$1\'/g;
131     s/\@file\{(.*?)\}/\`$1\'/g;
132     s/\@cite\{(.*?)\}/\\fI$1\\fP/g;
133     s/\@uref\{(.*?)(, (.*?))\}/$3 \<$1\>/g;
134     s/\@uref\{(.*?)\}/\<$1\>/g;
135     s/\@email\{(.*?)\}/\<$1\>/g;
136     s/\@sc\{(.*?)\}/$1/g;
137     s/\@\@/\@/g;
138
139     return $_;
140 }
141
142 sub texi2txt
143 {
144     $_ = $_[0];
145     s/\@code\{(.*?)\}/\'$1\'/g;
146     s/\@file\{(.*?)\}/\'$1\'/g;
147     s/\@\@/\@/g;
148     return $_;
149 }
150
151
152 sub make_man
153 {
154     open("MYTEXINFO", "<$texinfo") || die "unable to read '$texinfo'\n";
155     print ".TH ", uc $appname, " 6\n";
156     print ".SH NAME\n";
157     while(($_ = <MYTEXINFO>) !~ /^\* $appname: \($appname\). *.*/i) {
158         ;
159     }
160     /^\* $appname: \($appname\). *(.*)/i;
161     print "$appname \\- $1\n";
162     print ".SH SYNOPSIS\n";
163     print ".B $appname\n";
164     print ".I \"[options] file\"\n";
165     print ".SH DESCRIPTION\n";
166     print "This manpage was generated from bits of the info page.  See the info page for complete documentation.\n";
167     while(<MYTEXINFO> !~ /^\@chapter introduction/i) {
168         ;
169     }
170     while(($_ = <MYTEXINFO>) !~ /^(\@node)|(\@bye)|(\@menu)/) {
171         if($_ !~ /^\@.*/) {
172             print texi2roff($_);
173         }
174     }
175     print ".SH OPTIONS\n";
176     foreach my $soption (@LoL) {
177         my @option = @{ $soption };
178         print ".TP\n";
179         print ".B";
180         if($option[4] eq "flag") {
181             print " \\-$option[1]";
182             print ", \\-no\\-$option[1]";
183             if($option[2] ne "-") {
184                 print ", \\-$option[2]";
185             }
186         } else {
187             print " \\-$option[1] \\fI$option[4]\\fB";
188             if($option[2] ne "-") {
189                 print ", \\-$option[2] \\fI$option[4]";
190             }
191         }
192         print "\n";
193         print texi2roff($option[3]), ".  ", texi2roff($option[9]);
194     }
195
196     print ".SH BUGS\n";
197     while(<MYTEXINFO> !~ /^\@chapter bugs/i) {
198         ;
199     }
200     while(($_ = <MYTEXINFO>) !~ /^(\@node)|(\@bye)/) {
201         print texi2roff($_);
202     }
203
204     print ".SH \"SEE ALSO\"\n";
205     print ".RB \"`\\|\" $appname \"\\|'\"\n";
206     print "entry in\n";
207     print ".B\n";
208     print "info;\n";
209
210     my $flag = 0;
211     foreach my $also (@man_see_also) {
212         if($flag) {
213             print ",\n";
214         }
215         $flag = 1;
216         print ".BR $also";
217     }
218     print ".\n";
219
220     print ".SH AUTHOR\n";
221     print "$appname was written by $author, who can be reached at $email.\n";
222     close("MYTEXINFO");
223 }
224
225 sub make_glk_unix
226 {
227     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
228 #ifdef DEBUGGING
229 #include <signal.h>
230 #endif
231 #include <stdlib.h>
232 #include <stdio.h>
233 #include <ctype.h>
234 #include <sys/types.h>
235 #include <sys/stat.h>
236 #include <dirent.h>
237 #include <limits.h>
238 #include \"$header\"
239 #include \"glkstart.h\"
240
241 static char *game_filename = NULL;
242
243 static void set_game_filename(const char *name)
244 {
245   n_free(game_filename);
246   game_filename = 0;
247
248 #if defined(_GNU_SOURCE)
249   game_filename = canonicalize_file_name(name);
250 #else
251 #if defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE)
252   game_filename = (char *) n_malloc(PATH_MAX);
253   if(!realpath(name, game_filename)) {
254     n_free(game_filename);
255     game_filename = 0;
256   }
257 #else
258 #ifdef __DJGPP__
259   game_filename = (char *) n_malloc(FILENAME_MAX);
260   _fixpath(name, game_filename);
261 #endif
262 #endif
263 #endif
264
265   if(!game_filename)
266     game_filename = n_strdup(name);
267 }
268
269
270 strid_t startup_findfile(void)
271 {
272   static DIR *dir = NULL;
273   static char *pathstart = NULL;
274   static char *path = NULL;
275   strid_t stream;
276   struct dirent *d;
277   char *name = NULL;
278
279   if(!pathstart) {
280     char *p = search_path;
281     if(!p)
282       return 0;
283     pathstart = n_strdup(p);
284     if(!(path = n_strtok(pathstart, \":\"))) {
285       n_free(pathstart);
286       pathstart = 0;
287       return 0;
288     }
289   }
290
291   do {
292     if(!dir) {
293       dir = opendir(path);
294       if(!dir) {
295         n_free(pathstart);
296         pathstart = 0;
297         return 0;
298       }
299     }
300     d = readdir(dir);
301     if(!d) {
302       closedir(dir);
303       dir = NULL;
304       if(!(path = n_strtok(NULL, \":\"))) {
305         n_free(pathstart);
306         pathstart = 0;
307         return 0;
308       }
309     }
310   } while(!dir);
311
312   name = (char *) n_malloc(n_strlen(path) + n_strlen(d->d_name) + 2);
313   n_strcpy(name, path);
314   n_strcat(name, \"$dirsep\");
315   n_strcat(name, d->d_name);
316   stream = glkunix_stream_open_pathname(name, fileusage_Data |
317                                         fileusage_BinaryMode, 0);
318   if(stream)
319     set_game_filename(name);
320   n_free(name);
321   return stream;
322 }
323
324
325 strid_t intd_filehandle_open(strid_t savefile, glui32 operating_id,
326                              glui32 contents_id, glui32 interp_id,
327                              glui32 length)
328 {
329   char *name;
330   strid_t str;
331   if(operating_id != ", string_to_iff("UNIX"), ")
332     return 0;
333   if(contents_id != 0)
334     return 0;
335   if(interp_id != ", string_to_iff("    "), ")
336     return 0;
337
338   name = (char *) n_malloc(length+1);
339   glk_get_buffer_stream(savefile, name, length);
340   name[length] = 0;
341   str = glkunix_stream_open_pathname(name, fileusage_Data |
342                                      fileusage_BinaryMode, 0);
343   if(str)
344     set_game_filename(name);
345   n_free(name);
346   return str;
347 }
348
349 void intd_filehandle_make(strid_t savefile)
350 {
351   if(!game_filename)
352     return;
353   w_glk_put_string_stream(savefile, \"UNIX\");
354   glk_put_char_stream(savefile, b00000010); /* Flags */
355   glk_put_char_stream(savefile, 0);         /* Contents ID */
356   glk_put_char_stream(savefile, 0);         /* Reserved */
357   glk_put_char_stream(savefile, 0);         /* Reserved */
358   w_glk_put_string_stream(savefile, \"    \"); /* Interpreter ID */
359   w_glk_put_string_stream(savefile, game_filename);
360 }
361
362 glui32 intd_get_size(void)
363 {
364   if(!game_filename)
365     return 0;
366   return n_strlen(game_filename) + 12;
367 }
368
369 strid_t startup_open(const char *name)
370 {
371   strid_t str;
372
373   str = glkunix_stream_open_pathname((char *) name, fileusage_Data | fileusage_BinaryMode, 0);
374   if(str) {
375     set_game_filename(name);
376   } else {
377     char *path = search_path;
378     if(path) {
379       char *p;
380       char *newname = (char *) n_malloc(strlen(path) + strlen(name) + 2);
381       path = n_strdup(path);
382       for(p = n_strtok(path, \":\"); p; p = n_strtok(NULL, \":\")) {
383         n_strcpy(newname, p);
384         n_strcat(newname, \"$dirsep\");
385         n_strcat(newname, name);
386         str = glkunix_stream_open_pathname((char *) newname, fileusage_Data |
387                                            fileusage_BinaryMode, 0);
388         if(str) {
389           set_game_filename(newname);
390           break;
391         }
392       }
393       n_free(path);
394     }
395   }
396
397   if(!str)
398     fprintf(stderr, \"Cannot open '%s'\\n\", name);
399
400   return str;
401 }
402
403 ";
404
405     make_generic_startup_wopen();
406     make_useless_command_structure();
407     make_functions();
408     make_useful_command_structure();
409     make_default_setter();
410     make_textpref_reader();
411     make_help_printer();
412     make_command_parser();
413
414     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
415
416 #ifdef DEBUGGING
417 static void sighandle(int unused);
418
419 static void sighandle(int unused)
420 {
421 /*  signal(SIGINT, sighandle); */ /* SysV resets default behaviour - foil it */
422   enter_debugger = TRUE;
423 }
424 #endif
425
426 #ifdef __cplusplus
427 extern \"C\" {
428 #endif
429 int glkunix_startup_code(glkunix_startup_t *data)
430 {
431   strid_t pref;
432   const char *configname;
433   char *configdir, *prefname;
434   char *execname;
435   char *p;
436   username = getenv(\"LOGNAME\");   /* SysV */
437   if(!username)
438     username = getenv(\"USER\");    /* BSD */
439
440 #ifdef DEBUGGING
441 /*  signal(SIGINT, sighandle); */
442 #endif
443
444   execname = n_strrchr(data->argv[0], '$dirsep');
445
446   if(execname)
447     execname++;
448   else
449     execname = data->argv[0];
450   
451   set_defaults();
452   $configdir
453   $configname
454   prefname = n_malloc(n_strlen(configdir) + n_strlen(configname) + 1);
455   n_strcpy(prefname, configdir);
456   n_strcat(prefname, configname);
457   pref = glkunix_stream_open_pathname(prefname, fileusage_Data | fileusage_TextMode, 0);
458   n_free(configdir);
459   n_free(prefname);
460   read_textpref(pref, execname);
461   
462   p = getenv(\"$search_path\");
463   if(p) {
464     free(search_path);
465     search_path = n_strdup(p);
466   }
467
468   return parse_commands(data->argc, data->argv);
469 }
470 #ifdef __cplusplus
471 }
472 #endif
473 ";
474 }
475
476 sub make_glk_dos
477 {
478     $dirsep = "/";
479     $configdir = "configdir = n_strdup(data->argv[0]); if(n_strrchr(configdir, '$dirsep')) *n_strrchr(configdir, '$dirsep') = 0;";
480     $configname = "configname = \"${dirsep}${appname}.cfg\";";
481     make_glk_unix();
482 }
483
484
485 sub make_glk_win
486 {
487     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
488 #include \"$header\"
489 #include \"WinGlk.h\"
490
491 ";
492     make_generic_intd();
493     make_generic_findfile();
494     make_generic_startup_open();
495     make_generic_startup_wopen();
496     make_functions();
497     make_useful_command_structure();
498     make_default_setter();
499     make_help_printer();
500     make_command_parser();
501
502
503     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
504 void shift_string_left(char *str)
505 {
506   int len = strlen(str);
507   int i;
508   for(i = 0; i < len; i++)
509     str[i] = str[i+1];
510 }
511
512 int winglk_startup_code(void)
513 {
514   BOOL status;
515   char *commandline = strdup(GetCommandLine());
516   char **argv = (char **) n_malloc(sizeof(char *) * strlen(commandline));
517   int argc = 0;
518
519   int i;
520
521   while(*commandline) {
522     while(*commandline && isspace(*commandline))
523       commandline++;
524     
525     argv[argc++] =  commandline;
526     
527     while(*commandline && !isspace(*commandline)) {
528       if(*commandline == '\"') {
529         shift_string_left(commandline);
530         while(*commandline && *commandline != '\"')
531           commandline++;
532         shift_string_left(commandline);
533       } else {
534         commandline++;
535       }
536     }
537     
538     *commandline++ = 0;
539   }
540
541   argv[argc] = NULL;
542   
543   status = parse_commands(argc, argv);
544
545   n_free(argv);
546   n_free(commandline);
547
548   winglk_app_set_name(\"$appname\");
549   winglk_window_set_title(\"$appname\");
550   set_defaults();
551
552   return status;
553 }
554 ";
555 }
556
557
558
559 sub string_to_iff
560 {
561     my ($id) = @_;
562     my $i;
563     my $val;
564     $val = 0;
565     for($i=0; $i < length $id; $i++) {
566         $val = $val * 0x100 + ord substr $id, $i, 1;
567     }
568     return sprintf("0x%x /* '$id' */", $val);
569 }
570
571
572
573 sub make_glk_mac
574 {
575     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
576 #include \"$header\"
577 #include \"macglk_startup.h\"
578
579 static strid_t mac_gamefile;
580
581 static BOOL hashandle = FALSE;
582 static AliasHandle gamehandle;
583 ";
584     make_generic_findfile();
585     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
586 strid_t intd_filehandle_open(strid_t savefile, glui32 operating_id,
587                              glui32 contents_id, glui32 interp_id,
588                              glui32 length)
589 {
590   FSSpec file;
591   Boolean wasChanged;
592   if(operating_id != ", string_to_iff("MACS"), ")
593     return 0;
594   if(contents_id != 0)
595     return 0;
596   if(interp_id != ", string_to_iff("    "), ")
597     return 0;
598
599   gamehandle = NewHandle(length);
600   glk_get_buffer_stream(savefile, *gamehandle, length);
601   hashandle = TRUE;
602   ResolveAlias(NULL, gamehandle, &file, &wasChanged);
603   return macglk_stream_open_fsspec(&file, 0, 0);  
604 }
605
606 void intd_filehandle_make(strid_t savefile)
607 {
608   if(!hashandle)
609     return;
610   glk_put_string_stream(savefile, \"MACS\");
611   glk_put_char_stream(savefile, b00000010); /* Flags */
612   glk_put_char_stream(savefile, 0);         /* Contents ID */
613   glk_put_char_stream(savefile, 0);         /* Reserved */
614   glk_put_char_stream(savefile, 0);         /* Reserved */
615   glk_put_string_stream(savefile, \"    \");/* Interpreter ID */
616   glk_put_buffer_stream(savefile, *gamehandle, *gamehandle->aliasSize);
617 }
618
619 glui32 intd_get_size(void)
620 {
621   if(!hashandle)
622     return 0;
623   return *gamehandle->aliasSize + 12;
624 }
625
626 static Boolean mac_whenselected(FSSpec *file, OSType filetype)
627 {
628   NewAlias(NULL, file, &gamehandle);
629   hashandle = TRUE;
630   return game_use_file(mac_gamefile);
631 }
632
633 static Boolean mac_whenbuiltin()
634 {
635   return game_use_file(mac_gamefile);
636 }
637
638 Boolean macglk_startup_code(macglk_startup_t *data)
639 {
640   OSType mac_gamefile_types[] = { ";
641
642     my $flag = 0;
643     foreach my $filetype (@mac_gamefile) {
644         if($flag) {
645             print ", ";
646         }
647         $flag = 1;
648         print string_to_iff($filetype);
649     }
650
651     print " };
652
653   data->startup_model  = macglk_model_ChooseOrBuiltIn;
654   data->app_creator    = ", string_to_iff($mac_creator), ";
655   data->gamefile_types = mac_gamefile_types;
656   data->num_gamefile_types = sizeof(mac_gamefile_types) / sizeof(*mac_gamefile_types);
657   data->savefile_type  = ", string_to_iff($mac_savefile), ";
658   data->datafile_type  = ", string_to_iff($mac_datafile), ";
659   data->gamefile       = &mac_gamefile;
660   data->when_selected  = mac_whenselected;
661   data->when_builtin   = mac_whenbuiltin;
662
663   return TRUE;
664 }
665 ";
666 }
667
668 sub make_generic_intd
669 {
670     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
671 strid_t intd_filehandle_open(strid_t savefile, glui32 operating_id,
672                              glui32 contents_id, glui32 interp_id,
673                              glui32 length)
674 {
675   return 0;
676 }
677
678 void intd_filehandle_make(strid_t savefile)
679 {
680   ;
681 }
682
683 glui32 intd_get_size(void)
684 {
685   return 0;
686 }
687 ";
688 }
689
690
691 sub make_generic_findfile
692 {
693     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
694 strid_t startup_findfile(void)
695 {
696   ;
697 }
698 ";
699 }
700
701
702 sub make_generic_startup_open
703 {
704     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
705 strid_t startup_open(const char *name)
706 {
707   return n_file_name(fileusage_Data | fileusage_BinaryMode,
708                      filemode_Read, name);
709 }
710 ";
711 }
712
713
714 sub make_generic_startup_wopen
715 {
716     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
717 static strid_t startup_wopen(const char *name)
718 {
719   return n_file_name(fileusage_Data | fileusage_BinaryMode,
720                      filemode_Write, name);
721 }
722 ";
723 }
724
725
726
727 sub make_functions
728 {
729     foreach my $soption (@LoL) {
730         my @option = @{ $soption };
731         if($option[4] eq "flag") {
732             $argtype = "int flag";
733         }
734         if($option[4] eq "file" || $option[4] eq "wfile") {
735             $argtype = "strid_t stream";
736         }
737         if($option[4] eq "number") {
738             $argtype = "int number";
739         }
740         if($option[4] eq "string") {
741             $argtype = "const char *string";
742         }
743         
744         print "static void code_$option[1]($argtype)\n";
745         print "#line $option[7] \"$option[8]\"\n";
746         print "$option[6]\n\n";
747     }
748 }
749
750
751
752 sub make_useful_command_structure
753 {
754     #
755     # Write structure so we can actually parse the options
756     #
757     my ( $int_func, $defint, $str_func, $defstr, $string_func, $defstring );
758
759     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"';
760     print "\ntypedef enum { option_flag, option_file, option_wfile, option_number, option_string } option_type;\n";
761     print "typedef struct { const char *longname; char shortname; const char *description; option_type type; void (*int_func)(int); int defint; void (*str_func)(strid_t); strid_t defstream; void (*string_func)(const char *); const char *defstring; } option_option;\n\n";
762
763     print "static option_option options[] = {\n";
764
765     my $flag = 0;
766     foreach my $soption (@LoL) {
767         my @option = @{ $soption };
768         if($flag) {
769             print ",\n";
770         }
771         $flag = 1;
772
773         $int_func = "NULL";
774         $defint = "0";
775
776         $str_func = "NULL";
777         $defstr = "NULL";
778
779         $string_func = "NULL";
780         $defstring = "NULL";
781         
782         if($option[4] eq "flag") {
783             $defint = $option[5];
784             $int_func = "code_" . $option[1];
785         }
786         if($option[4] eq "file" || $option[4] eq "wfile") {
787             $defstr = $option[5];
788             $str_func = "code_" . $option[1];
789         }
790         if($option[4] eq "number") {
791             $defint = $option[5];
792             $int_func = "code_" . $option[1];
793         }
794         if($option[4] eq "string") {
795             $defstring = $option[5];
796             $string_func = "code_" . $option[1];
797         }
798         
799         print "  { \"$option[1]\", '$option[2]', \"", texi2txt($option[3]), "\", option_$option[4], $int_func, $defint, $str_func, $defstr, $string_func, $defstring }";
800     }
801     
802     print "\n};\n\n";
803
804 }
805
806
807
808 sub make_default_setter
809 {
810     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
811 static void set_defaults(void)
812 {
813   unsigned n;
814   for(n = 0; n < sizeof(options) / sizeof(*options); n++) {
815     if(options[n].int_func)
816       options[n].int_func(options[n].defint);
817     if(options[n].str_func)
818       options[n].str_func(options[n].defstream);
819     if(options[n].string_func)
820       options[n].string_func(options[n].defstring);
821   }
822 }
823 \n";
824 }
825
826 sub make_textpref_reader
827 {
828     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
829 static void read_textpref(strid_t pref, const char *progname)
830 {
831   unsigned n;
832   char buffer[1024];
833   int prognamelen = n_strlen(progname);
834   if(!pref)
835     return;
836   while(glk_get_line_stream(pref, buffer, sizeof(buffer))) {
837     char *optname;
838     char *optval;
839     long int optnum;
840
841     if(buffer[0] == '#')
842       continue;
843     while(buffer[0] == '[') {
844       if(n_strncasecmp(buffer+1, progname, prognamelen) != 0
845          || buffer[1+prognamelen] != ']') {
846         while(glk_get_line_stream(pref, buffer, sizeof(buffer)))
847           if(buffer[0] == '[')
848             break;
849       } else {
850         glk_get_line_stream(pref, buffer, sizeof(buffer));
851       }
852     }
853
854     optname = buffer;
855     while(isspace(*optname))
856       optname++;
857     if((optval = n_strchr(optname, '=')) != NULL) {
858       char *p;
859       *optval = 0;
860       optval++;
861
862       if((p = n_strchr(optname, ' ')) != NULL)
863         *p = 0;
864       
865       while(isspace(*optval))
866         optval++;
867
868       while(isspace(optval[strlen(optval)-1]))
869         optval[strlen(optval)-1] = 0;
870
871       optnum = n_strtol(optval, NULL, 0);
872       if(n_strcasecmp(optval, \"false\") == 0
873          || n_strcasecmp(optval, \"f\") == 0)
874         optnum = FALSE;
875       if(n_strcasecmp(optval, \"true\") == 0
876          || n_strcasecmp(optval, \"t\") == 0)
877         optnum = TRUE;
878
879       for(n = 0; n < sizeof(options) / sizeof(*options); n++) {
880         if(n_strcmp(options[n].longname, optname) == 0) {
881           switch(options[n].type) {
882           case option_flag:
883           case option_number:
884             options[n].int_func(optnum);
885             break;
886           case option_file:
887             options[n].str_func(startup_open(optval));
888             break;
889           case option_wfile:
890             options[n].str_func(startup_wopen(optval));
891             break;
892           case option_string:
893             options[n].string_func(optval);
894             break;
895           }
896           break;
897         }
898       }
899     }
900   }
901   glk_stream_close(pref, NULL);
902 }
903 \n";
904 }
905
906
907 sub make_help_printer
908 {
909     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
910 static void show_help(void)
911 {
912   unsigned n;
913   printf(\"Usage: $appname [OPTIONS] gamefile\\n\");
914   for(n = 0; n < sizeof(options) / sizeof(*options); n++) {
915     if(options[n].shortname != '-')
916       printf(\" -%c, \", options[n].shortname);
917     else
918       printf(\"     \");
919     printf(\"-%-15s %s\\n\", options[n].longname, options[n].description);
920   }
921 }
922 \n";
923 }
924
925 sub make_command_parser
926 {
927     print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
928 static BOOL parse_commands(int argc, char **argv)
929 {
930   int i;
931   unsigned n;
932
933   for(i = 1; i < argc; i++) {
934     BOOL flag = TRUE;
935
936     const char *p = argv[i];
937     
938     if(p[0] == '-') {
939       BOOL found = FALSE;
940
941       while(*p == '-')
942         p++;
943       if(n_strncmp(p, \"no-\", 3) == 0) {
944         flag = FALSE;
945         p+=3;
946       }
947
948       if(n_strcasecmp(p, \"help\") == 0) {
949         show_help();
950         exit(0);
951       }
952       if(n_strcasecmp(p, \"version\") == 0) {
953         printf(\"$appname version %d.%d\\n\", $appmajor, $appminor);
954         exit(0);
955       }
956       
957       for(n = 0; n < sizeof(options) / sizeof(*options); n++) {
958         if((n_strlen(p) == 1 && *p == options[n].shortname) ||
959            n_strcmp(options[n].longname, p) == 0) {
960           found = TRUE;
961
962           switch(options[n].type) {
963           case option_flag:
964             options[n].int_func(flag);
965             break;
966
967           case option_file:
968             i++;
969             options[n].str_func(startup_open(argv[i]));
970             break;
971
972           case option_wfile:
973             i++;
974             options[n].str_func(startup_wopen(argv[i]));
975             break;
976
977           case option_number:
978             i++;
979             options[n].int_func(n_strtol(argv[i], NULL, 0));
980             break;
981
982           case option_string:
983             i++;
984             options[n].string_func(argv[i]);
985             break;
986           }
987         }
988       }
989
990       if(!found)
991         return FALSE;
992
993     } else {
994       strid_t s = startup_open(argv[i]);
995       if(!s)
996         return FALSE;
997       if(!game_use_file(s))
998         return FALSE;
999     }
1000   }
1001
1002   return TRUE;
1003 }
1004 \n";
1005 }
1006
1007
1008
1009
1010 sub make_useless_command_structure
1011 {
1012     print "glkunix_argumentlist_t glkunix_arguments[] = {\n";
1013     
1014     print "  { (char *) \"\", glkunix_arg_ValueCanFollow, (char *) \"filename\tfile to load\" },\n";
1015
1016     print "  { (char *) \"-help\", glkunix_arg_NoValue, (char *) \"list command-line options\" },\n";
1017     print "  { (char *) \"--help\", glkunix_arg_NoValue, (char *) \"list command-line options\" },\n";
1018     print "  { (char *) \"-version\", glkunix_arg_NoValue, (char *) \"get version number\" },\n";
1019     print "  { (char *) \"--version\", glkunix_arg_NoValue, (char *) \"get version number\" },\n";
1020
1021     
1022     foreach my $soption (@LoL) {
1023         my @option = @{ $soption };
1024         if($option[4] eq "flag") {
1025             $argtype = "glkunix_arg_NoValue";
1026         }
1027         if($option[4] eq "file" || $option[4] eq "wfile") {
1028             $argtype = "glkunix_arg_ValueFollows";
1029         }
1030         if($option[4] eq "number") {
1031             $argtype = "glkunix_arg_NumberValue";
1032         }
1033         if($option[4] eq "string") {
1034            $argtype = "glkunix_arg_ValueFollows";
1035        }
1036         
1037         if($option[2] ne "-") {
1038             print "  { (char *) \"-$option[2]\", $argtype, (char *) \"-$option[2]\" },\n";
1039         }
1040         
1041         if($option[4] eq "flag") {
1042             print "  { (char *) \"-no-$option[1]\", $argtype, (char *) \"-no-$option[1]\" },\n";
1043             print "  { (char *) \"--no-$option[1]\", $argtype, (char *) \"--no-$option[1]\" },\n";
1044         }
1045         
1046         print "  { (char *) \"-$option[1]\", $argtype, (char *) \"-$option[1]\" },\n";
1047         print "  { (char *) \"--$option[1]\", $argtype, (char *) \"--$option[1]\t$option[3]\" },\n";
1048     }
1049
1050     print "  { NULL, glkunix_arg_End, NULL }\n";
1051     print "};\n\n";
1052
1053 }
1054
1055