1 #!/usr/local/bin/perl -w
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 );
18 # The following are modified by make_glk_* as appropriate
20 my $configdir = "configdir = n_strdup(getenv(\"HOME\"));";
21 my $configname = "configname = \"${dirsep}.${appname}rc\";";
24 # opt2glkc.pl - Generates Glk startup code and some documentation
25 # Copyright (C) 1999 Evin Robertson
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.
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.
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.
41 # The author can be reached at nitfol@my-deja.com
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 ]
66 $optionlist{$systemtype} || die "Unknown switch '-$systemtype'\n";
68 open("MYOUTPUT", ">$optionlist{$systemtype}[0]") || die "cannot write to $optionlist{$systemtype}[0]\n";
71 &{ $optionlist{$systemtype}[1] }();
87 elsif(/^\s*\"(.*?)\"\s+(\S+)\s+(\S)\s+\"(.*?)\"\s+(\S+)\s+((\S+)|(\".*?\"))\s+(\{.*)$/) {
89 push @LoL, [ ( $1, $2, $3, $4, $5, $6, $9, $i, $ARGV, $longdesc ) ];
92 die "Error in file $ARGV line $i.";
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";
111 print "\@item -$option[1] \@var{$option[4]}\n";
112 if($option[2] ne "-") {
113 print "\@itemx -$option[2] \@var{$option[4]}\n";
116 print "$option[3]. $option[9]\n";
123 s/\@itemize \@minus\n//;
124 s/\@end itemize/.PP/;
125 s/\@item /.IP \\\(bu\n/;
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;
145 s/\@code\{(.*?)\}/\'$1\'/g;
146 s/\@file\{(.*?)\}/\'$1\'/g;
154 open("MYTEXINFO", "<$texinfo") || die "unable to read '$texinfo'\n";
155 print ".TH ", uc $appname, " 6\n";
157 while(($_ = <MYTEXINFO>) !~ /^\* $appname: \($appname\). *.*/i) {
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) {
170 while(($_ = <MYTEXINFO>) !~ /^(\@node)|(\@bye)|(\@menu)/) {
175 print ".SH OPTIONS\n";
176 foreach my $soption (@LoL) {
177 my @option = @{ $soption };
180 if($option[4] eq "flag") {
181 print " \\-$option[1]";
182 print ", \\-no\\-$option[1]";
183 if($option[2] ne "-") {
184 print ", \\-$option[2]";
187 print " \\-$option[1] \\fI$option[4]\\fB";
188 if($option[2] ne "-") {
189 print ", \\-$option[2] \\fI$option[4]";
193 print texi2roff($option[3]), ". ", texi2roff($option[9]);
197 while(<MYTEXINFO> !~ /^\@chapter bugs/i) {
200 while(($_ = <MYTEXINFO>) !~ /^(\@node)|(\@bye)/) {
204 print ".SH \"SEE ALSO\"\n";
205 print ".RB \"`\\|\" $appname \"\\|'\"\n";
211 foreach my $also (@man_see_also) {
220 print ".SH AUTHOR\n";
221 print "$appname was written by $author, who can be reached at $email.\n";
227 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
234 #include <sys/types.h>
235 #include <sys/stat.h>
239 #include \"glkstart.h\"
241 static char *game_filename = NULL;
243 static void set_game_filename(const char *name)
245 n_free(game_filename);
248 #if defined(_GNU_SOURCE)
249 game_filename = canonicalize_file_name(name);
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);
259 game_filename = (char *) n_malloc(FILENAME_MAX);
260 _fixpath(name, game_filename);
266 game_filename = n_strdup(name);
270 strid_t startup_findfile(void)
272 static DIR *dir = NULL;
273 static char *pathstart = NULL;
274 static char *path = NULL;
280 char *p = search_path;
283 pathstart = n_strdup(p);
284 if(!(path = n_strtok(pathstart, \":\"))) {
304 if(!(path = n_strtok(NULL, \":\"))) {
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);
319 set_game_filename(name);
325 strid_t intd_filehandle_open(strid_t savefile, glui32 operating_id,
326 glui32 contents_id, glui32 interp_id,
331 if(operating_id != ", string_to_iff("UNIX"), ")
335 if(interp_id != ", string_to_iff(" "), ")
338 name = (char *) n_malloc(length+1);
339 glk_get_buffer_stream(savefile, name, length);
341 str = glkunix_stream_open_pathname(name, fileusage_Data |
342 fileusage_BinaryMode, 0);
344 set_game_filename(name);
349 void intd_filehandle_make(strid_t savefile)
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);
362 glui32 intd_get_size(void)
366 return n_strlen(game_filename) + 12;
369 strid_t startup_open(const char *name)
373 str = glkunix_stream_open_pathname((char *) name, fileusage_Data | fileusage_BinaryMode, 0);
375 set_game_filename(name);
377 char *path = search_path;
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);
389 set_game_filename(newname);
398 fprintf(stderr, \"Cannot open '%s'\\n\", name);
405 make_generic_startup_wopen();
406 make_useless_command_structure();
408 make_useful_command_structure();
409 make_default_setter();
410 make_textpref_reader();
412 make_command_parser();
414 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
417 static void sighandle(int unused);
419 static void sighandle(int unused)
421 /* signal(SIGINT, sighandle); */ /* SysV resets default behaviour - foil it */
422 enter_debugger = TRUE;
429 int glkunix_startup_code(glkunix_startup_t *data)
432 const char *configname;
433 char *configdir, *prefname;
436 username = getenv(\"LOGNAME\"); /* SysV */
438 username = getenv(\"USER\"); /* BSD */
441 /* signal(SIGINT, sighandle); */
444 execname = n_strrchr(data->argv[0], '$dirsep');
449 execname = data->argv[0];
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);
460 read_textpref(pref, execname);
462 p = getenv(\"$search_path\");
465 search_path = n_strdup(p);
468 return parse_commands(data->argc, data->argv);
479 $configdir = "configdir = n_strdup(data->argv[0]); if(n_strrchr(configdir, '$dirsep')) *n_strrchr(configdir, '$dirsep') = 0;";
480 $configname = "configname = \"${dirsep}${appname}.cfg\";";
487 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
489 #include \"WinGlk.h\"
493 make_generic_findfile();
494 make_generic_startup_open();
495 make_generic_startup_wopen();
497 make_useful_command_structure();
498 make_default_setter();
500 make_command_parser();
503 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
504 void shift_string_left(char *str)
506 int len = strlen(str);
508 for(i = 0; i < len; i++)
512 int winglk_startup_code(void)
515 char *commandline = strdup(GetCommandLine());
516 char **argv = (char **) n_malloc(sizeof(char *) * strlen(commandline));
521 while(*commandline) {
522 while(*commandline && isspace(*commandline))
525 argv[argc++] = commandline;
527 while(*commandline && !isspace(*commandline)) {
528 if(*commandline == '\"') {
529 shift_string_left(commandline);
530 while(*commandline && *commandline != '\"')
532 shift_string_left(commandline);
543 status = parse_commands(argc, argv);
548 winglk_app_set_name(\"$appname\");
549 winglk_window_set_title(\"$appname\");
565 for($i=0; $i < length $id; $i++) {
566 $val = $val * 0x100 + ord substr $id, $i, 1;
568 return sprintf("0x%x /* '$id' */", $val);
575 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
577 #include \"macglk_startup.h\"
579 static strid_t mac_gamefile;
581 static BOOL hashandle = FALSE;
582 static AliasHandle gamehandle;
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,
592 if(operating_id != ", string_to_iff("MACS"), ")
596 if(interp_id != ", string_to_iff(" "), ")
599 gamehandle = NewHandle(length);
600 glk_get_buffer_stream(savefile, *gamehandle, length);
602 ResolveAlias(NULL, gamehandle, &file, &wasChanged);
603 return macglk_stream_open_fsspec(&file, 0, 0);
606 void intd_filehandle_make(strid_t savefile)
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);
619 glui32 intd_get_size(void)
623 return *gamehandle->aliasSize + 12;
626 static Boolean mac_whenselected(FSSpec *file, OSType filetype)
628 NewAlias(NULL, file, &gamehandle);
630 return game_use_file(mac_gamefile);
633 static Boolean mac_whenbuiltin()
635 return game_use_file(mac_gamefile);
638 Boolean macglk_startup_code(macglk_startup_t *data)
640 OSType mac_gamefile_types[] = { ";
643 foreach my $filetype (@mac_gamefile) {
648 print string_to_iff($filetype);
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;
668 sub make_generic_intd
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,
678 void intd_filehandle_make(strid_t savefile)
683 glui32 intd_get_size(void)
691 sub make_generic_findfile
693 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
694 strid_t startup_findfile(void)
702 sub make_generic_startup_open
704 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
705 strid_t startup_open(const char *name)
707 return n_file_name(fileusage_Data | fileusage_BinaryMode,
708 filemode_Read, name);
714 sub make_generic_startup_wopen
716 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
717 static strid_t startup_wopen(const char *name)
719 return n_file_name(fileusage_Data | fileusage_BinaryMode,
720 filemode_Write, name);
729 foreach my $soption (@LoL) {
730 my @option = @{ $soption };
731 if($option[4] eq "flag") {
732 $argtype = "int flag";
734 if($option[4] eq "file" || $option[4] eq "wfile") {
735 $argtype = "strid_t stream";
737 if($option[4] eq "number") {
738 $argtype = "int number";
740 if($option[4] eq "string") {
741 $argtype = "const char *string";
744 print "static void code_$option[1]($argtype)\n";
745 print "#line $option[7] \"$option[8]\"\n";
746 print "$option[6]\n\n";
752 sub make_useful_command_structure
755 # Write structure so we can actually parse the options
757 my ( $int_func, $defint, $str_func, $defstr, $string_func, $defstring );
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";
763 print "static option_option options[] = {\n";
766 foreach my $soption (@LoL) {
767 my @option = @{ $soption };
779 $string_func = "NULL";
782 if($option[4] eq "flag") {
783 $defint = $option[5];
784 $int_func = "code_" . $option[1];
786 if($option[4] eq "file" || $option[4] eq "wfile") {
787 $defstr = $option[5];
788 $str_func = "code_" . $option[1];
790 if($option[4] eq "number") {
791 $defint = $option[5];
792 $int_func = "code_" . $option[1];
794 if($option[4] eq "string") {
795 $defstring = $option[5];
796 $string_func = "code_" . $option[1];
799 print " { \"$option[1]\", '$option[2]', \"", texi2txt($option[3]), "\", option_$option[4], $int_func, $defint, $str_func, $defstr, $string_func, $defstring }";
808 sub make_default_setter
810 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
811 static void set_defaults(void)
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);
826 sub make_textpref_reader
828 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
829 static void read_textpref(strid_t pref, const char *progname)
833 int prognamelen = n_strlen(progname);
836 while(glk_get_line_stream(pref, buffer, sizeof(buffer))) {
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)))
850 glk_get_line_stream(pref, buffer, sizeof(buffer));
855 while(isspace(*optname))
857 if((optval = n_strchr(optname, '=')) != NULL) {
862 if((p = n_strchr(optname, ' ')) != NULL)
865 while(isspace(*optval))
868 while(isspace(optval[strlen(optval)-1]))
869 optval[strlen(optval)-1] = 0;
871 optnum = n_strtol(optval, NULL, 0);
872 if(n_strcasecmp(optval, \"false\") == 0
873 || n_strcasecmp(optval, \"f\") == 0)
875 if(n_strcasecmp(optval, \"true\") == 0
876 || n_strcasecmp(optval, \"t\") == 0)
879 for(n = 0; n < sizeof(options) / sizeof(*options); n++) {
880 if(n_strcmp(options[n].longname, optname) == 0) {
881 switch(options[n].type) {
884 options[n].int_func(optnum);
887 options[n].str_func(startup_open(optval));
890 options[n].str_func(startup_wopen(optval));
893 options[n].string_func(optval);
901 glk_stream_close(pref, NULL);
907 sub make_help_printer
909 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
910 static void show_help(void)
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);
919 printf(\"-%-15s %s\\n\", options[n].longname, options[n].description);
925 sub make_command_parser
927 print "#line " . (__LINE__+1) . ' "' . __FILE__ . '"' . "
928 static BOOL parse_commands(int argc, char **argv)
933 for(i = 1; i < argc; i++) {
936 const char *p = argv[i];
943 if(n_strncmp(p, \"no-\", 3) == 0) {
948 if(n_strcasecmp(p, \"help\") == 0) {
952 if(n_strcasecmp(p, \"version\") == 0) {
953 printf(\"$appname version %d.%d\\n\", $appmajor, $appminor);
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) {
962 switch(options[n].type) {
964 options[n].int_func(flag);
969 options[n].str_func(startup_open(argv[i]));
974 options[n].str_func(startup_wopen(argv[i]));
979 options[n].int_func(n_strtol(argv[i], NULL, 0));
984 options[n].string_func(argv[i]);
994 strid_t s = startup_open(argv[i]);
997 if(!game_use_file(s))
1010 sub make_useless_command_structure
1012 print "glkunix_argumentlist_t glkunix_arguments[] = {\n";
1014 print " { (char *) \"\", glkunix_arg_ValueCanFollow, (char *) \"filename\tfile to load\" },\n";
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";
1022 foreach my $soption (@LoL) {
1023 my @option = @{ $soption };
1024 if($option[4] eq "flag") {
1025 $argtype = "glkunix_arg_NoValue";
1027 if($option[4] eq "file" || $option[4] eq "wfile") {
1028 $argtype = "glkunix_arg_ValueFollows";
1030 if($option[4] eq "number") {
1031 $argtype = "glkunix_arg_NumberValue";
1033 if($option[4] eq "string") {
1034 $argtype = "glkunix_arg_ValueFollows";
1037 if($option[2] ne "-") {
1038 print " { (char *) \"-$option[2]\", $argtype, (char *) \"-$option[2]\" },\n";
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";
1046 print " { (char *) \"-$option[1]\", $argtype, (char *) \"-$option[1]\" },\n";
1047 print " { (char *) \"--$option[1]\", $argtype, (char *) \"--$option[1]\t$option[3]\" },\n";
1050 print " { NULL, glkunix_arg_End, NULL }\n";