From bbb9b015db1f543d35a98debbc2a7a73f7ca81a0 Mon Sep 17 00:00:00 2001 From: Stephen Oman Date: Fri, 12 Jun 2026 15:05:25 +0100 Subject: [PATCH 1/3] Remove files deleted from nh5 --- util/dgn_comp.l | 144 --- util/dgn_comp.y | 678 ------------ util/dgn_main.c | 193 ---- util/lev_comp.l | 437 -------- util/lev_comp.y | 2721 ----------------------------------------------- util/lev_main.c | 1649 ---------------------------- 6 files changed, 5822 deletions(-) delete mode 100644 util/dgn_comp.l delete mode 100644 util/dgn_comp.y delete mode 100644 util/dgn_main.c delete mode 100644 util/lev_comp.l delete mode 100644 util/lev_comp.y delete mode 100644 util/lev_main.c diff --git a/util/dgn_comp.l b/util/dgn_comp.l deleted file mode 100644 index 99c8527a1..000000000 --- a/util/dgn_comp.l +++ /dev/null @@ -1,144 +0,0 @@ -%{ -/* NetHack 3.6 dgn_comp.l $NHDT-Date: 1455415007 2016/02/14 01:56:47 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* Copyright (c) 1990 by M. Stephenson */ -/* NetHack may be freely redistributed. See license for details. */ - -#define DGN_COMP - -#include "config.h" -#include "dgn_comp.h" -#include "dgn_file.h" - -/* - * Most of these don't exist in flex, yywrap is macro and - * yyunput is properly declared in flex.skel. - */ -#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) -int FDECL(yyback, (int *,int)); -int NDECL(yylook); -int NDECL(yyinput); -int NDECL(yywrap); -int NDECL(yylex); - /* Traditional lexes let yyunput() and yyoutput() default to int; - * newer ones may declare them as void since they don't return - * values. For even more fun, the lex supplied as part of the - * newer unbundled compiler for SunOS 4.x adds the void declarations - * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain - * int) while the bundled lex and the one with the older unbundled - * compiler do not. To detect this, we need help from outside -- - * sys/unix/Makefile.utl. - * - * Digital UNIX is difficult and still has int in spite of all - * other signs. - */ -# if defined(NeXT) || defined(SVR4) || defined(_AIX32) -# define VOIDYYPUT -# endif -# if !defined(VOIDYYPUT) && defined(POSIX_TYPES) -# if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) -# define VOIDYYPUT -# endif -# endif -# if !defined(VOIDYYPUT) && defined(WEIRD_LEX) -# if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) -# define VOIDYYPUT -# endif -# endif -# if defined(VOIDYYPUT) && defined(__osf__) -# undef VOIDYYPUT -# endif -# ifdef VOIDYYPUT -void FDECL(yyunput, (int)); -void FDECL(yyoutput, (int)); -# else -int FDECL(yyunput, (int)); -int FDECL(yyoutput, (int)); -# endif - -#else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ -/* most recent flex allows suppressing yyunput() altogether when not needed */ -#define YY_NO_UNPUT -#define YY_NO_INPUT -#endif - -#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) -/* older flex wants this */ -#define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ - genericptr_t FDECL(realloc, (genericptr_t, size_t)); -/* newer flex assumes so needs this in case it's been suppressed */ -YY_MALLOC_DECL -#endif - -void FDECL(init_yyin, (FILE *)); -void FDECL(init_yyout, (FILE *)); - -/* this doesn't always get put in dgn_comp.h - * (esp. when using older versions of bison) - */ -extern YYSTYPE yylval; - -int nh_line_number = 1; - -%} -%% -DUNGEON return(A_DUNGEON); -up { yylval.i=1; return(UP_OR_DOWN); } -down { yylval.i=0; return(UP_OR_DOWN); } -ENTRY return(ENTRY); -stair return(STAIR); -no_up return(NO_UP); -no_down return(NO_DOWN); -portal return(PORTAL); -PROTOFILE return(PROTOFILE); -DESCRIPTION return(DESCRIPTION); -LEVELDESC return(LEVELDESC); -ALIGNMENT return(ALIGNMENT); -LEVALIGN return(LEVALIGN); -town { yylval.i=TOWN ; return(DESCRIPTOR); } -hellish { yylval.i=HELLISH ; return(DESCRIPTOR); } -mazelike { yylval.i=MAZELIKE ; return(DESCRIPTOR); } -roguelike { yylval.i=ROGUELIKE ; return(DESCRIPTOR); } -unaligned { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } -noalign { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } -lawful { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); } -neutral { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); } -chaotic { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); } -BRANCH return(BRANCH); -CHAINBRANCH return(CHBRANCH); -LEVEL return(LEVEL); -RNDLEVEL return(RNDLEVEL); -CHAINLEVEL return(CHLEVEL); -RNDCHLEVEL return(RNDCHLEVEL); -[-0-9]+ { yylval.i=atoi(yytext); return(INTEGER); } -\"[^"]*\" { yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ - yylval.str = dupstr(yytext + 1); /* skip the first \" */ - return STRING; } -^#.*\n { nh_line_number++; } -\r?\n { nh_line_number++; } -[ \t]+ ; /* skip trailing tabs & spaces */ -. { return yytext[0]; } -%% - -/* routine to switch to another input file; needed for flex */ -void -init_yyin( input_f ) -FILE *input_f; -{ -#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) - if (yyin) - yyrestart(input_f); - else -#endif - yyin = input_f; -} - -/* analogous routine (for completeness) */ -void -init_yyout( output_f ) -FILE *output_f; -{ - yyout = output_f; -} - -/*dgn_comp.l*/ diff --git a/util/dgn_comp.y b/util/dgn_comp.y deleted file mode 100644 index a00ff7559..000000000 --- a/util/dgn_comp.y +++ /dev/null @@ -1,678 +0,0 @@ -%{ -/* NetHack 3.6 dgn_comp.y $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* Copyright (c) 1990 by M. Stephenson */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * This file contains the Dungeon Compiler code - */ - -/* In case we're using bison in AIX. This definition must be - * placed before any other C-language construct in the file - * excluding comments and preprocessor directives (thanks IBM - * for this wonderful feature...). - * - * Note: some cpps barf on this 'undefined control' (#pragma). - * Addition of the leading space seems to prevent barfage for now, - * and AIX will still see the directive in its non-standard locale. - */ - -#ifdef _AIX - #pragma alloca /* keep leading space! */ -#endif - -#include "config.h" -#include "date.h" -#include "dgn_file.h" - -void FDECL(yyerror, (const char *)); -void FDECL(yywarning, (const char *)); -int NDECL(yylex); -int NDECL(yyparse); -int FDECL(getchain, (char *)); -int NDECL(check_dungeon); -int NDECL(check_branch); -int NDECL(check_level); -void NDECL(init_dungeon); -void NDECL(init_branch); -void NDECL(init_level); -void NDECL(output_dgn); - -#define Free(ptr) free((genericptr_t)ptr) - -#ifdef AMIGA -# undef printf -#ifndef LATTICE -# define memset(addr,val,len) setmem(addr,len,val) -#endif -#endif - -#define ERR (-1) - -static struct couple couple; -static struct tmpdungeon tmpdungeon[MAXDUNGEON]; -static struct tmplevel tmplevel[LEV_LIMIT]; -static struct tmpbranch tmpbranch[BRANCH_LIMIT]; - -static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; - -extern int fatal_error; -extern const char *fname; -extern FILE *yyin, *yyout; /* from dgn_lex.c */ - -%} - -%union -{ - int i; - char* str; -} - -%token INTEGER -%token A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL -%token UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC -%token ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL -%token STRING -%type optional_int direction branch_type bones_tag -%start file - -%% -file : /* nothing */ - | dungeons - { - output_dgn(); - } - ; - -dungeons : dungeon - | dungeons dungeon - ; - -dungeon : dungeonline - | dungeondesc - | branches - | levels - ; - -dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int - { - init_dungeon(); - Strcpy(tmpdungeon[n_dgns].name, $3); - tmpdungeon[n_dgns].boneschar = (char)$4; - tmpdungeon[n_dgns].lev.base = couple.base; - tmpdungeon[n_dgns].lev.rand = couple.rand; - tmpdungeon[n_dgns].chance = $6; - Free($3); - } - ; - -optional_int : /* nothing */ - { - $$ = 0; - } - | INTEGER - { - $$ = $1; - } - ; - -dungeondesc : entry - | descriptions - | prototype - ; - -entry : ENTRY ':' INTEGER - { - tmpdungeon[n_dgns].entry_lev = $3; - } - ; - -descriptions : desc - ; - -desc : DESCRIPTION ':' DESCRIPTOR - { - if($3 <= TOWN || $3 >= D_ALIGN_CHAOTIC) - yyerror("Illegal description - ignoring!"); - else - tmpdungeon[n_dgns].flags |= $3 ; - } - | ALIGNMENT ':' DESCRIPTOR - { - if($3 && $3 < D_ALIGN_CHAOTIC) - yyerror("Illegal alignment - ignoring!"); - else - tmpdungeon[n_dgns].flags |= $3 ; - } - ; - -prototype : PROTOFILE ':' STRING - { - Strcpy(tmpdungeon[n_dgns].protoname, $3); - Free($3); - } - ; - -levels : level1 - | level2 - | levdesc - | chlevel1 - | chlevel2 - ; - -level1 : LEVEL ':' STRING bones_tag '@' acouple - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmpdungeon[n_dgns].levels++; - Free($3); - } - | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].rndlevs = $7; - tmpdungeon[n_dgns].levels++; - Free($3); - } - ; - -level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].chance = $7; - tmpdungeon[n_dgns].levels++; - Free($3); - } - | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].chance = $7; - tmplevel[n_levs].rndlevs = $8; - tmpdungeon[n_dgns].levels++; - Free($3); - } - ; - -levdesc : LEVELDESC ':' DESCRIPTOR - { - if($3 >= D_ALIGN_CHAOTIC) - yyerror("Illegal description - ignoring!"); - else - tmplevel[n_levs].flags |= $3 ; - } - | LEVALIGN ':' DESCRIPTOR - { - if($3 && $3 < D_ALIGN_CHAOTIC) - yyerror("Illegal alignment - ignoring!"); - else - tmplevel[n_levs].flags |= $3 ; - } - ; - -chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].chain = getchain($5); - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - if(!check_level()) n_levs--; - else tmpdungeon[n_dgns].levels++; - Free($3); - Free($5); - } - | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].chain = getchain($5); - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].rndlevs = $8; - if(!check_level()) n_levs--; - else tmpdungeon[n_dgns].levels++; - Free($3); - Free($5); - } - ; - -chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].chain = getchain($5); - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].chance = $8; - if(!check_level()) n_levs--; - else tmpdungeon[n_dgns].levels++; - Free($3); - Free($5); - } - | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER - { - init_level(); - Strcpy(tmplevel[n_levs].name, $3); - tmplevel[n_levs].boneschar = (char)$4; - tmplevel[n_levs].chain = getchain($5); - tmplevel[n_levs].lev.base = couple.base; - tmplevel[n_levs].lev.rand = couple.rand; - tmplevel[n_levs].chance = $8; - tmplevel[n_levs].rndlevs = $9; - if(!check_level()) n_levs--; - else tmpdungeon[n_dgns].levels++; - Free($3); - Free($5); - } - ; - -branches : branch - | chbranch - ; - -branch : BRANCH ':' STRING '@' acouple branch_type direction - { - init_branch(); - Strcpy(tmpbranch[n_brs].name, $3); - tmpbranch[n_brs].lev.base = couple.base; - tmpbranch[n_brs].lev.rand = couple.rand; - tmpbranch[n_brs].type = $6; - tmpbranch[n_brs].up = $7; - if(!check_branch()) n_brs--; - else tmpdungeon[n_dgns].branches++; - Free($3); - } - ; - -chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction - { - init_branch(); - Strcpy(tmpbranch[n_brs].name, $3); - tmpbranch[n_brs].chain = getchain($4); - tmpbranch[n_brs].lev.base = couple.base; - tmpbranch[n_brs].lev.rand = couple.rand; - tmpbranch[n_brs].type = $7; - tmpbranch[n_brs].up = $8; - if(!check_branch()) n_brs--; - else tmpdungeon[n_dgns].branches++; - Free($3); - Free($4); - } - ; - -branch_type : /* nothing */ - { - $$ = TBR_STAIR; /* two way stair */ - } - | STAIR - { - $$ = TBR_STAIR; /* two way stair */ - } - | NO_UP - { - $$ = TBR_NO_UP; /* no up staircase */ - } - | NO_DOWN - { - $$ = TBR_NO_DOWN; /* no down staircase */ - } - | PORTAL - { - $$ = TBR_PORTAL; /* portal connection */ - } - ; - -direction : /* nothing */ - { - $$ = 0; /* defaults to down */ - } - | UP_OR_DOWN - { - $$ = $1; - } - ; - -bones_tag : STRING - { - char *p = $1; - if (strlen(p) != 1) { - if (strcmp(p, "none") != 0) - yyerror("Bones marker must be a single char, or \"none\"!"); - *p = '\0'; - } - $$ = *p; - Free(p); - } - ; - -/* - * acouple rules: - * - * (base, range) where: - * - * base is either a positive or negative integer with a value - * less than or equal to MAXLEVEL. - * base > 0 indicates the base level. - * base < 0 indicates reverse index (-1 == lowest level) - * - * range is the random component. - * if range is zero, there is no random component. - * if range is -1 the dungeon loader will randomize between - * the base and the end of the dungeon. - * during dungeon load, range is always *added* to the base, - * therefore range + base(converted) must not exceed MAXLEVEL. - */ -acouple : '(' INTEGER ',' INTEGER ')' - { - if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { - yyerror("Abs base out of dlevel range - zeroing!"); - couple.base = couple.rand = 0; - } else if ($4 < -1 || - (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL : - ($2 + $4) > MAXLEVEL)) { - yyerror("Abs range out of dlevel range - zeroing!"); - couple.base = couple.rand = 0; - } else { - couple.base = $2; - couple.rand = $4; - } - } - ; - -/* - * rcouple rules: - * - * (base, range) where: - * - * base is either a positive or negative integer with a value - * less than or equal to MAXLEVEL. - * base > 0 indicates a forward index. - * base < 0 indicates a reverse index. - * base == 0 indicates on the parent level. - * - * range is the random component. - * if range is zero, there is no random component. - * during dungeon load, range is always *added* to the base, - * range + base(converted) may be very large. The dungeon - * loader will then correct to "between here and the top/bottom". - * - * There is no practical way of specifying "between here and the - * nth / nth last level". - */ -rcouple : '(' INTEGER ',' INTEGER ')' - { - if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { - yyerror("Rel base out of dlevel range - zeroing!"); - couple.base = couple.rand = 0; - } else { - couple.base = $2; - couple.rand = $4; - } - } - ; -%% - -void -init_dungeon() -{ - if(++n_dgns > MAXDUNGEON) { - (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", - MAXDUNGEON); - (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); - exit(EXIT_FAILURE); - } - - in_dungeon = 1; - tmpdungeon[n_dgns].lev.base = 0; - tmpdungeon[n_dgns].lev.rand = 0; - tmpdungeon[n_dgns].chance = 100; - Strcpy(tmpdungeon[n_dgns].name, ""); - Strcpy(tmpdungeon[n_dgns].protoname, ""); - tmpdungeon[n_dgns].flags = 0; - tmpdungeon[n_dgns].levels = 0; - tmpdungeon[n_dgns].branches = 0; - tmpdungeon[n_dgns].entry_lev = 0; -} - -void -init_level() -{ - if(++n_levs > LEV_LIMIT) { - - yyerror("FATAL - Too many special levels defined."); - exit(EXIT_FAILURE); - } - tmplevel[n_levs].lev.base = 0; - tmplevel[n_levs].lev.rand = 0; - tmplevel[n_levs].chance = 100; - tmplevel[n_levs].rndlevs = 0; - tmplevel[n_levs].flags = 0; - Strcpy(tmplevel[n_levs].name, ""); - tmplevel[n_levs].chain = -1; -} - -void -init_branch() -{ - if(++n_brs > BRANCH_LIMIT) { - - yyerror("FATAL - Too many special levels defined."); - exit(EXIT_FAILURE); - } - tmpbranch[n_brs].lev.base = 0; - tmpbranch[n_brs].lev.rand = 0; - Strcpy(tmpbranch[n_brs].name, ""); - tmpbranch[n_brs].chain = -1; -} - -int -getchain(s) - char *s; -{ - int i; - - if(strlen(s)) { - - for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) - if(!strcmp(tmplevel[i].name, s)) return i; - - yyerror("Can't locate the specified chain level."); - return(-2); - } - return(-1); -} - -/* - * Consistancy checking routines: - * - * - A dungeon must have a unique name. - * - A dungeon must have a originating "branch" command - * (except, of course, for the first dungeon). - * - A dungeon must have a proper depth (at least (1, 0)). - */ - -int -check_dungeon() -{ - int i; - - for(i = 0; i < n_dgns; i++) - if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { - yyerror("Duplicate dungeon name."); - return(0); - } - - if(n_dgns) - for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { - if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; - - if(i >= n_brs - tmpdungeon[n_dgns].branches) { - yyerror("Dungeon cannot be reached."); - return(0); - } - } - - if(tmpdungeon[n_dgns].lev.base <= 0 || - tmpdungeon[n_dgns].lev.rand < 0) { - yyerror("Invalid dungeon depth specified."); - return(0); - } - return(1); /* OK */ -} - -/* - * - A level must have a unique level name. - * - If chained, the level used as reference for the chain - * must be in this dungeon, must be previously defined, and - * the level chained from must be "non-probabilistic" (ie. - * have a 100% chance of existing). - */ - -int -check_level() -{ - int i; - - if(!in_dungeon) { - yyerror("Level defined outside of dungeon."); - return(0); - } - - for(i = 0; i < n_levs; i++) - if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { - yyerror("Duplicate level name."); - return(0); - } - - if(tmplevel[i].chain == -2) { - yyerror("Invaild level chain reference."); - return(0); - } else if(tmplevel[i].chain != -1) { /* there is a chain */ - /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ - if(tmplevel[tmplevel[i].chain].chance != 100) { - yyerror("Level cannot chain from a probabilistic level."); - return(0); - } else if(tmplevel[i].chain == n_levs) { - yyerror("A level cannot chain to itself!"); - return(0); - } - } - return(1); /* OK */ -} - -/* - * - A branch may not branch backwards - to avoid branch loops. - * - A branch name must be unique. - * (ie. You can only have one entry point to each dungeon). - * - If chained, the level used as reference for the chain - * must be in this dungeon, must be previously defined, and - * the level chained from must be "non-probabilistic" (ie. - * have a 100% chance of existing). - */ - -int -check_branch() -{ - int i; - - if(!in_dungeon) { - yyerror("Branch defined outside of dungeon."); - return(0); - } - - for(i = 0; i < n_dgns; i++) - if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { - - yyerror("Reverse branching not allowed."); - return(0); - } - - if(tmpbranch[i].chain == -2) { - - yyerror("Invaild branch chain reference."); - return(0); - } else if(tmpbranch[i].chain != -1) { /* it is chained */ - - if(tmplevel[tmpbranch[i].chain].chance != 100) { - yyerror("Branch cannot chain from a probabilistic level."); - return(0); - } - } - return(1); /* OK */ -} - -/* - * Output the dungon definition into a file. - * - * The file will have the following format: - * - * [ nethack version ID ] - * [ number of dungeons ] - * [ first dungeon struct ] - * [ levels for the first dungeon ] - * ... - * [ branches for the first dungeon ] - * ... - * [ second dungeon struct ] - * ... - */ - -void -output_dgn() -{ - int nd, cl = 0, nl = 0, - cb = 0, nb = 0; - static struct version_info version_data = { - VERSION_NUMBER, VERSION_FEATURES, - VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 - }; - - if(++n_dgns <= 0) { - yyerror("FATAL - no dungeons were defined."); - exit(EXIT_FAILURE); - } - - if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { - yyerror("FATAL - output failure."); - exit(EXIT_FAILURE); - } - - (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); - for (nd = 0; nd < n_dgns; nd++) { - (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), - 1, yyout); - - nl += tmpdungeon[nd].levels; - for(; cl < nl; cl++) - (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), - 1, yyout); - - nb += tmpdungeon[nd].branches; - for(; cb < nb; cb++) - (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), - 1, yyout); - } - /* apparently necessary for Think C 5.x, otherwise harmless */ - (void) fflush(yyout); -} - -/*dgn_comp.y*/ diff --git a/util/dgn_main.c b/util/dgn_main.c deleted file mode 100644 index e3e5e5939..000000000 --- a/util/dgn_main.c +++ /dev/null @@ -1,193 +0,0 @@ -/* NetHack 3.6 dgn_main.c $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* Copyright (c) 1990 by M. Stephenson */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * This file contains the main function for the parser - * and some useful functions needed by yacc - */ - -#include "config.h" -#include "dlb.h" - -/* Macintosh-specific code */ -#if defined(__APPLE__) && defined(__MACH__) -/* MacOS X has Unix-style files and processes */ -#undef MAC -#endif -#ifdef MAC -#if defined(__SC__) || defined(__MRC__) -#define MPWTOOL -#include -#else -/* put dungeon file in library location */ -#define PREFIX ":lib:" -#endif -#endif - -#ifndef MPWTOOL -#define SpinCursor(x) -#endif - -#define MAX_ERRORS 25 - -extern int NDECL(yyparse); -extern int nh_line_number; -const char *fname = "(stdin)"; -int fatal_error = 0; - -int FDECL(main, (int, char **)); -void FDECL(yyerror, (const char *)); -void FDECL(yywarning, (const char *)); -int NDECL(yywrap); -void FDECL(init_yyin, (FILE *)); -void FDECL(init_yyout, (FILE *)); - -#ifdef AZTEC_36 -FILE *FDECL(freopen, (char *, char *, FILE *)); -#endif -#define Fprintf (void) fprintf - -#if defined(__BORLANDC__) && !defined(_WIN32) -extern unsigned _stklen = STKSIZ; -#endif -int -main(argc, argv) -int argc; -char **argv; -{ - char infile[64], outfile[64], basename[64]; - FILE *fin, *fout; - int i, len; - boolean errors_encountered = FALSE; -#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) - char *mark; - static char *mac_argv[] = { "dgn_comp", /* dummy argv[0] */ - ":dat:dungeon.pdf" }; - - argc = SIZE(mac_argv); - argv = mac_argv; -#endif - - Strcpy(infile, "(stdin)"); - fin = stdin; - Strcpy(outfile, "(stdout)"); - fout = stdout; - - if (argc == 1) { /* Read standard input */ - init_yyin(fin); - init_yyout(fout); - (void) yyparse(); - if (fatal_error > 0) - errors_encountered = TRUE; - } else { /* Otherwise every argument is a filename */ - for (i = 1; i < argc; i++) { - fname = strcpy(infile, argv[i]); - /* the input file had better be a .pdf file */ - len = strlen(fname) - 4; /* length excluding suffix */ - if (len < 0 || strncmp(".pdf", fname + len, 4)) { - Fprintf(stderr, "Error - file name \"%s\" in wrong format.\n", - fname); - errors_encountered = TRUE; - continue; - } - -/* build output file name */ -#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) - /* extract basename from path to infile */ - mark = strrchr(infile, ':'); - strcpy(basename, mark ? mark + 1 : infile); - mark = strchr(basename, '.'); - if (mark) - *mark = '\0'; -#else -/* Use the whole name - strip off the last 3 or 4 chars. */ - -#ifdef VMS /* avoid possible interaction with logical name */ - len++; /* retain "." as trailing punctuation */ -#endif - (void) strncpy(basename, infile, len); - basename[len] = '\0'; -#endif - - outfile[0] = '\0'; -#ifdef PREFIX - (void) strcat(outfile, PREFIX); -#endif - (void) strcat(outfile, basename); - - fin = freopen(infile, "r", stdin); - if (!fin) { - Fprintf(stderr, "Can't open %s for input.\n", infile); - perror(infile); - errors_encountered = TRUE; - continue; - } - fout = freopen(outfile, WRBMODE, stdout); - if (!fout) { - Fprintf(stderr, "Can't open %s for output.\n", outfile); - perror(outfile); - errors_encountered = TRUE; - continue; - } - init_yyin(fin); - init_yyout(fout); - (void) yyparse(); - nh_line_number = 1; - if (fatal_error > 0) { - errors_encountered = TRUE; - fatal_error = 0; - } - } - } - if (fout && fclose(fout) < 0) { - Fprintf(stderr, "Can't finish output file."); - perror(outfile); - errors_encountered = TRUE; - } - exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); - /*NOTREACHED*/ - return 0; -} - -/* - * Each time the parser detects an error, it uses this function. - * Here we take count of the errors. To continue farther than - * MAX_ERRORS wouldn't be reasonable. - */ - -void -yyerror(s) -const char *s; -{ - (void) fprintf(stderr, "%s : line %d : %s\n", fname, nh_line_number, s); - if (++fatal_error > MAX_ERRORS) { - (void) fprintf(stderr, "Too many errors, good bye!\n"); - exit(EXIT_FAILURE); - } -} - -/* - * Just display a warning (that is : a non fatal error) - */ - -void -yywarning(s) -const char *s; -{ - (void) fprintf(stderr, "%s : line %d : WARNING : %s\n", fname, - nh_line_number, s); -} - -int -yywrap() -{ - SpinCursor(3); /* Don't know if this is a good place to put it ? - Is it called for our grammar ? - Often enough ? - Too often ? -- h+ */ - return 1; -} - -/*dgn_main.c*/ diff --git a/util/lev_comp.l b/util/lev_comp.l deleted file mode 100644 index 8866e3f6f..000000000 --- a/util/lev_comp.l +++ /dev/null @@ -1,437 +0,0 @@ -%{ -/* NetHack 3.6 lev_comp.l $NHDT-Date: 1543371690 2018/11/28 02:21:30 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.25 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* NetHack may be freely redistributed. See license for details. */ - -#define LEV_LEX_C - -#include "hack.h" -#include "lev_comp.h" -#include "sp_lev.h" - -/* Most of these don't exist in flex, yywrap is macro and - * yyunput is properly declared in flex.skel. - */ -#if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) -int FDECL(yyback, (int *,int)); -int NDECL(yylook); -int NDECL(yyinput); -int NDECL(yywrap); -int NDECL(yylex); - /* Traditional lexes let yyunput() and yyoutput() default to int; - * newer ones may declare them as void since they don't return - * values. For even more fun, the lex supplied as part of the - * newer unbundled compiler for SunOS 4.x adds the void declarations - * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain - * int) while the bundled lex and the one with the older unbundled - * compiler do not. To detect this, we need help from outside -- - * sys/unix/Makefile.utl. - * - * Digital UNIX is difficult and still has int in spite of all - * other signs. - */ -# if defined(NeXT) || defined(SVR4) || defined(_AIX32) -# define VOIDYYPUT -# endif -# if !defined(VOIDYYPUT) && defined(POSIX_TYPES) -# if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) -# define VOIDYYPUT -# endif -# endif -# if !defined(VOIDYYPUT) && defined(WEIRD_LEX) -# if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) -# define VOIDYYPUT -# endif -# endif -# if defined(VOIDYYPUT) && defined(__osf__) -# undef VOIDYYPUT -# endif -# ifdef VOIDYYPUT -void FDECL(yyunput, (int)); -void FDECL(yyoutput, (int)); -# else -int FDECL(yyunput, (int)); -int FDECL(yyoutput, (int)); -# endif - -#else /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ -/* most recent flex allows suppressing yyunput() altogether when not needed */ -#define YY_NO_UNPUT -#define YY_NO_INPUT -#endif - -#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) -/* older flex wants this */ -#define YY_MALLOC_DECL genericptr_t FDECL(malloc, (size_t)); \ - genericptr_t FDECL(realloc, (genericptr_t, size_t)); -/* newer flex assumes so needs this in case it's been suppressed */ -YY_MALLOC_DECL -#endif - -void FDECL(init_yyin, (FILE *)); -void FDECL(init_yyout, (FILE *)); - -long NDECL(handle_varstring_check); -long FDECL(corefunc_str_check, (char *, long)); - -extern void VDECL(lc_error, (const char *, ...)); -extern struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int)); - -extern struct lc_vardefs *vardefs; - -extern long FDECL(method_defined, (char *, long, long *)); - -void FDECL(savetoken, (char *)); -void NDECL(newline); -void FDECL(advancepos, (char *)); - -/* - * This doesn't always get put in lev_comp.h - * (esp. when using older versions of bison). - */ -extern YYSTYPE yylval; - -int nh_line_number = 1; -int token_start_pos = 0; -char curr_token[512]; -static char map[4096]; -static int map_cnt = 0; - -FILE *orig_yyin = NULL; - -#define ST_RET(x) do { savetoken(yytext); return x; } while (0); -#define ST_RETF(y, x) do { savetoken(yytext); y; return x; } while (0); - -%} -%e 2500 -%p 10000 -%n 1500 -%s MAPC -%% -ENDMAP { - savetoken(yytext); - BEGIN(INITIAL); - yylval.map = (char *) alloc(map_cnt + 1); - (void) strncpy(yylval.map, map, map_cnt); - yylval.map[map_cnt] = 0; - map_cnt = 0; - return MAP_ID; - } -[-|}{+xABCISHKPLWTF\\#. 0123456789]*\r?\n { - int len = yyleng; - savetoken(yytext); - /* convert \r\n to \n */ - if (len >= 2 && yytext[len - 2] == '\r') - len -= 1; - (void) strncpy(map + map_cnt, yytext, len); - map_cnt += len; - map[map_cnt - 1] = '\n'; - map[map_cnt] = '\0'; - newline(); - } -^[ \t]*#.*\n { savetoken(yytext); newline(); } -MESSAGE ST_RET(MESSAGE_ID); -NOMAP ST_RET(NOMAP_ID); -MAZE ST_RET(MAZE_ID); -LEVEL ST_RET(LEVEL_ID); -INIT_MAP ST_RET(LEV_INIT_ID); -mazegrid ST_RET(MAZE_GRID_ID); -solidfill ST_RET(SOLID_FILL_ID); -mines ST_RET(MINES_ID); -rogue ST_RET(ROGUELEV_ID); -FLAGS ST_RET(FLAGS_ID); -GEOMETRY ST_RET(GEOMETRY_ID); -^MAP\r?\n { savetoken(yytext); BEGIN(MAPC); newline(); } -obj(ect)? ST_RET(object_ID); -OBJECT ST_RET(OBJECT_ID); -CONTAINER ST_RET(COBJECT_ID); -MONSTER ST_RET(MONSTER_ID); -monster ST_RET(monster_ID); -TRAP ST_RET(TRAP_ID); -DOOR ST_RET(DOOR_ID); -ROOMDOOR ST_RET(ROOMDOOR_ID); -DRAWBRIDGE ST_RET(DRAWBRIDGE_ID); -MAZEWALK ST_RET(MAZEWALK_ID); -WALLIFY ST_RET(WALLIFY_ID); -REGION ST_RET(REGION_ID); -ALTAR ST_RET(ALTAR_ID); -LADDER ST_RET(LADDER_ID); -STAIR ST_RET(STAIR_ID); -PORTAL ST_RET(PORTAL_ID); -TELEPORT_REGION ST_RET(TELEPRT_ID); -BRANCH ST_RET(BRANCH_ID); -FOUNTAIN ST_RET(FOUNTAIN_ID); -SINK ST_RET(SINK_ID); -POOL ST_RET(POOL_ID); -NON_DIGGABLE ST_RET(NON_DIGGABLE_ID); -NON_PASSWALL ST_RET(NON_PASSWALL_ID); -IF ST_RET(IF_ID); -ELSE ST_RET(ELSE_ID); -EXIT ST_RET(EXIT_ID); -ROOM ST_RET(ROOM_ID); -SUBROOM ST_RET(SUBROOM_ID); -RANDOM_CORRIDORS ST_RET(RAND_CORRIDOR_ID); -CORRIDOR ST_RET(CORRIDOR_ID); -TERRAIN ST_RET(TERRAIN_ID); -terrain ST_RET(terrain_ID); -REPLACE_TERRAIN ST_RET(REPLACE_TERRAIN_ID); -GOLD ST_RET(GOLD_ID); -GRAVE ST_RET(GRAVE_ID); -ENGRAVING ST_RET(ENGRAVING_ID); -MINERALIZE ST_RET(MINERALIZE_ID); -(NAME|name) ST_RET(NAME_ID); -FOR ST_RET(FOR_ID); -TO ST_RET(TO_ID); -LOOP ST_RET(LOOP_ID); -SWITCH ST_RET(SWITCH_ID); -CASE ST_RET(CASE_ID); -BREAK ST_RET(BREAK_ID); -DEFAULT ST_RET(DEFAULT_ID); -FUNCTION ST_RET(FUNCTION_ID); -SHUFFLE ST_RET(SHUFFLE_ID); -montype ST_RET(MONTYPE_ID); -selection ST_RET(selection_ID); -rect ST_RET(rect_ID); -fillrect ST_RET(fillrect_ID); -line ST_RET(line_ID); -randline ST_RET(randline_ID); -grow ST_RET(grow_ID); -floodfill ST_RET(flood_ID); -rndcoord ST_RET(rndcoord_ID); -circle ST_RET(circle_ID); -ellipse ST_RET(ellipse_ID); -filter ST_RET(filter_ID); -gradient ST_RET(gradient_ID); -complement ST_RET(complement_ID); -radial { savetoken(yytext); yylval.i=SEL_GRADIENT_RADIAL; return GRADIENT_TYPE; } -square { savetoken(yytext); yylval.i=SEL_GRADIENT_SQUARE; return GRADIENT_TYPE; } -dry { savetoken(yytext); yylval.i=DRY; return HUMIDITY_TYPE; } -wet { savetoken(yytext); yylval.i=WET; return HUMIDITY_TYPE; } -hot { savetoken(yytext); yylval.i=HOT; return HUMIDITY_TYPE; } -solid { savetoken(yytext); yylval.i=SOLID; return HUMIDITY_TYPE; } -any { savetoken(yytext); yylval.i=ANY_LOC; return HUMIDITY_TYPE; } -levregion ST_RET(LEV); -quantity ST_RET(QUANTITY_ID); -buried ST_RET(BURIED_ID); -eroded ST_RET(ERODED_ID); -erodeproof ST_RET(ERODEPROOF_ID); -trapped { savetoken(yytext); yylval.i=1; return TRAPPED_STATE; } -not_trapped { savetoken(yytext); yylval.i=0; return TRAPPED_STATE; } -recharged ST_RET(RECHARGED_ID); -invisible ST_RET(INVIS_ID); -greased ST_RET(GREASED_ID); -female ST_RET(FEMALE_ID); -cancelled ST_RET(CANCELLED_ID); -revived ST_RET(REVIVED_ID); -avenge ST_RET(AVENGE_ID); -fleeing ST_RET(FLEEING_ID); -blinded ST_RET(BLINDED_ID); -paralyzed ST_RET(PARALYZED_ID); -stunned ST_RET(STUNNED_ID); -confused ST_RET(CONFUSED_ID); -seen_traps ST_RET(SEENTRAPS_ID); -all ST_RET(ALL_ID); -horizontal ST_RETF((yylval.i=1), HORIZ_OR_VERT); -vertical { savetoken(yytext); yylval.i=2; return HORIZ_OR_VERT; } -open { savetoken(yytext); yylval.i=D_ISOPEN; return DOOR_STATE; } -closed { savetoken(yytext); yylval.i=D_CLOSED; return DOOR_STATE; } -locked { savetoken(yytext); yylval.i=D_LOCKED; return DOOR_STATE; } -nodoor { savetoken(yytext); yylval.i=D_NODOOR; return DOOR_STATE; } -broken { savetoken(yytext); yylval.i=D_BROKEN; return DOOR_STATE; } -secret { savetoken(yytext); yylval.i=D_SECRET; return DOOR_STATE; } -north { savetoken(yytext); yylval.i=W_NORTH; return DIRECTION; } -east { savetoken(yytext); yylval.i=W_EAST; return DIRECTION; } -south { savetoken(yytext); yylval.i=W_SOUTH; return DIRECTION; } -west { savetoken(yytext); yylval.i=W_WEST; return DIRECTION; } -random { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE; } -random\[ { savetoken(yytext); yylval.i = -1; return RANDOM_TYPE_BRACKET; } -none { savetoken(yytext); yylval.i = -2; return NONE; } -align ST_RET(A_REGISTER); -left { savetoken(yytext); yylval.i=1; return LEFT_OR_RIGHT; } -half-left { savetoken(yytext); yylval.i=2; return LEFT_OR_RIGHT; } -center { savetoken(yytext); yylval.i=3; return CENTER; } -half-right { savetoken(yytext); yylval.i=4; return LEFT_OR_RIGHT; } -right { savetoken(yytext); yylval.i=5; return LEFT_OR_RIGHT; } -top { savetoken(yytext); yylval.i=1; return TOP_OR_BOT; } -bottom { savetoken(yytext); yylval.i=5; return TOP_OR_BOT; } -lit { savetoken(yytext); yylval.i=1; return LIGHT_STATE; } -unlit { savetoken(yytext); yylval.i=0; return LIGHT_STATE; } -filled { savetoken(yytext); yylval.i=1; return FILLING; } -unfilled { savetoken(yytext); yylval.i=0; return FILLING; } -regular { savetoken(yytext); yylval.i=0; return IRREGULAR; } -irregular { savetoken(yytext); yylval.i=1; return IRREGULAR; } -unjoined { savetoken(yytext); yylval.i=1; return JOINED; } -joined { savetoken(yytext); yylval.i=0; return JOINED; } -limited { savetoken(yytext); yylval.i=1; return LIMITED; } -unlimited { savetoken(yytext); yylval.i=0; return LIMITED; } -noalign { savetoken(yytext); yylval.i= AM_NONE; return ALIGNMENT; } -law { savetoken(yytext); yylval.i= AM_LAWFUL; return ALIGNMENT; } -neutral { savetoken(yytext); yylval.i= AM_NEUTRAL; return ALIGNMENT; } -chaos { savetoken(yytext); yylval.i= AM_CHAOTIC; return ALIGNMENT; } -coaligned { savetoken(yytext); yylval.i= AM_SPLEV_CO; return ALIGNMENT; } -noncoaligned { savetoken(yytext); yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; } -peaceful { savetoken(yytext); yylval.i=1; return MON_ATTITUDE; } -hostile { savetoken(yytext); yylval.i=0; return MON_ATTITUDE; } -asleep { savetoken(yytext); yylval.i=1; return MON_ALERTNESS; } -awake { savetoken(yytext); yylval.i=0; return MON_ALERTNESS; } -m_feature { savetoken(yytext); yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; } -m_monster { savetoken(yytext); yylval.i= M_AP_MONSTER; return MON_APPEARANCE; } -m_object { savetoken(yytext); yylval.i= M_AP_OBJECT; return MON_APPEARANCE; } -sanctum { savetoken(yytext); yylval.i=2; return ALTAR_TYPE; } -shrine { savetoken(yytext); yylval.i=1; return ALTAR_TYPE; } -altar { savetoken(yytext); yylval.i=0; return ALTAR_TYPE; } -up { savetoken(yytext); yylval.i=1; return UP_OR_DOWN; } -down { savetoken(yytext); yylval.i=0; return UP_OR_DOWN; } -false { savetoken(yytext); yylval.i=0; return BOOLEAN; } -true { savetoken(yytext); yylval.i=1; return BOOLEAN; } -dust { savetoken(yytext); yylval.i=DUST; return ENGRAVING_TYPE; } -engrave { savetoken(yytext); yylval.i=ENGRAVE; return ENGRAVING_TYPE; } -burn { savetoken(yytext); yylval.i=BURN; return ENGRAVING_TYPE; } -mark { savetoken(yytext); yylval.i=MARK; return ENGRAVING_TYPE; } -blood { savetoken(yytext); yylval.i=ENGR_BLOOD; return ENGRAVING_TYPE; } -blessed { savetoken(yytext); yylval.i=1; return CURSE_TYPE; } -uncursed { savetoken(yytext); yylval.i=2; return CURSE_TYPE; } -cursed { savetoken(yytext); yylval.i=3; return CURSE_TYPE; } -noteleport { savetoken(yytext); yylval.i=NOTELEPORT; return FLAG_TYPE; } -hardfloor { savetoken(yytext); yylval.i=HARDFLOOR; return FLAG_TYPE; } -nommap { savetoken(yytext); yylval.i=NOMMAP; return FLAG_TYPE; } -arboreal { savetoken(yytext); yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ -shortsighted { savetoken(yytext); yylval.i=SHORTSIGHTED; return FLAG_TYPE; } -mazelevel { savetoken(yytext); yylval.i=MAZELEVEL; return FLAG_TYPE; } -premapped { savetoken(yytext); yylval.i=PREMAPPED; return FLAG_TYPE; } -shroud { savetoken(yytext); yylval.i=SHROUD; return FLAG_TYPE; } -graveyard { savetoken(yytext); yylval.i=GRAVEYARD; return FLAG_TYPE; } -icedpools { savetoken(yytext); yylval.i=ICEDPOOLS; return FLAG_TYPE; } -solidify { savetoken(yytext); yylval.i=SOLIDIFY; return FLAG_TYPE; } -corrmaze { savetoken(yytext); yylval.i=CORRMAZE; return FLAG_TYPE; } -inaccessibles { savetoken(yytext); yylval.i=CHECK_INACCESSIBLES; return FLAG_TYPE; } -[0-9]+d[0-9]+ { char *p = index(yytext, 'd'); - savetoken(yytext); - if (p) { - *p++ = '\0'; - yylval.dice.num = atoi(yytext); - yylval.dice.die = atoi(p); - } else { - yylval.dice.num = yylval.dice.die = 1; - } - return DICE; - } -\[\ *[0-9]+\%\ *\] { savetoken(yytext); yylval.i = atoi(yytext + 1); - if (yylval.i < 0 || yylval.i > 100) - lc_error("Unexpected percentile '%li%%'", yylval.i); - return PERCENT; } --[0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return MINUS_INTEGER; } -\+[0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return PLUS_INTEGER; } -[0-9]+\% { savetoken(yytext); yylval.i = atoi(yytext); - if (yylval.i < 0 || yylval.i > 100) - lc_error("Unexpected percentile '%li%%'", yylval.i); - return SPERCENT; } -[0-9]+ { savetoken(yytext); yylval.i=atoi(yytext); return INTEGER; } -\"[^"]*\" { savetoken(yytext); - yytext[yyleng - 1] = '\0'; /* discard the trailing \" */ - yylval.map = dupstr(yytext + 1); /* skip the first \" */ - return STRING; } -\$[a-zA-Z_]+ { savetoken(yytext); return handle_varstring_check(); } -"==" { savetoken(yytext); yylval.i = SPO_JE; return COMPARE_TYPE; } -"!=" { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } -"<>" { savetoken(yytext); yylval.i = SPO_JNE; return COMPARE_TYPE; } -"<=" { savetoken(yytext); yylval.i = SPO_JLE; return COMPARE_TYPE; } -">=" { savetoken(yytext); yylval.i = SPO_JGE; return COMPARE_TYPE; } -"<" { savetoken(yytext); yylval.i = SPO_JL; return COMPARE_TYPE; } -">" { savetoken(yytext); yylval.i = SPO_JG; return COMPARE_TYPE; } -\r?\n { newline(); } -[ \t]+ { advancepos(yytext); } -'\\.' { savetoken(yytext); yylval.i = yytext[2]; return CHAR; } -'.' { savetoken(yytext); yylval.i = yytext[1]; return CHAR; } -[-_a-zA-Z0-9]+ ST_RET(UNKNOWN_TYPE); -. { savetoken(yytext); return yytext[0]; } -%% -#ifdef AMIGA -long * -alloc(n) - unsigned n; -{ - return (long *) malloc(n); -} -#endif - -/* routine to switch to another input file; needed for flex */ -void -init_yyin( input_f ) -FILE *input_f; -{ -#if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) - if (yyin) - yyrestart(input_f); - else -#endif - yyin = input_f; - - if (!orig_yyin) - orig_yyin = yyin; -} -/* analogous routine (for completeness) */ -void -init_yyout( output_f ) -FILE *output_f; -{ - yyout = output_f; -} - -long -handle_varstring_check() -{ - struct lc_vardefs *vd; - - yylval.map = dupstr(yytext); - if ((vd = vardef_defined(vardefs, yytext, 1)) != 0) { - long l = vd->var_type; - int a = ((l & SPOVAR_ARRAY) == SPOVAR_ARRAY); - - l &= ~SPOVAR_ARRAY; - if (l == SPOVAR_INT) - return (a ? VARSTRING_INT_ARRAY : VARSTRING_INT); - if (l == SPOVAR_STRING) - return (a ? VARSTRING_STRING_ARRAY : VARSTRING_STRING); - if (l == SPOVAR_VARIABLE) - return (a ? VARSTRING_VAR_ARRAY : VARSTRING_VAR); - if (l == SPOVAR_COORD) - return (a ? VARSTRING_COORD_ARRAY : VARSTRING_COORD); - if (l == SPOVAR_REGION) - return (a ? VARSTRING_REGION_ARRAY : VARSTRING_REGION); - if (l == SPOVAR_MAPCHAR) - return (a ? VARSTRING_MAPCHAR_ARRAY : VARSTRING_MAPCHAR); - if (l == SPOVAR_MONST) - return (a ? VARSTRING_MONST_ARRAY : VARSTRING_MONST); - if (l == SPOVAR_OBJ) - return (a ? VARSTRING_OBJ_ARRAY : VARSTRING_OBJ); - if (l == SPOVAR_SEL) - return (a ? VARSTRING_SEL_ARRAY : VARSTRING_SEL); - } - return VARSTRING; -} - -void -newline() -{ - nh_line_number++; - token_start_pos = 0; - (void) memset((genericptr_t) curr_token, 0, 512); -} - -void -savetoken(s) -char *s; -{ - Sprintf(curr_token, "%s", s); - advancepos(s); -} - -void -advancepos(s) -char *s; -{ - token_start_pos += strlen(s); -} - -/*lev_comp.l*/ diff --git a/util/lev_comp.y b/util/lev_comp.y deleted file mode 100644 index 1b1c93056..000000000 --- a/util/lev_comp.y +++ /dev/null @@ -1,2721 +0,0 @@ -%{ -/* NetHack 3.6 lev_comp.y $NHDT-Date: 1543371691 2018/11/28 02:21:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.22 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * This file contains the Level Compiler code - * It may handle special mazes & special room-levels - */ - -/* In case we're using bison in AIX. This definition must be - * placed before any other C-language construct in the file - * excluding comments and preprocessor directives (thanks IBM - * for this wonderful feature...). - * - * Note: some cpps barf on this 'undefined control' (#pragma). - * Addition of the leading space seems to prevent barfage for now, - * and AIX will still see the directive. - */ -#ifdef _AIX - #pragma alloca /* keep leading space! */ -#endif - -#define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) */ -#include "hack.h" -#include "sp_lev.h" - -#define ERR (-1) -/* many types of things are put in chars for transference to NetHack. - * since some systems will use signed chars, limit everybody to the - * same number for portability. - */ -#define MAX_OF_TYPE 128 - -#define MAX_NESTED_IFS 20 -#define MAX_SWITCH_CASES 20 - -#define New(type) \ - (type *) memset((genericptr_t) alloc(sizeof (type)), 0, sizeof (type)) -#define NewTab(type, size) (type **) alloc(sizeof (type *) * size) -#define Free(ptr) free((genericptr_t) ptr) - -extern void VDECL(lc_error, (const char *, ...)); -extern void VDECL(lc_warning, (const char *, ...)); -extern void FDECL(yyerror, (const char *)); -extern void FDECL(yywarning, (const char *)); -extern int NDECL(yylex); -int NDECL(yyparse); - -extern int FDECL(get_floor_type, (CHAR_P)); -extern int FDECL(get_room_type, (char *)); -extern int FDECL(get_trap_type, (char *)); -extern int FDECL(get_monster_id, (char *,CHAR_P)); -extern int FDECL(get_object_id, (char *,CHAR_P)); -extern boolean FDECL(check_monster_char, (CHAR_P)); -extern boolean FDECL(check_object_char, (CHAR_P)); -extern char FDECL(what_map_char, (CHAR_P)); -extern void FDECL(scan_map, (char *, sp_lev *)); -extern void FDECL(add_opcode, (sp_lev *, int, genericptr_t)); -extern genericptr_t FDECL(get_last_opcode_data1, (sp_lev *, int)); -extern genericptr_t FDECL(get_last_opcode_data2, (sp_lev *, int, int)); -extern boolean FDECL(check_subrooms, (sp_lev *)); -extern boolean FDECL(write_level_file, (char *,sp_lev *)); -extern struct opvar *FDECL(set_opvar_int, (struct opvar *, long)); -extern void VDECL(add_opvars, (sp_lev *, const char *, ...)); -extern void FDECL(start_level_def, (sp_lev * *, char *)); - -extern struct lc_funcdefs *FDECL(funcdef_new, (long,char *)); -extern void FDECL(funcdef_free_all, (struct lc_funcdefs *)); -extern struct lc_funcdefs *FDECL(funcdef_defined, (struct lc_funcdefs *, - char *, int)); -extern char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *)); -extern char *FDECL(decode_parm_str, (char *)); - -extern struct lc_vardefs *FDECL(vardef_new, (long,char *)); -extern void FDECL(vardef_free_all, (struct lc_vardefs *)); -extern struct lc_vardefs *FDECL(vardef_defined, (struct lc_vardefs *, - char *, int)); - -extern void NDECL(break_stmt_start); -extern void FDECL(break_stmt_end, (sp_lev *)); -extern void FDECL(break_stmt_new, (sp_lev *, long)); - -extern void FDECL(splev_add_from, (sp_lev *, sp_lev *)); - -extern void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long)); -extern void FDECL(vardef_used, (struct lc_vardefs *, char *)); -extern struct lc_vardefs *FDECL(add_vardef_type, (struct lc_vardefs *, - char *, long)); - -extern int FDECL(reverse_jmp_opcode, (int)); - -struct coord { - long x; - long y; -}; - -struct forloopdef { - char *varname; - long jmp_point; -}; -static struct forloopdef forloop_list[MAX_NESTED_IFS]; -static short n_forloops = 0; - - -sp_lev *splev = NULL; - -static struct opvar *if_list[MAX_NESTED_IFS]; - -static short n_if_list = 0; - -unsigned int max_x_map, max_y_map; -int obj_containment = 0; - -int in_container_obj = 0; - -/* integer value is possibly an inconstant value (eg. dice notation - or a variable) */ -int is_inconstant_number = 0; - -int in_switch_statement = 0; -static struct opvar *switch_check_jump = NULL; -static struct opvar *switch_default_case = NULL; -static struct opvar *switch_case_list[MAX_SWITCH_CASES]; -static long switch_case_value[MAX_SWITCH_CASES]; -int n_switch_case_list = 0; - -int allow_break_statements = 0; -struct lc_breakdef *break_list = NULL; - -extern struct lc_vardefs *vardefs; /* variable definitions */ - - -struct lc_vardefs *function_tmp_var_defs = NULL; -extern struct lc_funcdefs *function_definitions; -struct lc_funcdefs *curr_function = NULL; -struct lc_funcdefs_parm * curr_function_param = NULL; -int in_function_definition = 0; -sp_lev *function_splev_backup = NULL; - -extern int fatal_error; -extern int got_errors; -extern int line_number; -extern const char *fname; - -extern char curr_token[512]; - -%} - -%union -{ - long i; - char *map; - struct { - long room; - long wall; - long door; - } corpos; - struct { - long area; - long x1; - long y1; - long x2; - long y2; - } lregn; - struct { - long x; - long y; - } crd; - struct { - long ter; - long lit; - } terr; - struct { - long height; - long width; - } sze; - struct { - long die; - long num; - } dice; - struct { - long cfunc; - char *varstr; - } meth; -} - - -%token CHAR INTEGER BOOLEAN PERCENT SPERCENT -%token MINUS_INTEGER PLUS_INTEGER -%token MAZE_GRID_ID SOLID_FILL_ID MINES_ID ROGUELEV_ID -%token MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID -%token OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID -%token object_ID monster_ID terrain_ID -%token MAZEWALK_ID WALLIFY_ID REGION_ID FILLING IRREGULAR JOINED -%token ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID -%token PORTAL_ID TELEPRT_ID BRANCH_ID LEV MINERALIZE_ID -%token CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE -%token RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE -%token DIRECTION RANDOM_TYPE RANDOM_TYPE_BRACKET A_REGISTER -%token ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN -%token SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS -%token MON_APPEARANCE ROOMDOOR_ID IF_ID ELSE_ID -%token TERRAIN_ID HORIZ_OR_VERT REPLACE_TERRAIN_ID -%token EXIT_ID SHUFFLE_ID -%token QUANTITY_ID BURIED_ID LOOP_ID -%token FOR_ID TO_ID -%token SWITCH_ID CASE_ID BREAK_ID DEFAULT_ID -%token ERODED_ID TRAPPED_STATE RECHARGED_ID INVIS_ID GREASED_ID -%token FEMALE_ID CANCELLED_ID REVIVED_ID AVENGE_ID FLEEING_ID BLINDED_ID -%token PARALYZED_ID STUNNED_ID CONFUSED_ID SEENTRAPS_ID ALL_ID -%token MONTYPE_ID -%token GRAVE_ID ERODEPROOF_ID -%token FUNCTION_ID -%token MSG_OUTPUT_TYPE -%token COMPARE_TYPE -%token UNKNOWN_TYPE -%token rect_ID fillrect_ID line_ID randline_ID grow_ID -%token selection_ID flood_ID -%token rndcoord_ID circle_ID ellipse_ID filter_ID complement_ID -%token gradient_ID GRADIENT_TYPE LIMITED HUMIDITY_TYPE -%token ',' ':' '(' ')' '[' ']' '{' '}' -%token STRING MAP_ID -%token NQSTRING VARSTRING -%token CFUNC CFUNC_INT CFUNC_STR CFUNC_COORD CFUNC_REGION -%token VARSTRING_INT VARSTRING_INT_ARRAY -%token VARSTRING_STRING VARSTRING_STRING_ARRAY -%token VARSTRING_VAR VARSTRING_VAR_ARRAY -%token VARSTRING_COORD VARSTRING_COORD_ARRAY -%token VARSTRING_REGION VARSTRING_REGION_ARRAY -%token VARSTRING_MAPCHAR VARSTRING_MAPCHAR_ARRAY -%token VARSTRING_MONST VARSTRING_MONST_ARRAY -%token VARSTRING_OBJ VARSTRING_OBJ_ARRAY -%token VARSTRING_SEL VARSTRING_SEL_ARRAY -%token METHOD_INT METHOD_INT_ARRAY -%token METHOD_STRING METHOD_STRING_ARRAY -%token METHOD_VAR METHOD_VAR_ARRAY -%token METHOD_COORD METHOD_COORD_ARRAY -%token METHOD_REGION METHOD_REGION_ARRAY -%token METHOD_MAPCHAR METHOD_MAPCHAR_ARRAY -%token METHOD_MONST METHOD_MONST_ARRAY -%token METHOD_OBJ METHOD_OBJ_ARRAY -%token METHOD_SEL METHOD_SEL_ARRAY -%token DICE -%type h_justif v_justif trap_name room_type door_state light_state -%type alignment altar_type a_register roomfill door_pos -%type alignment_prfx -%type door_wall walled secret -%type dir_list teleprt_detail -%type object_infos object_info monster_infos monster_info -%type levstatements stmt_block region_detail_end -%type engraving_type flag_list roomregionflag roomregionflags -%type optroomregionflags -%type humidity_flags -%type comparestmt encodecoord encoderegion mapchar -%type seen_trap_mask -%type encodemonster encodeobj encodeobj_list -%type integer_list string_list encodecoord_list encoderegion_list -%type mapchar_list encodemonster_list -%type opt_percent opt_fillchar -%type all_integers -%type ter_selection ter_selection_x -%type func_param_type -%type objectid monsterid terrainid -%type opt_coord_or_var opt_limited -%type mazefiller -%type level_def -%type any_var any_var_array any_var_or_arr any_var_or_unk -%type func_call_params_list func_call_param_list -%type func_call_param_part -%type corr_spec -%type region lev_region -%type room_pos subroom_pos room_align -%type room_size -%type terrain_type -%left '+' '-' -%left '*' '/' '%' -%start file - -%% -file : /* nothing */ - | levels - ; - -levels : level - | level levels - ; - -level : level_def flags levstatements - { - if (fatal_error > 0) { - (void) fprintf(stderr, - "%s: %d errors detected for level \"%s\". No output created!\n", - fname, fatal_error, $1); - fatal_error = 0; - got_errors++; - } else if (!got_errors) { - if (!write_level_file($1, splev)) { - lc_error("Can't write output file for '%s'!", - $1); - exit(EXIT_FAILURE); - } - } - Free($1); - Free(splev); - splev = NULL; - vardef_free_all(vardefs); - vardefs = NULL; - } - ; - -level_def : LEVEL_ID ':' STRING - { - start_level_def(&splev, $3); - $$ = $3; - } - | MAZE_ID ':' STRING ',' mazefiller - { - start_level_def(&splev, $3); - if ($5 == -1) { - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_MAZEGRID, HWALL, 0,0, - 0,0,0,0, SPO_INITLEVEL)); - } else { - int bg = (int) what_map_char((char) $5); - - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_SOLIDFILL, bg, 0,0, - 0,0,0,0, SPO_INITLEVEL)); - } - add_opvars(splev, "io", - VA_PASS2(MAZELEVEL, SPO_LEVEL_FLAGS)); - max_x_map = COLNO-1; - max_y_map = ROWNO; - $$ = $3; - } - ; - -mazefiller : RANDOM_TYPE - { - $$ = -1; - } - | CHAR - { - $$ = what_map_char((char) $1); - } - ; - -lev_init : LEV_INIT_ID ':' SOLID_FILL_ID ',' terrain_type - { - int filling = (int) $5.ter; - - if (filling == INVALID_TYPE || filling >= MAX_TYPE) - lc_error("INIT_MAP: Invalid fill char type."); - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_SOLIDFILL, filling, - 0, (int) $5.lit, - 0,0,0,0, SPO_INITLEVEL)); - max_x_map = COLNO-1; - max_y_map = ROWNO; - } - | LEV_INIT_ID ':' MAZE_GRID_ID ',' CHAR - { - int filling = (int) what_map_char((char) $5); - - if (filling == INVALID_TYPE || filling >= MAX_TYPE) - lc_error("INIT_MAP: Invalid fill char type."); - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_MAZEGRID, filling, 0,0, - 0,0,0,0, SPO_INITLEVEL)); - max_x_map = COLNO-1; - max_y_map = ROWNO; - } - | LEV_INIT_ID ':' ROGUELEV_ID - { - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_ROGUE,0,0,0, - 0,0,0,0, SPO_INITLEVEL)); - } - | LEV_INIT_ID ':' MINES_ID ',' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled opt_fillchar - { - int fg = (int) what_map_char((char) $5), - bg = (int) what_map_char((char) $7); - int smoothed = (int) $9, - joined = (int) $11, - lit = (int) $13, - walled = (int) $15, - filling = (int) $16; - - if (fg == INVALID_TYPE || fg >= MAX_TYPE) - lc_error("INIT_MAP: Invalid foreground type."); - if (bg == INVALID_TYPE || bg >= MAX_TYPE) - lc_error("INIT_MAP: Invalid background type."); - if (joined && fg != CORR && fg != ROOM) - lc_error("INIT_MAP: Invalid foreground type for joined map."); - - if (filling == INVALID_TYPE) - lc_error("INIT_MAP: Invalid fill char type."); - - add_opvars(splev, "iiiiiiiio", - VA_PASS9(LVLINIT_MINES, filling, walled, lit, - joined, smoothed, bg, fg, - SPO_INITLEVEL)); - max_x_map = COLNO-1; - max_y_map = ROWNO; - } - ; - -opt_limited : /* nothing */ - { - $$ = 0; - } - | ',' LIMITED - { - $$ = $2; - } - ; - -opt_coord_or_var : /* nothing */ - { - add_opvars(splev, "o", VA_PASS1(SPO_COPY)); - $$ = 0; - } - | ',' coord_or_var - { - $$ = 1; - } - ; - -opt_fillchar : /* nothing */ - { - $$ = -1; - } - | ',' CHAR - { - $$ = what_map_char((char) $2); - } - ; - - -walled : BOOLEAN - | RANDOM_TYPE - ; - -flags : /* nothing */ - { - add_opvars(splev, "io", VA_PASS2(0, SPO_LEVEL_FLAGS)); - } - | FLAGS_ID ':' flag_list - { - add_opvars(splev, "io", - VA_PASS2((int) $3, SPO_LEVEL_FLAGS)); - } - ; - -flag_list : FLAG_TYPE ',' flag_list - { - $$ = ($1 | $3); - } - | FLAG_TYPE - { - $$ = $1; - } - ; - -levstatements : /* nothing */ - { - $$ = 0; - } - | levstatement levstatements - { - $$ = 1 + $2; - } - ; - -stmt_block : '{' levstatements '}' - { - $$ = $2; - } - ; - -levstatement : message - | lev_init - | altar_detail - | grave_detail - | branch_region - | corridor - | variable_define - | shuffle_detail - | diggable_detail - | door_detail - | drawbridge_detail - | engraving_detail - | mineralize - | fountain_detail - | gold_detail - | switchstatement - | forstatement - | loopstatement - | ifstatement - | chancestatement - | exitstatement - | breakstatement - | function_define - | function_call - | ladder_detail - | map_definition - | mazewalk_detail - | monster_detail - | object_detail - | passwall_detail - | pool_detail - | portal_region - | random_corridors - | region_detail - | room_def - | subroom_def - | sink_detail - | terrain_detail - | replace_terrain_detail - | stair_detail - | stair_region - | teleprt_region - | trap_detail - | wallify_detail - ; - -any_var_array : VARSTRING_INT_ARRAY - | VARSTRING_STRING_ARRAY - | VARSTRING_VAR_ARRAY - | VARSTRING_COORD_ARRAY - | VARSTRING_REGION_ARRAY - | VARSTRING_MAPCHAR_ARRAY - | VARSTRING_MONST_ARRAY - | VARSTRING_OBJ_ARRAY - | VARSTRING_SEL_ARRAY - ; - -any_var : VARSTRING_INT - | VARSTRING_STRING - | VARSTRING_VAR - | VARSTRING_COORD - | VARSTRING_REGION - | VARSTRING_MAPCHAR - | VARSTRING_MONST - | VARSTRING_OBJ - | VARSTRING_SEL - ; - -any_var_or_arr : any_var_array - | any_var - | VARSTRING - ; - -any_var_or_unk : VARSTRING - | any_var - ; - -shuffle_detail : SHUFFLE_ID ':' any_var_array - { - struct lc_vardefs *vd; - - if ((vd = vardef_defined(vardefs, $3, 1))) { - if (!(vd->var_type & SPOVAR_ARRAY)) - lc_error("Trying to shuffle non-array variable '%s'", - $3); - } else - lc_error("Trying to shuffle undefined variable '%s'", - $3); - add_opvars(splev, "so", VA_PASS2($3, SPO_SHUFFLE_ARRAY)); - Free($3); - } - ; - -variable_define : any_var_or_arr '=' math_expr_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_INT); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' selection_ID ':' ter_selection - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_SEL); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' string_expr - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_STRING); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' terrainid ':' mapchar_or_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_MAPCHAR); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' monsterid ':' monster_or_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_MONST); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' objectid ':' object_or_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_OBJ); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' coord_or_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_COORD); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' region_or_var - { - vardefs = add_vardef_type(vardefs, $1, SPOVAR_REGION); - add_opvars(splev, "iso", VA_PASS3(0, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' '{' integer_list '}' - { - int n_items = (int) $4; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_INT | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' '{' encodecoord_list '}' - { - int n_items = (int) $4; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_COORD | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' '{' encoderegion_list '}' - { - int n_items = (int) $4; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_REGION | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' terrainid ':' '{' mapchar_list '}' - { - int n_items = (int) $6; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_MAPCHAR | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' monsterid ':' '{' encodemonster_list '}' - { - int n_items = (int) $6; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_MONST | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' objectid ':' '{' encodeobj_list '}' - { - int n_items = (int) $6; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_OBJ | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - | any_var_or_arr '=' '{' string_list '}' - { - int n_items = (int) $4; - - vardefs = add_vardef_type(vardefs, $1, - SPOVAR_STRING | SPOVAR_ARRAY); - add_opvars(splev, "iso", - VA_PASS3(n_items, $1, SPO_VAR_INIT)); - Free($1); - } - ; - -encodeobj_list : encodeobj - { - add_opvars(splev, "O", VA_PASS1($1)); - $$ = 1; - } - | encodeobj_list ',' encodeobj - { - add_opvars(splev, "O", VA_PASS1($3)); - $$ = 1 + $1; - } - ; - -encodemonster_list : encodemonster - { - add_opvars(splev, "M", VA_PASS1($1)); - $$ = 1; - } - | encodemonster_list ',' encodemonster - { - add_opvars(splev, "M", VA_PASS1($3)); - $$ = 1 + $1; - } - ; - -mapchar_list : mapchar - { - add_opvars(splev, "m", VA_PASS1($1)); - $$ = 1; - } - | mapchar_list ',' mapchar - { - add_opvars(splev, "m", VA_PASS1($3)); - $$ = 1 + $1; - } - ; - -encoderegion_list : encoderegion - { - $$ = 1; - } - | encoderegion_list ',' encoderegion - { - $$ = 1 + $1; - } - ; - -encodecoord_list : encodecoord - { - add_opvars(splev, "c", VA_PASS1($1)); - $$ = 1; - } - | encodecoord_list ',' encodecoord - { - add_opvars(splev, "c", VA_PASS1($3)); - $$ = 1 + $1; - } - ; - -integer_list : math_expr_var - { - $$ = 1; - } - | integer_list ',' math_expr_var - { - $$ = 1 + $1; - } - ; - -string_list : string_expr - { - $$ = 1; - } - | string_list ',' string_expr - { - $$ = 1 + $1; - } - ; - -function_define : FUNCTION_ID NQSTRING '(' - { - struct lc_funcdefs *funcdef; - - if (in_function_definition) - lc_error("Recursively defined functions not allowed (function %s).", $2); - - in_function_definition++; - - if (funcdef_defined(function_definitions, $2, 1)) - lc_error("Function '%s' already defined once.", $2); - - funcdef = funcdef_new(-1, $2); - funcdef->next = function_definitions; - function_definitions = funcdef; - function_splev_backup = splev; - splev = &(funcdef->code); - Free($2); - curr_function = funcdef; - function_tmp_var_defs = vardefs; - vardefs = NULL; - } - func_params_list ')' - { - /* nothing */ - } - stmt_block - { - add_opvars(splev, "io", VA_PASS2(0, SPO_RETURN)); - splev = function_splev_backup; - in_function_definition--; - curr_function = NULL; - vardef_free_all(vardefs); - vardefs = function_tmp_var_defs; - } - ; - -function_call : NQSTRING '(' func_call_params_list ')' - { - struct lc_funcdefs *tmpfunc; - - tmpfunc = funcdef_defined(function_definitions, $1, 1); - if (tmpfunc) { - int l; - int nparams = (int) strlen($3); - char *fparamstr = funcdef_paramtypes(tmpfunc); - - if (strcmp($3, fparamstr)) { - char *tmps = strdup(decode_parm_str(fparamstr)); - - lc_error("Function '%s' requires params '%s', got '%s' instead.", - $1, tmps, decode_parm_str($3)); - Free(tmps); - } - Free(fparamstr); - Free($3); - if (!(tmpfunc->n_called)) { - /* we haven't called the function yet, so insert it in the code */ - struct opvar *jmp = New(struct opvar); - - set_opvar_int(jmp, splev->n_opcodes+1); - add_opcode(splev, SPO_PUSH, jmp); - /* we must jump past it first, then CALL it, due to RETURN. */ - add_opcode(splev, SPO_JMP, NULL); - - tmpfunc->addr = splev->n_opcodes; - - { /* init function parameter variables */ - struct lc_funcdefs_parm *tfp = tmpfunc->params; - while (tfp) { - add_opvars(splev, "iso", - VA_PASS3(0, tfp->name, - SPO_VAR_INIT)); - tfp = tfp->next; - } - } - - splev_add_from(splev, &(tmpfunc->code)); - set_opvar_int(jmp, - splev->n_opcodes - jmp->vardata.l); - } - l = (int) (tmpfunc->addr - splev->n_opcodes - 2); - add_opvars(splev, "iio", - VA_PASS3(nparams, l, SPO_CALL)); - tmpfunc->n_called++; - } else { - lc_error("Function '%s' not defined.", $1); - } - Free($1); - } - ; - -exitstatement : EXIT_ID - { - add_opcode(splev, SPO_EXIT, NULL); - } - ; - -opt_percent : /* nothing */ - { - $$ = 100; - } - | PERCENT - { - $$ = $1; - } - ; - -comparestmt : PERCENT - { - /* val > rn2(100) */ - add_opvars(splev, "iio", - VA_PASS3((int) $1, 100, SPO_RN2)); - $$ = SPO_JG; - } - | '[' math_expr_var COMPARE_TYPE math_expr_var ']' - { - $$ = $3; - } - | '[' math_expr_var ']' - { - /* boolean, explicit foo != 0 */ - add_opvars(splev, "i", VA_PASS1(0)); - $$ = SPO_JNE; - } - ; - -switchstatement : SWITCH_ID - { - is_inconstant_number = 0; - } - '[' integer_or_var ']' - { - struct opvar *chkjmp; - - if (in_switch_statement > 0) - lc_error("Cannot nest switch-statements."); - - in_switch_statement++; - - n_switch_case_list = 0; - switch_default_case = NULL; - - if (!is_inconstant_number) - add_opvars(splev, "o", VA_PASS1(SPO_RN2)); - is_inconstant_number = 0; - - chkjmp = New(struct opvar); - set_opvar_int(chkjmp, splev->n_opcodes+1); - switch_check_jump = chkjmp; - add_opcode(splev, SPO_PUSH, chkjmp); - add_opcode(splev, SPO_JMP, NULL); - break_stmt_start(); - } - '{' switchcases '}' - { - struct opvar *endjump = New(struct opvar); - int i; - - set_opvar_int(endjump, splev->n_opcodes+1); - - add_opcode(splev, SPO_PUSH, endjump); - add_opcode(splev, SPO_JMP, NULL); - - set_opvar_int(switch_check_jump, - splev->n_opcodes - switch_check_jump->vardata.l); - - for (i = 0; i < n_switch_case_list; i++) { - add_opvars(splev, "oio", - VA_PASS3(SPO_COPY, - switch_case_value[i], SPO_CMP)); - set_opvar_int(switch_case_list[i], - switch_case_list[i]->vardata.l - splev->n_opcodes-1); - add_opcode(splev, SPO_PUSH, switch_case_list[i]); - add_opcode(splev, SPO_JE, NULL); - } - - if (switch_default_case) { - set_opvar_int(switch_default_case, - switch_default_case->vardata.l - splev->n_opcodes-1); - add_opcode(splev, SPO_PUSH, switch_default_case); - add_opcode(splev, SPO_JMP, NULL); - } - - set_opvar_int(endjump, splev->n_opcodes - endjump->vardata.l); - - break_stmt_end(splev); - - add_opcode(splev, SPO_POP, NULL); /* get rid of the value in stack */ - in_switch_statement--; - - - } - ; - -switchcases : /* nothing */ - | switchcase switchcases - ; - -switchcase : CASE_ID all_integers ':' - { - if (n_switch_case_list < MAX_SWITCH_CASES) { - struct opvar *tmppush = New(struct opvar); - - set_opvar_int(tmppush, splev->n_opcodes); - switch_case_value[n_switch_case_list] = $2; - switch_case_list[n_switch_case_list++] = tmppush; - } else lc_error("Too many cases in a switch."); - } - levstatements - { - } - | DEFAULT_ID ':' - { - struct opvar *tmppush = New(struct opvar); - - if (switch_default_case) - lc_error("Switch default case already used."); - - set_opvar_int(tmppush, splev->n_opcodes); - switch_default_case = tmppush; - } - levstatements - { - } - ; - -breakstatement : BREAK_ID - { - if (!allow_break_statements) - lc_error("Cannot use BREAK outside a statement block."); - else { - break_stmt_new(splev, splev->n_opcodes); - } - } - ; - -for_to_span : '.' '.' - | TO_ID - ; - -forstmt_start : FOR_ID any_var_or_unk '=' math_expr_var for_to_span math_expr_var - { - char buf[256], buf2[256]; - - if (n_forloops >= MAX_NESTED_IFS) { - lc_error("FOR: Too deeply nested loops."); - n_forloops = MAX_NESTED_IFS - 1; - } - - /* first, define a variable for the for-loop end value */ - Sprintf(buf, "%s end", $2); - /* the value of which is already in stack (the 2nd math_expr) */ - add_opvars(splev, "iso", VA_PASS3(0, buf, SPO_VAR_INIT)); - - vardefs = add_vardef_type(vardefs, $2, SPOVAR_INT); - /* define the for-loop variable. value is in stack (1st math_expr) */ - add_opvars(splev, "iso", VA_PASS3(0, $2, SPO_VAR_INIT)); - - /* calculate value for the loop "step" variable */ - Sprintf(buf2, "%s step", $2); - /* end - start */ - add_opvars(splev, "vvo", - VA_PASS3(buf, $2, SPO_MATH_SUB)); - /* sign of that */ - add_opvars(splev, "o", VA_PASS1(SPO_MATH_SIGN)); - /* save the sign into the step var */ - add_opvars(splev, "iso", - VA_PASS3(0, buf2, SPO_VAR_INIT)); - - forloop_list[n_forloops].varname = strdup($2); - forloop_list[n_forloops].jmp_point = splev->n_opcodes; - - n_forloops++; - Free($2); - } - ; - -forstatement : forstmt_start - { - /* nothing */ - break_stmt_start(); - } - stmt_block - { - int l; - char buf[256], buf2[256]; - - n_forloops--; - Sprintf(buf, "%s step", forloop_list[n_forloops].varname); - Sprintf(buf2, "%s end", forloop_list[n_forloops].varname); - /* compare for-loop var to end value */ - add_opvars(splev, "vvo", - VA_PASS3(forloop_list[n_forloops].varname, - buf2, SPO_CMP)); - /* var + step */ - add_opvars(splev, "vvo", - VA_PASS3(buf, forloop_list[n_forloops].varname, - SPO_MATH_ADD)); - /* for-loop var = (for-loop var + step) */ - add_opvars(splev, "iso", - VA_PASS3(0, forloop_list[n_forloops].varname, - SPO_VAR_INIT)); - /* jump back if compared values were not equal */ - l = (int) (forloop_list[n_forloops].jmp_point - - splev->n_opcodes - 1); - add_opvars(splev, "io", VA_PASS2(l, SPO_JNE)); - Free(forloop_list[n_forloops].varname); - break_stmt_end(splev); - } - ; - -loopstatement : LOOP_ID '[' integer_or_var ']' - { - struct opvar *tmppush = New(struct opvar); - - if (n_if_list >= MAX_NESTED_IFS) { - lc_error("LOOP: Too deeply nested conditionals."); - n_if_list = MAX_NESTED_IFS - 1; - } - set_opvar_int(tmppush, splev->n_opcodes); - if_list[n_if_list++] = tmppush; - - add_opvars(splev, "o", VA_PASS1(SPO_DEC)); - break_stmt_start(); - } - stmt_block - { - struct opvar *tmppush; - - add_opvars(splev, "oio", VA_PASS3(SPO_COPY, 0, SPO_CMP)); - - tmppush = (struct opvar *) if_list[--n_if_list]; - set_opvar_int(tmppush, - tmppush->vardata.l - splev->n_opcodes-1); - add_opcode(splev, SPO_PUSH, tmppush); - add_opcode(splev, SPO_JG, NULL); - add_opcode(splev, SPO_POP, NULL); /* discard count */ - break_stmt_end(splev); - } - ; - -chancestatement : comparestmt ':' - { - struct opvar *tmppush2 = New(struct opvar); - - if (n_if_list >= MAX_NESTED_IFS) { - lc_error("IF: Too deeply nested conditionals."); - n_if_list = MAX_NESTED_IFS - 1; - } - - add_opcode(splev, SPO_CMP, NULL); - - set_opvar_int(tmppush2, splev->n_opcodes+1); - - if_list[n_if_list++] = tmppush2; - - add_opcode(splev, SPO_PUSH, tmppush2); - - add_opcode(splev, reverse_jmp_opcode( $1 ), NULL); - - } - levstatement - { - if (n_if_list > 0) { - struct opvar *tmppush; - - tmppush = (struct opvar *) if_list[--n_if_list]; - set_opvar_int(tmppush, - splev->n_opcodes - tmppush->vardata.l); - } else lc_error("IF: Huh?! No start address?"); - } - ; - -ifstatement : IF_ID comparestmt - { - struct opvar *tmppush2 = New(struct opvar); - - if (n_if_list >= MAX_NESTED_IFS) { - lc_error("IF: Too deeply nested conditionals."); - n_if_list = MAX_NESTED_IFS - 1; - } - - add_opcode(splev, SPO_CMP, NULL); - - set_opvar_int(tmppush2, splev->n_opcodes+1); - - if_list[n_if_list++] = tmppush2; - - add_opcode(splev, SPO_PUSH, tmppush2); - - add_opcode(splev, reverse_jmp_opcode( $2 ), NULL); - - } - if_ending - { - /* do nothing */ - } - ; - -if_ending : stmt_block - { - if (n_if_list > 0) { - struct opvar *tmppush; - - tmppush = (struct opvar *) if_list[--n_if_list]; - set_opvar_int(tmppush, - splev->n_opcodes - tmppush->vardata.l); - } else lc_error("IF: Huh?! No start address?"); - } - | stmt_block - { - if (n_if_list > 0) { - struct opvar *tmppush = New(struct opvar); - struct opvar *tmppush2; - - set_opvar_int(tmppush, splev->n_opcodes+1); - add_opcode(splev, SPO_PUSH, tmppush); - - add_opcode(splev, SPO_JMP, NULL); - - tmppush2 = (struct opvar *) if_list[--n_if_list]; - - set_opvar_int(tmppush2, - splev->n_opcodes - tmppush2->vardata.l); - if_list[n_if_list++] = tmppush; - } else lc_error("IF: Huh?! No else-part address?"); - } - ELSE_ID stmt_block - { - if (n_if_list > 0) { - struct opvar *tmppush; - tmppush = (struct opvar *) if_list[--n_if_list]; - set_opvar_int(tmppush, splev->n_opcodes - tmppush->vardata.l); - } else lc_error("IF: Huh?! No end address?"); - } - ; - -message : MESSAGE_ID ':' string_expr - { - add_opvars(splev, "o", VA_PASS1(SPO_MESSAGE)); - } - ; - -random_corridors: RAND_CORRIDOR_ID - { - add_opvars(splev, "iiiiiio", - VA_PASS7(-1, 0, -1, -1, -1, -1, SPO_CORRIDOR)); - } - | RAND_CORRIDOR_ID ':' all_integers - { - add_opvars(splev, "iiiiiio", - VA_PASS7(-1, $3, -1, -1, -1, -1, SPO_CORRIDOR)); - } - | RAND_CORRIDOR_ID ':' RANDOM_TYPE - { - add_opvars(splev, "iiiiiio", - VA_PASS7(-1, -1, -1, -1, -1, -1, SPO_CORRIDOR)); - } - ; - -corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec - { - add_opvars(splev, "iiiiiio", - VA_PASS7($3.room, $3.door, $3.wall, - $5.room, $5.door, $5.wall, - SPO_CORRIDOR)); - } - | CORRIDOR_ID ':' corr_spec ',' all_integers - { - add_opvars(splev, "iiiiiio", - VA_PASS7($3.room, $3.door, $3.wall, - -1, -1, (long)$5, - SPO_CORRIDOR)); - } - ; - -corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' - { - $$.room = $2; - $$.wall = $4; - $$.door = $6; - } - ; - -room_begin : room_type opt_percent ',' light_state - { - if (($2 < 100) && ($1 == OROOM)) - lc_error("Only typed rooms can have a chance."); - else { - add_opvars(splev, "iii", - VA_PASS3((long)$1, (long)$2, (long)$4)); - } - } - ; - -subroom_def : SUBROOM_ID ':' room_begin ',' subroom_pos ',' room_size optroomregionflags - { - long rflags = $8; - - if (rflags == -1) rflags = (1 << 0); - add_opvars(splev, "iiiiiiio", - VA_PASS8(rflags, ERR, ERR, - $5.x, $5.y, $7.width, $7.height, - SPO_SUBROOM)); - break_stmt_start(); - } - stmt_block - { - break_stmt_end(splev); - add_opcode(splev, SPO_ENDROOM, NULL); - } - ; - -room_def : ROOM_ID ':' room_begin ',' room_pos ',' room_align ',' room_size optroomregionflags - { - long rflags = $8; - - if (rflags == -1) rflags = (1 << 0); - add_opvars(splev, "iiiiiiio", - VA_PASS8(rflags, - $7.x, $7.y, $5.x, $5.y, - $9.width, $9.height, SPO_ROOM)); - break_stmt_start(); - } - stmt_block - { - break_stmt_end(splev); - add_opcode(splev, SPO_ENDROOM, NULL); - } - ; - -roomfill : /* nothing */ - { - $$ = 1; - } - | ',' BOOLEAN - { - $$ = $2; - } - ; - -room_pos : '(' INTEGER ',' INTEGER ')' - { - if ( $2 < 1 || $2 > 5 || - $4 < 1 || $4 > 5 ) { - lc_error("Room positions should be between 1-5: (%li,%li)!", $2, $4); - } else { - $$.x = $2; - $$.y = $4; - } - } - | RANDOM_TYPE - { - $$.x = $$.y = ERR; - } - ; - -subroom_pos : '(' INTEGER ',' INTEGER ')' - { - if ( $2 < 0 || $4 < 0) { - lc_error("Invalid subroom position (%li,%li)!", $2, $4); - } else { - $$.x = $2; - $$.y = $4; - } - } - | RANDOM_TYPE - { - $$.x = $$.y = ERR; - } - ; - -room_align : '(' h_justif ',' v_justif ')' - { - $$.x = $2; - $$.y = $4; - } - | RANDOM_TYPE - { - $$.x = $$.y = ERR; - } - ; - -room_size : '(' INTEGER ',' INTEGER ')' - { - $$.width = $2; - $$.height = $4; - } - | RANDOM_TYPE - { - $$.height = $$.width = ERR; - } - ; - -door_detail : ROOMDOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos - { - /* ERR means random here */ - if ($7 == ERR && $9 != ERR) { - lc_error("If the door wall is random, so must be its pos!"); - } else { - add_opvars(splev, "iiiio", - VA_PASS5((long)$9, (long)$5, (long)$3, - (long)$7, SPO_ROOM_DOOR)); - } - } - | DOOR_ID ':' door_state ',' ter_selection - { - add_opvars(splev, "io", VA_PASS2((long)$3, SPO_DOOR)); - } - ; - -secret : BOOLEAN - | RANDOM_TYPE - ; - -door_wall : dir_list - | RANDOM_TYPE - ; - -dir_list : DIRECTION - { - $$ = $1; - } - | DIRECTION '|' dir_list - { - $$ = ($1 | $3); - } - ; - -door_pos : INTEGER - | RANDOM_TYPE - ; - -map_definition : NOMAP_ID - { - add_opvars(splev, "ciisiio", - VA_PASS7(0, 0, 1, (char *) 0, 0, 0, SPO_MAP)); - max_x_map = COLNO-1; - max_y_map = ROWNO; - } - | GEOMETRY_ID ':' h_justif ',' v_justif roomfill MAP_ID - { - add_opvars(splev, "cii", - VA_PASS3(SP_COORD_PACK(($3), ($5)), - 1, (int) $6)); - scan_map($7, splev); - Free($7); - } - | GEOMETRY_ID ':' coord_or_var roomfill MAP_ID - { - add_opvars(splev, "ii", VA_PASS2(2, (int) $4)); - scan_map($5, splev); - Free($5); - } - ; - -h_justif : LEFT_OR_RIGHT - | CENTER - ; - -v_justif : TOP_OR_BOT - | CENTER - ; - -monster_detail : MONSTER_ID ':' monster_desc - { - add_opvars(splev, "io", VA_PASS2(0, SPO_MONSTER)); - } - | MONSTER_ID ':' monster_desc - { - add_opvars(splev, "io", VA_PASS2(1, SPO_MONSTER)); - in_container_obj++; - break_stmt_start(); - } - stmt_block - { - break_stmt_end(splev); - in_container_obj--; - add_opvars(splev, "o", VA_PASS1(SPO_END_MONINVENT)); - } - ; - -monster_desc : monster_or_var ',' coord_or_var monster_infos - { - /* nothing */ - } - ; - -monster_infos : /* nothing */ - { - struct opvar *stopit = New(struct opvar); - - set_opvar_int(stopit, SP_M_V_END); - add_opcode(splev, SPO_PUSH, stopit); - $$ = 0x0000; - } - | monster_infos ',' monster_info - { - if (( $1 & $3 )) - lc_error("MONSTER extra info defined twice."); - $$ = ( $1 | $3 ); - } - ; - -monster_info : string_expr - { - add_opvars(splev, "i", VA_PASS1(SP_M_V_NAME)); - $$ = 0x0001; - } - | MON_ATTITUDE - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_M_V_PEACEFUL)); - $$ = 0x0002; - } - | MON_ALERTNESS - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_M_V_ASLEEP)); - $$ = 0x0004; - } - | alignment_prfx - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_M_V_ALIGN)); - $$ = 0x0008; - } - | MON_APPEARANCE string_expr - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_M_V_APPEAR)); - $$ = 0x0010; - } - | FEMALE_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_FEMALE)); - $$ = 0x0020; - } - | INVIS_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_INVIS)); - $$ = 0x0040; - } - | CANCELLED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CANCELLED)); - $$ = 0x0080; - } - | REVIVED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_REVIVED)); - $$ = 0x0100; - } - | AVENGE_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_AVENGE)); - $$ = 0x0200; - } - | FLEEING_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_M_V_FLEEING)); - $$ = 0x0400; - } - | BLINDED_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_M_V_BLINDED)); - $$ = 0x0800; - } - | PARALYZED_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_M_V_PARALYZED)); - $$ = 0x1000; - } - | STUNNED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_STUNNED)); - $$ = 0x2000; - } - | CONFUSED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_M_V_CONFUSED)); - $$ = 0x4000; - } - | SEENTRAPS_ID ':' seen_trap_mask - { - add_opvars(splev, "ii", - VA_PASS2((int) $3, SP_M_V_SEENTRAPS)); - $$ = 0x8000; - } - ; - -seen_trap_mask : STRING - { - int token = get_trap_type($1); - - if (token == ERR || token == 0) - lc_error("Unknown trap type '%s'!", $1); - Free($1); - $$ = (1L << (token - 1)); - } - | ALL_ID - { - $$ = (long) ~0; - } - | STRING '|' seen_trap_mask - { - int token = get_trap_type($1); - if (token == ERR || token == 0) - lc_error("Unknown trap type '%s'!", $1); - - if ((1L << (token - 1)) & $3) - lc_error("Monster seen_traps, trap '%s' listed twice.", $1); - Free($1); - $$ = ((1L << (token - 1)) | $3); - } - ; - -object_detail : OBJECT_ID ':' object_desc - { - int cnt = 0; - - if (in_container_obj) - cnt |= SP_OBJ_CONTENT; - add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); - } - | COBJECT_ID ':' object_desc - { - int cnt = SP_OBJ_CONTAINER; - - if (in_container_obj) - cnt |= SP_OBJ_CONTENT; - add_opvars(splev, "io", VA_PASS2(cnt, SPO_OBJECT)); - in_container_obj++; - break_stmt_start(); - } - stmt_block - { - break_stmt_end(splev); - in_container_obj--; - add_opcode(splev, SPO_POP_CONTAINER, NULL); - } - ; - -object_desc : object_or_var object_infos - { - if (( $2 & 0x4000) && in_container_obj) - lc_error("Object cannot have a coord when contained."); - else if (!( $2 & 0x4000) && !in_container_obj) - lc_error("Object needs a coord when not contained."); - } - ; - -object_infos : /* nothing */ - { - struct opvar *stopit = New(struct opvar); - set_opvar_int(stopit, SP_O_V_END); - add_opcode(splev, SPO_PUSH, stopit); - $$ = 0x00; - } - | object_infos ',' object_info - { - if (( $1 & $3 )) - lc_error("OBJECT extra info '%s' defined twice.", curr_token); - $$ = ( $1 | $3 ); - } - ; - -object_info : CURSE_TYPE - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_O_V_CURSE)); - $$ = 0x0001; - } - | MONTYPE_ID ':' monster_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_CORPSENM)); - $$ = 0x0002; - } - | all_ints_push - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_SPE)); - $$ = 0x0004; - } - | NAME_ID ':' string_expr - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_NAME)); - $$ = 0x0008; - } - | QUANTITY_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_QUAN)); - $$ = 0x0010; - } - | BURIED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BURIED)); - $$ = 0x0020; - } - | LIGHT_STATE - { - add_opvars(splev, "ii", VA_PASS2((int) $1, SP_O_V_LIT)); - $$ = 0x0040; - } - | ERODED_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_ERODED)); - $$ = 0x0080; - } - | ERODEPROOF_ID - { - add_opvars(splev, "ii", VA_PASS2(-1, SP_O_V_ERODED)); - $$ = 0x0080; - } - | DOOR_STATE - { - if ($1 == D_LOCKED) { - add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_LOCKED)); - $$ = 0x0100; - } else if ($1 == D_BROKEN) { - add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_BROKEN)); - $$ = 0x0200; - } else - lc_error("DOOR state can only be locked or broken."); - } - | TRAPPED_STATE - { - add_opvars(splev, "ii", - VA_PASS2((int) $1, SP_O_V_TRAPPED)); - $$ = 0x0400; - } - | RECHARGED_ID ':' integer_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_RECHARGED)); - $$ = 0x0800; - } - | INVIS_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_INVIS)); - $$ = 0x1000; - } - | GREASED_ID - { - add_opvars(splev, "ii", VA_PASS2(1, SP_O_V_GREASED)); - $$ = 0x2000; - } - | coord_or_var - { - add_opvars(splev, "i", VA_PASS1(SP_O_V_COORD)); - $$ = 0x4000; - } - ; - -trap_detail : TRAP_ID ':' trap_name ',' coord_or_var - { - add_opvars(splev, "io", VA_PASS2((int) $3, SPO_TRAP)); - } - ; - -drawbridge_detail: DRAWBRIDGE_ID ':' coord_or_var ',' DIRECTION ',' door_state - { - long dir, state = 0; - - /* convert dir from a DIRECTION to a DB_DIR */ - dir = $5; - switch (dir) { - case W_NORTH: dir = DB_NORTH; break; - case W_SOUTH: dir = DB_SOUTH; break; - case W_EAST: dir = DB_EAST; break; - case W_WEST: dir = DB_WEST; break; - default: - lc_error("Invalid drawbridge direction."); - break; - } - - if ( $7 == D_ISOPEN ) - state = 1; - else if ( $7 == D_CLOSED ) - state = 0; - else if ( $7 == -1 ) - state = -1; - else - lc_error("A drawbridge can only be open, closed or random!"); - add_opvars(splev, "iio", - VA_PASS3(state, dir, SPO_DRAWBRIDGE)); - } - ; - -mazewalk_detail : MAZEWALK_ID ':' coord_or_var ',' DIRECTION - { - add_opvars(splev, "iiio", - VA_PASS4((int) $5, 1, 0, SPO_MAZEWALK)); - } - | MAZEWALK_ID ':' coord_or_var ',' DIRECTION ',' BOOLEAN opt_fillchar - { - add_opvars(splev, "iiio", - VA_PASS4((int) $5, (int) $7, - (int) $8, SPO_MAZEWALK)); - } - ; - -wallify_detail : WALLIFY_ID - { - add_opvars(splev, "rio", - VA_PASS3(SP_REGION_PACK(-1,-1,-1,-1), - 0, SPO_WALLIFY)); - } - | WALLIFY_ID ':' ter_selection - { - add_opvars(splev, "io", VA_PASS2(1, SPO_WALLIFY)); - } - ; - -ladder_detail : LADDER_ID ':' coord_or_var ',' UP_OR_DOWN - { - add_opvars(splev, "io", - VA_PASS2((int) $5, SPO_LADDER)); - } - ; - -stair_detail : STAIR_ID ':' coord_or_var ',' UP_OR_DOWN - { - add_opvars(splev, "io", - VA_PASS2((int) $5, SPO_STAIR)); - } - ; - -stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN - { - add_opvars(splev, "iiiii iiiii iiso", - VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, - $5.x1, $5.y1, $5.x2, $5.y2, $5.area, - (long) (($7) ? LR_UPSTAIR : LR_DOWNSTAIR), - 0, (char *) 0, SPO_LEVREGION)); - } - ; - -portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' STRING - { - add_opvars(splev, "iiiii iiiii iiso", - VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, - $5.x1, $5.y1, $5.x2, $5.y2, $5.area, - LR_PORTAL, 0, $7, SPO_LEVREGION)); - Free($7); - } - ; - -teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail - { - long rtyp = 0; - switch($6) { - case -1: rtyp = LR_TELE; break; - case 0: rtyp = LR_DOWNTELE; break; - case 1: rtyp = LR_UPTELE; break; - } - add_opvars(splev, "iiiii iiiii iiso", - VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, - $5.x1, $5.y1, $5.x2, $5.y2, $5.area, - rtyp, 0, (char *)0, SPO_LEVREGION)); - } - ; - -branch_region : BRANCH_ID ':' lev_region ',' lev_region - { - add_opvars(splev, "iiiii iiiii iiso", - VA_PASS14($3.x1, $3.y1, $3.x2, $3.y2, $3.area, - $5.x1, $5.y1, $5.x2, $5.y2, $5.area, - (long) LR_BRANCH, 0, - (char *) 0, SPO_LEVREGION)); - } - ; - -teleprt_detail : /* empty */ - { - $$ = -1; - } - | ',' UP_OR_DOWN - { - $$ = $2; - } - ; - -fountain_detail : FOUNTAIN_ID ':' ter_selection - { - add_opvars(splev, "o", VA_PASS1(SPO_FOUNTAIN)); - } - ; - -sink_detail : SINK_ID ':' ter_selection - { - add_opvars(splev, "o", VA_PASS1(SPO_SINK)); - } - ; - -pool_detail : POOL_ID ':' ter_selection - { - add_opvars(splev, "o", VA_PASS1(SPO_POOL)); - } - ; - -terrain_type : CHAR - { - $$.lit = -2; - $$.ter = what_map_char((char) $1); - } - | '(' CHAR ',' light_state ')' - { - $$.lit = $4; - $$.ter = what_map_char((char) $2); - } - ; - -replace_terrain_detail : REPLACE_TERRAIN_ID ':' region_or_var ',' mapchar_or_var ',' mapchar_or_var ',' SPERCENT - { - add_opvars(splev, "io", - VA_PASS2($9, SPO_REPLACETERRAIN)); - } - ; - -terrain_detail : TERRAIN_ID ':' ter_selection ',' mapchar_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_TERRAIN)); - } - ; - -diggable_detail : NON_DIGGABLE_ID ':' region_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_NON_DIGGABLE)); - } - ; - -passwall_detail : NON_PASSWALL_ID ':' region_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_NON_PASSWALL)); - } - ; - -region_detail : REGION_ID ':' region_or_var ',' light_state ',' room_type optroomregionflags - { - long irr; - long rt = $7; - long rflags = $8; - - if (rflags == -1) rflags = (1 << 0); - if (!(rflags & 1)) rt += MAXRTYPE+1; - irr = ((rflags & 2) != 0); - add_opvars(splev, "iiio", - VA_PASS4((long)$5, rt, rflags, SPO_REGION)); - $$ = (irr || (rflags & 1) || rt != OROOM); - break_stmt_start(); - } - region_detail_end - { - break_stmt_end(splev); - if ( $9 ) { - add_opcode(splev, SPO_ENDROOM, NULL); - } else if ( $10 ) - lc_error("Cannot use lev statements in non-permanent REGION"); - } - ; - -region_detail_end : /* nothing */ - { - $$ = 0; - } - | stmt_block - { - $$ = $1; - } - ; - -altar_detail : ALTAR_ID ':' coord_or_var ',' alignment ',' altar_type - { - add_opvars(splev, "iio", - VA_PASS3((long)$7, (long)$5, SPO_ALTAR)); - } - ; - -grave_detail : GRAVE_ID ':' coord_or_var ',' string_expr - { - add_opvars(splev, "io", VA_PASS2(2, SPO_GRAVE)); - } - | GRAVE_ID ':' coord_or_var ',' RANDOM_TYPE - { - add_opvars(splev, "sio", - VA_PASS3((char *)0, 1, SPO_GRAVE)); - } - | GRAVE_ID ':' coord_or_var - { - add_opvars(splev, "sio", - VA_PASS3((char *)0, 0, SPO_GRAVE)); - } - ; - -gold_detail : GOLD_ID ':' math_expr_var ',' coord_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_GOLD)); - } - ; - -engraving_detail: ENGRAVING_ID ':' coord_or_var ',' engraving_type ',' string_expr - { - add_opvars(splev, "io", - VA_PASS2((long)$5, SPO_ENGRAVING)); - } - ; - -mineralize : MINERALIZE_ID ':' integer_or_var ',' integer_or_var ',' integer_or_var ',' integer_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MINERALIZE)); - } - | MINERALIZE_ID - { - add_opvars(splev, "iiiio", - VA_PASS5(-1L, -1L, -1L, -1L, SPO_MINERALIZE)); - } - ; - -trap_name : STRING - { - int token = get_trap_type($1); - if (token == ERR) - lc_error("Unknown trap type '%s'!", $1); - $$ = token; - Free($1); - } - | RANDOM_TYPE - ; - -room_type : STRING - { - int token = get_room_type($1); - if (token == ERR) { - lc_warning("Unknown room type \"%s\"! Making ordinary room...", $1); - $$ = OROOM; - } else - $$ = token; - Free($1); - } - | RANDOM_TYPE - ; - -optroomregionflags : /* empty */ - { - $$ = -1; - } - | ',' roomregionflags - { - $$ = $2; - } - ; - -roomregionflags : roomregionflag - { - $$ = $1; - } - | roomregionflag ',' roomregionflags - { - $$ = $1 | $3; - } - ; - -/* 0 is the "default" here */ -roomregionflag : FILLING - { - $$ = ($1 << 0); - } - | IRREGULAR - { - $$ = ($1 << 1); - } - | JOINED - { - $$ = ($1 << 2); - } - ; - -door_state : DOOR_STATE - | RANDOM_TYPE - ; - -light_state : LIGHT_STATE - | RANDOM_TYPE - ; - -alignment : ALIGNMENT - | a_register - | RANDOM_TYPE - { - $$ = - MAX_REGISTERS - 1; - } - ; - -alignment_prfx : ALIGNMENT - | a_register - | A_REGISTER ':' RANDOM_TYPE - { - $$ = - MAX_REGISTERS - 1; - } - ; - -altar_type : ALTAR_TYPE - | RANDOM_TYPE - ; - -a_register : A_REGISTER '[' INTEGER ']' - { - if ( $3 >= 3 ) - lc_error("Register Index overflow!"); - else - $$ = - $3 - 1; - } - ; - -string_or_var : STRING - { - add_opvars(splev, "s", VA_PASS1($1)); - Free($1); - } - | VARSTRING_STRING - { - check_vardef_type(vardefs, $1, SPOVAR_STRING); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_STRING_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_STRING | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - - -integer_or_var : math_expr_var - { - /* nothing */ - } - ; - -coord_or_var : encodecoord - { - add_opvars(splev, "c", VA_PASS1($1)); - } - | rndcoord_ID '(' ter_selection ')' - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDCOORD)); - } - | VARSTRING_COORD - { - check_vardef_type(vardefs, $1, SPOVAR_COORD); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_COORD_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_COORD | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - -encodecoord : '(' INTEGER ',' INTEGER ')' - { - if ($2 < 0 || $4 < 0 || $2 >= COLNO || $4 >= ROWNO) - lc_error("Coordinates (%li,%li) out of map range!", - $2, $4); - $$ = SP_COORD_PACK($2, $4); - } - | RANDOM_TYPE - { - $$ = SP_COORD_PACK_RANDOM(0); - } - | RANDOM_TYPE_BRACKET humidity_flags ']' - { - $$ = SP_COORD_PACK_RANDOM($2); - } - ; - -humidity_flags : HUMIDITY_TYPE - { - $$ = $1; - } - | HUMIDITY_TYPE ',' humidity_flags - { - if (($1 & $3)) - lc_warning("Humidity flag used twice."); - $$ = ($1 | $3); - } - ; - -region_or_var : encoderegion - { - /* nothing */ - } - | VARSTRING_REGION - { - check_vardef_type(vardefs, $1, SPOVAR_REGION); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_REGION_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_REGION | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - -encoderegion : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' - { - long r = SP_REGION_PACK($2, $4, $6, $8); - - if ($2 > $6 || $4 > $8) - lc_error("Region start > end: (%ld,%ld,%ld,%ld)!", - $2, $4, $6, $8); - - add_opvars(splev, "r", VA_PASS1(r)); - $$ = r; - } - ; - -mapchar_or_var : mapchar - { - add_opvars(splev, "m", VA_PASS1($1)); - } - | VARSTRING_MAPCHAR - { - check_vardef_type(vardefs, $1, SPOVAR_MAPCHAR); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_MAPCHAR_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_MAPCHAR | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - -mapchar : CHAR - { - if (what_map_char((char) $1) != INVALID_TYPE) - $$ = SP_MAPCHAR_PACK(what_map_char((char) $1), -2); - else { - lc_error("Unknown map char type '%c'!", $1); - $$ = SP_MAPCHAR_PACK(STONE, -2); - } - } - | '(' CHAR ',' light_state ')' - { - if (what_map_char((char) $2) != INVALID_TYPE) - $$ = SP_MAPCHAR_PACK(what_map_char((char) $2), $4); - else { - lc_error("Unknown map char type '%c'!", $2); - $$ = SP_MAPCHAR_PACK(STONE, $4); - } - } - ; - -monster_or_var : encodemonster - { - add_opvars(splev, "M", VA_PASS1($1)); - } - | VARSTRING_MONST - { - check_vardef_type(vardefs, $1, SPOVAR_MONST); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_MONST_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_MONST | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - -encodemonster : STRING - { - long m = get_monster_id($1, (char)0); - if (m == ERR) { - lc_error("Unknown monster \"%s\"!", $1); - $$ = -1; - } else - $$ = SP_MONST_PACK(m, - def_monsyms[(int) mons[m].mlet].sym); - Free($1); - } - | CHAR - { - if (check_monster_char((char) $1)) - $$ = SP_MONST_PACK(-1, $1); - else { - lc_error("Unknown monster class '%c'!", $1); - $$ = -1; - } - } - | '(' CHAR ',' STRING ')' - { - long m = get_monster_id($4, (char) $2); - if (m == ERR) { - lc_error("Unknown monster ('%c', \"%s\")!", $2, $4); - $$ = -1; - } else - $$ = SP_MONST_PACK(m, $2); - Free($4); - } - | RANDOM_TYPE - { - $$ = -1; - } - ; - -object_or_var : encodeobj - { - add_opvars(splev, "O", VA_PASS1($1)); - } - | VARSTRING_OBJ - { - check_vardef_type(vardefs, $1, SPOVAR_OBJ); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | VARSTRING_OBJ_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_OBJ | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - ; - -encodeobj : STRING - { - long m = get_object_id($1, (char)0); - if (m == ERR) { - lc_error("Unknown object \"%s\"!", $1); - $$ = -1; - } else - /* obj class != 0 to force generation of a specific item */ - $$ = SP_OBJ_PACK(m, 1); - Free($1); - } - | CHAR - { - if (check_object_char((char) $1)) - $$ = SP_OBJ_PACK(-1, $1); - else { - lc_error("Unknown object class '%c'!", $1); - $$ = -1; - } - } - | '(' CHAR ',' STRING ')' - { - long m = get_object_id($4, (char) $2); - if (m == ERR) { - lc_error("Unknown object ('%c', \"%s\")!", $2, $4); - $$ = -1; - } else - $$ = SP_OBJ_PACK(m, $2); - Free($4); - } - | RANDOM_TYPE - { - $$ = -1; - } - ; - - -string_expr : string_or_var { } - | string_expr '.' string_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); - } - ; - -math_expr_var : INTEGER - { - add_opvars(splev, "i", VA_PASS1($1)); - } - | dice - { - is_inconstant_number = 1; - } - | '(' MINUS_INTEGER ')' - { - add_opvars(splev, "i", VA_PASS1($2)); - } - | VARSTRING_INT - { - check_vardef_type(vardefs, $1, SPOVAR_INT); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - is_inconstant_number = 1; - } - | VARSTRING_INT_ARRAY '[' math_expr_var ']' - { - check_vardef_type(vardefs, $1, - SPOVAR_INT | SPOVAR_ARRAY); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - is_inconstant_number = 1; - } - | math_expr_var '+' math_expr_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_ADD)); - } - | math_expr_var '-' math_expr_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_SUB)); - } - | math_expr_var '*' math_expr_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_MUL)); - } - | math_expr_var '/' math_expr_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_DIV)); - } - | math_expr_var '%' math_expr_var - { - add_opvars(splev, "o", VA_PASS1(SPO_MATH_MOD)); - } - | '(' math_expr_var ')' { } - ; - -func_param_type : CFUNC_INT - { - if (!strcmp("int", $1) || !strcmp("integer", $1)) { - $$ = (int)'i'; - } else - lc_error("Unknown function parameter type '%s'", $1); - } - | CFUNC_STR - { - if (!strcmp("str", $1) || !strcmp("string", $1)) { - $$ = (int)'s'; - } else - lc_error("Unknown function parameter type '%s'", $1); - } - ; - -func_param_part : any_var_or_arr ':' func_param_type - { - struct lc_funcdefs_parm *tmp = New(struct lc_funcdefs_parm); - - if (!curr_function) { - lc_error("Function parameters outside function definition."); - } else if (!tmp) { - lc_error("Could not alloc function params."); - } else { - long vt = SPOVAR_NULL; - - tmp->name = strdup($1); - tmp->parmtype = (char) $3; - tmp->next = curr_function->params; - curr_function->params = tmp; - curr_function->n_params++; - switch (tmp->parmtype) { - case 'i': - vt = SPOVAR_INT; - break; - case 's': - vt = SPOVAR_STRING; - break; - default: - lc_error("Unknown func param conversion."); - break; - } - vardefs = add_vardef_type( vardefs, $1, vt); - } - Free($1); - } - ; - -func_param_list : func_param_part - | func_param_list ',' func_param_part - ; - -func_params_list : /* nothing */ - | func_param_list - ; - -func_call_param_part : math_expr_var - { - $$ = (int)'i'; - } - | string_expr - { - $$ = (int)'s'; - } - ; - - -func_call_param_list : func_call_param_part - { - char tmpbuf[2]; - tmpbuf[0] = (char) $1; - tmpbuf[1] = '\0'; - $$ = strdup(tmpbuf); - } - | func_call_param_list ',' func_call_param_part - { - long len = strlen( $1 ); - char *tmp = (char *) alloc(len + 2); - sprintf(tmp, "%c%s", (char) $3, $1 ); - Free( $1 ); - $$ = tmp; - } - ; - -func_call_params_list : /* nothing */ - { - $$ = strdup(""); - } - | func_call_param_list - { - char *tmp = strdup( $1 ); - Free( $1 ); - $$ = tmp; - } - ; - -ter_selection_x : coord_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_POINT)); - } - | rect_ID region_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_RECT)); - } - | fillrect_ID region_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_FILLRECT)); - } - | line_ID coord_or_var ',' coord_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_LINE)); - } - | randline_ID coord_or_var ',' coord_or_var ',' math_expr_var - { - /* randline (x1,y1),(x2,y2), roughness */ - add_opvars(splev, "o", VA_PASS1(SPO_SEL_RNDLINE)); - } - | grow_ID '(' ter_selection ')' - { - add_opvars(splev, "io", VA_PASS2(W_ANY, SPO_SEL_GROW)); - } - | grow_ID '(' dir_list ',' ter_selection ')' - { - add_opvars(splev, "io", VA_PASS2($3, SPO_SEL_GROW)); - } - | filter_ID '(' SPERCENT ',' ter_selection ')' - { - add_opvars(splev, "iio", - VA_PASS3($3, SPOFILTER_PERCENT, SPO_SEL_FILTER)); - } - | filter_ID '(' ter_selection ',' ter_selection ')' - { - add_opvars(splev, "io", - VA_PASS2(SPOFILTER_SELECTION, SPO_SEL_FILTER)); - } - | filter_ID '(' mapchar_or_var ',' ter_selection ')' - { - add_opvars(splev, "io", - VA_PASS2(SPOFILTER_MAPCHAR, SPO_SEL_FILTER)); - } - | flood_ID coord_or_var - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_FLOOD)); - } - | circle_ID '(' coord_or_var ',' math_expr_var ')' - { - add_opvars(splev, "oio", - VA_PASS3(SPO_COPY, 1, SPO_SEL_ELLIPSE)); - } - | circle_ID '(' coord_or_var ',' math_expr_var ',' FILLING ')' - { - add_opvars(splev, "oio", - VA_PASS3(SPO_COPY, $7, SPO_SEL_ELLIPSE)); - } - | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ')' - { - add_opvars(splev, "io", VA_PASS2(1, SPO_SEL_ELLIPSE)); - } - | ellipse_ID '(' coord_or_var ',' math_expr_var ',' math_expr_var ',' FILLING ')' - { - add_opvars(splev, "io", VA_PASS2($9, SPO_SEL_ELLIPSE)); - } - | gradient_ID '(' GRADIENT_TYPE ',' '(' math_expr_var '-' math_expr_var opt_limited ')' ',' coord_or_var opt_coord_or_var ')' - { - add_opvars(splev, "iio", - VA_PASS3($9, $3, SPO_SEL_GRADIENT)); - } - | complement_ID ter_selection_x - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_COMPLEMENT)); - } - | VARSTRING_SEL - { - check_vardef_type(vardefs, $1, SPOVAR_SEL); - vardef_used(vardefs, $1); - add_opvars(splev, "v", VA_PASS1($1)); - Free($1); - } - | '(' ter_selection ')' - { - /* nothing */ - } - ; - -ter_selection : ter_selection_x - { - /* nothing */ - } - | ter_selection_x '&' ter_selection - { - add_opvars(splev, "o", VA_PASS1(SPO_SEL_ADD)); - } - ; - -dice : DICE - { - add_opvars(splev, "iio", - VA_PASS3($1.num, $1.die, SPO_DICE)); - } - ; - -all_integers : MINUS_INTEGER - | PLUS_INTEGER - | INTEGER - ; - -all_ints_push : MINUS_INTEGER - { - add_opvars(splev, "i", VA_PASS1($1)); - } - | PLUS_INTEGER - { - add_opvars(splev, "i", VA_PASS1($1)); - } - | INTEGER - { - add_opvars(splev, "i", VA_PASS1($1)); - } - | dice - { - /* nothing */ - } - ; - -objectid : object_ID - | OBJECT_ID - ; - -monsterid : monster_ID - | MONSTER_ID - ; - -terrainid : terrain_ID - | TERRAIN_ID - ; - -engraving_type : ENGRAVING_TYPE - | RANDOM_TYPE - ; - -lev_region : region - { - $$ = $1; - } - | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' - { - if ($3 <= 0 || $3 >= COLNO) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of level range (x1)!", - $3, $5, $7, $9); - else if ($5 < 0 || $5 >= ROWNO) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of level range (y1)!", - $3, $5, $7, $9); - else if ($7 <= 0 || $7 >= COLNO) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of level range (x2)!", - $3, $5, $7, $9); - else if ($9 < 0 || $9 >= ROWNO) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of level range (y2)!", - $3, $5, $7, $9); - $$.x1 = $3; - $$.y1 = $5; - $$.x2 = $7; - $$.y2 = $9; - $$.area = 1; - } - ; - -region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' - { -/* This series of if statements is a hack for MSC 5.1. It seems that its - tiny little brain cannot compile if these are all one big if statement. */ - if ($2 < 0 || $2 > (int) max_x_map) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of map range (x1)!", - $2, $4, $6, $8); - else if ($4 < 0 || $4 > (int) max_y_map) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of map range (y1)!", - $2, $4, $6, $8); - else if ($6 < 0 || $6 > (int) max_x_map) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of map range (x2)!", - $2, $4, $6, $8); - else if ($8 < 0 || $8 > (int) max_y_map) - lc_error( - "Region (%ld,%ld,%ld,%ld) out of map range (y2)!", - $2, $4, $6, $8); - $$.area = 0; - $$.x1 = $2; - $$.y1 = $4; - $$.x2 = $6; - $$.y2 = $8; - } - ; - - -%% - -/*lev_comp.y*/ diff --git a/util/lev_main.c b/util/lev_main.c deleted file mode 100644 index 8bcfc8365..000000000 --- a/util/lev_main.c +++ /dev/null @@ -1,1649 +0,0 @@ -/* NetHack 3.6 lev_main.c $NHDT-Date: 1543371692 2018/11/28 02:21:32 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.56 $ */ -/* Copyright (c) 1989 by Jean-Christophe Collet */ -/* NetHack may be freely redistributed. See license for details. */ - -/* - * This file contains the main function for the parser - * and some useful functions needed by yacc - */ -#define SPEC_LEV /* for USE_OLDARGS (sp_lev.h) and for MPW (macconf.h) */ - -#define NEED_VARARGS -#include "hack.h" -#include "date.h" -#include "sp_lev.h" -#ifdef STRICT_REF_DEF -#include "tcap.h" -#endif -#include - -#ifdef MAC -#if defined(__SC__) || defined(__MRC__) -#define MPWTOOL -#define PREFIX ":dungeon:" /* place output files here */ -#include -#else -#if !defined(__MACH__) -#define PREFIX ":lib:" /* place output files here */ -#endif -#endif -#endif - -#ifdef WIN_CE -#define PREFIX "\\nethack\\dat\\" -#endif - -#ifndef MPWTOOL -#define SpinCursor(x) -#endif - -#if defined(AMIGA) && defined(DLB) -#define PREFIX "NH:slib/" -#endif - -#ifndef O_WRONLY -#include -#endif -#ifndef O_CREAT /* some older BSD systems do not define O_CREAT in \ - */ -#include -#endif -#ifndef O_BINARY /* used for micros, no-op for others */ -#define O_BINARY 0 -#endif - -#if defined(MICRO) || defined(WIN32) -#define OMASK FCMASK -#else -#define OMASK 0644 -#endif - -#define ERR (-1) - -#define NewTab(type, size) (type **) alloc(sizeof(type *) * size) -#define Free(ptr) \ - if (ptr) \ - free((genericptr_t)(ptr)) -/* write() returns a signed value but its size argument is unsigned; - types might be int and unsigned or ssize_t and size_t; casting - to long should be safe for all permutations (even if size_t is - bigger, since the values involved won't be too big for long) */ -#define Write(fd, item, size) \ - if ((long) write(fd, (genericptr_t)(item), size) != (long) (size)) \ - return FALSE; - -#if defined(__BORLANDC__) && !defined(_WIN32) -extern unsigned _stklen = STKSIZ; -#endif -#define MAX_ERRORS 25 - -extern int NDECL(yyparse); -extern void FDECL(init_yyin, (FILE *)); -extern void FDECL(init_yyout, (FILE *)); - -int FDECL(main, (int, char **)); -void FDECL(yyerror, (const char *)); -void FDECL(yywarning, (const char *)); -int NDECL(yywrap); -int FDECL(get_floor_type, (CHAR_P)); -int FDECL(get_room_type, (char *)); -int FDECL(get_trap_type, (char *)); -int FDECL(get_monster_id, (char *, CHAR_P)); -int FDECL(get_object_id, (char *, CHAR_P)); -boolean FDECL(check_monster_char, (CHAR_P)); -boolean FDECL(check_object_char, (CHAR_P)); -char FDECL(what_map_char, (CHAR_P)); -void FDECL(scan_map, (char *, sp_lev *)); -boolean NDECL(check_subrooms); -boolean FDECL(write_level_file, (char *, sp_lev *)); - -struct lc_funcdefs *FDECL(funcdef_new, (long, char *)); -void FDECL(funcdef_free_all, (struct lc_funcdefs *)); -struct lc_funcdefs *FDECL(funcdef_defined, - (struct lc_funcdefs *, char *, int)); - -struct lc_vardefs *FDECL(vardef_new, (long, char *)); -void FDECL(vardef_free_all, (struct lc_vardefs *)); -struct lc_vardefs *FDECL(vardef_defined, (struct lc_vardefs *, char *, int)); - -void FDECL(splev_add_from, (sp_lev *, sp_lev *)); - -extern void NDECL(monst_init); -extern void NDECL(objects_init); -extern void NDECL(decl_init); - -void FDECL(add_opcode, (sp_lev *, int, genericptr_t)); - -static boolean FDECL(write_common_data, (int)); -static boolean FDECL(write_maze, (int, sp_lev *)); -static void NDECL(init_obj_classes); -static int FDECL(case_insensitive_comp, (const char *, const char *)); - -void VDECL(lc_pline, (const char *, ...)); -void VDECL(lc_error, (const char *, ...)); -void VDECL(lc_warning, (const char *, ...)); -char *FDECL(decode_parm_chr, (CHAR_P)); -char *FDECL(decode_parm_str, (char *)); -struct opvar *FDECL(set_opvar_int, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_coord, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_region, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_mapchar, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_monst, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_obj, (struct opvar *, long)); -struct opvar *FDECL(set_opvar_str, (struct opvar *, const char *)); -struct opvar *FDECL(set_opvar_var, (struct opvar *, const char *)); -void VDECL(add_opvars, (sp_lev *, const char *, ...)); -void NDECL(break_stmt_start); -void FDECL(break_stmt_end, (sp_lev *)); -void FDECL(break_stmt_new, (sp_lev *, long)); -char *FDECL(funcdef_paramtypes, (struct lc_funcdefs *)); -const char *FDECL(spovar2str, (long)); -void FDECL(vardef_used, (struct lc_vardefs *, char *)); -void FDECL(check_vardef_type, (struct lc_vardefs *, char *, long)); -struct lc_vardefs *FDECL(add_vardef_type, - (struct lc_vardefs *, char *, long)); -int FDECL(reverse_jmp_opcode, (int)); -struct opvar *FDECL(opvar_clone, (struct opvar *)); -void FDECL(start_level_def, (sp_lev **, char *)); - -static struct { - const char *name; - int type; -} trap_types[] = { { "arrow", ARROW_TRAP }, - { "dart", DART_TRAP }, - { "falling rock", ROCKTRAP }, - { "board", SQKY_BOARD }, - { "bear", BEAR_TRAP }, - { "land mine", LANDMINE }, - { "rolling boulder", ROLLING_BOULDER_TRAP }, - { "sleep gas", SLP_GAS_TRAP }, - { "rust", RUST_TRAP }, - { "fire", FIRE_TRAP }, - { "pit", PIT }, - { "spiked pit", SPIKED_PIT }, - { "hole", HOLE }, - { "trap door", TRAPDOOR }, - { "teleport", TELEP_TRAP }, - { "level teleport", LEVEL_TELEP }, - { "magic portal", MAGIC_PORTAL }, - { "web", WEB }, - { "statue", STATUE_TRAP }, - { "magic", MAGIC_TRAP }, - { "anti magic", ANTI_MAGIC }, - { "polymorph", POLY_TRAP }, - { "vibrating square", VIBRATING_SQUARE }, - { 0, 0 } }; - -static struct { - const char *name; - int type; -} room_types[] = { - /* for historical reasons, room types are not contiguous numbers */ - /* (type 1 is skipped) */ - { "ordinary", OROOM }, - { "throne", COURT }, - { "swamp", SWAMP }, - { "vault", VAULT }, - { "beehive", BEEHIVE }, - { "morgue", MORGUE }, - { "barracks", BARRACKS }, - { "zoo", ZOO }, - { "delphi", DELPHI }, - { "temple", TEMPLE }, - { "anthole", ANTHOLE }, - { "cocknest", COCKNEST }, - { "leprehall", LEPREHALL }, - { "shop", SHOPBASE }, - { "armor shop", ARMORSHOP }, - { "scroll shop", SCROLLSHOP }, - { "potion shop", POTIONSHOP }, - { "weapon shop", WEAPONSHOP }, - { "food shop", FOODSHOP }, - { "ring shop", RINGSHOP }, - { "wand shop", WANDSHOP }, - { "tool shop", TOOLSHOP }, - { "book shop", BOOKSHOP }, - { "health food shop", FODDERSHOP }, - { "candle shop", CANDLESHOP }, - { 0, 0 } -}; - -const char *fname = "(stdin)"; -int fatal_error = 0; -int got_errors = 0; -int be_verbose = 0; -int fname_counter = 1; - -#ifdef FLEX23_BUG -/* Flex 2.3 bug work around; not needed for 2.3.6 or later */ -int yy_more_len = 0; -#endif - -extern unsigned int max_x_map, max_y_map; - -extern int nh_line_number; - -extern int token_start_pos; -extern char curr_token[512]; - -struct lc_vardefs *vardefs = NULL; -struct lc_funcdefs *function_definitions = NULL; - -extern int allow_break_statements; -extern struct lc_breakdef *break_list; - -int -main(argc, argv) -int argc; -char **argv; -{ - FILE *fin; - int i; - boolean errors_encountered = FALSE; -#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) - static char *mac_argv[] = { - "lev_comp", /* dummy argv[0] */ - ":dat:Arch.des", ":dat:Barb.des", ":dat:Caveman.des", - ":dat:Healer.des", ":dat:Knight.des", ":dat:Monk.des", - ":dat:Priest.des", ":dat:Ranger.des", ":dat:Rogue.des", - ":dat:Samurai.des", ":dat:Tourist.des", ":dat:Valkyrie.des", - ":dat:Wizard.des", ":dat:bigroom.des", ":dat:castle.des", - ":dat:endgame.des", ":dat:gehennom.des", ":dat:knox.des", - ":dat:medusa.des", ":dat:mines.des", ":dat:oracle.des", - ":dat:sokoban.des", ":dat:tower.des", ":dat:yendor.des" - }; - - argc = SIZE(mac_argv); - argv = mac_argv; -#endif - /* Note: these initializers don't do anything except guarantee that - * we're linked properly. - */ - monst_init(); - objects_init(); - decl_init(); - /* this one does something... */ - init_obj_classes(); - - init_yyout(stdout); - if (argc == 1) { /* Read standard input */ - init_yyin(stdin); - (void) yyparse(); - if (fatal_error > 0) { - errors_encountered = TRUE; - } - } else { /* Otherwise every argument is a filename */ - for (i = 1; i < argc; i++) { - fname = argv[i]; - if (!strcmp(fname, "-v")) { - be_verbose++; - continue; - } - fin = freopen(fname, "r", stdin); - if (!fin) { - lc_pline("Can't open \"%s\" for input.\n", VA_PASS1(fname)); - perror(fname); - errors_encountered = TRUE; - } else { - fname_counter = 1; - init_yyin(fin); - (void) yyparse(); - nh_line_number = 1; - if (fatal_error > 0 || got_errors > 0) { - errors_encountered = TRUE; - fatal_error = 0; - } - } - } - } - exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); - /*NOTREACHED*/ - return 0; -} - -/* - * Each time the parser detects an error, it uses this function. - * Here we take count of the errors. To continue farther than - * MAX_ERRORS wouldn't be reasonable. - * Assume that explicit calls from lev_comp.y have the 1st letter - * capitalized, to allow printing of the line containing the start of - * the current declaration, instead of the beginning of the next declaration. - */ -void -yyerror(s) -const char *s; -{ - char *e = ((char *) s + strlen(s) - 1); - - (void) fprintf(stderr, "%s: line %d, pos %d: %s", fname, nh_line_number, - token_start_pos - (int) strlen(curr_token), s); - if (*e != '.' && *e != '!') - (void) fprintf(stderr, " at \"%s\"", curr_token); - (void) fprintf(stderr, "\n"); - - if (++fatal_error > MAX_ERRORS) { - (void) fprintf(stderr, "Too many errors, good bye!\n"); - exit(EXIT_FAILURE); - } -} - -/* - * Just display a warning (that is : a non fatal error) - */ -void -yywarning(s) -const char *s; -{ - (void) fprintf(stderr, "%s: line %d : WARNING : %s\n", fname, - nh_line_number, s); -} - -/* - * Stub needed for lex interface. - */ -int -yywrap() -{ - return 1; -} - -/* - * lc_pline(): lev_comp version of pline(), stripped down version of - * core's pline(), with convoluted handling for variadic arguments to - * support , , and neither of the above. - * - * Using state for message/warning/error mode simplifies calling interface. - */ -#define LC_PLINE_MESSAGE 0 -#define LC_PLINE_WARNING 1 -#define LC_PLINE_ERROR 2 -static int lc_pline_mode = LC_PLINE_MESSAGE; - -#if defined(USE_STDARG) || defined(USE_VARARGS) -static void FDECL(lc_vpline, (const char *, va_list)); - -void lc_pline -VA_DECL(const char *, line) -{ - VA_START(line); - VA_INIT(line, char *); - lc_vpline(line, VA_ARGS); - VA_END(); -} - -#ifdef USE_STDARG -static void -lc_vpline(const char *line, va_list the_args) -#else -static void -lc_vpline(line, the_args) -const char *line; -va_list the_args; -#endif - -#else /* USE_STDARG | USE_VARARG */ - -#define lc_vpline lc_pline - -void -lc_pline -VA_DECL(const char *, line) -#endif /* USE_STDARG | USE_VARARG */ -{ /* opening brace for lc_vpline, nested block for USE_OLDARGS lc_pline */ - - char pbuf[3 * BUFSZ]; - static char nomsg[] = "(no message)"; - /* Do NOT use VA_START and VA_END in here... see above */ - - if (!line || !*line) - line = nomsg; /* shouldn't happen */ - if (index(line, '%')) { - Vsprintf(pbuf, line, VA_ARGS); - pbuf[BUFSZ - 1] = '\0'; /* truncate if long */ - line = pbuf; - } - switch (lc_pline_mode) { - case LC_PLINE_ERROR: - yyerror(line); - break; - case LC_PLINE_WARNING: - yywarning(line); - break; - default: - (void) fprintf(stderr, "%s\n", line); - break; - } - lc_pline_mode = LC_PLINE_MESSAGE; /* reset to default */ - return; -#if !(defined(USE_STDARG) || defined(USE_VARARGS)) - VA_END(); /* closing brace ofr USE_OLDARGS's nested block */ -#endif -} - -/*VARARGS1*/ -void -lc_error -VA_DECL(const char *, line) -{ - VA_START(line); - VA_INIT(line, const char *); - lc_pline_mode = LC_PLINE_ERROR; - lc_vpline(line, VA_ARGS); - VA_END(); - return; -} - -/*VARARGS1*/ -void -lc_warning -VA_DECL(const char *, line) -{ - VA_START(line); - VA_INIT(line, const char *); - lc_pline_mode = LC_PLINE_WARNING; - lc_vpline(line, VA_ARGS); - VA_END(); - return; -} - -char * -decode_parm_chr(chr) -char chr; -{ - static char buf[32]; - - switch (chr) { - default: - Strcpy(buf, "unknown"); - break; - case 'i': - Strcpy(buf, "int"); - break; - case 'r': - Strcpy(buf, "region"); - break; - case 's': - Strcpy(buf, "str"); - break; - case 'O': - Strcpy(buf, "obj"); - break; - case 'c': - Strcpy(buf, "coord"); - break; - case ' ': - Strcpy(buf, "nothing"); - break; - case 'm': - Strcpy(buf, "mapchar"); - break; - case 'M': - Strcpy(buf, "monster"); - break; - } - return buf; -} - -char * -decode_parm_str(str) -char *str; -{ - static char tmpbuf[1024]; - char *p = str; - tmpbuf[0] = '\0'; - if (str) { - for (; *p; p++) { - Strcat(tmpbuf, decode_parm_chr(*p)); - if (*(p + 1)) - Strcat(tmpbuf, ", "); - } - } - return tmpbuf; -} - -struct opvar * -set_opvar_int(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_INT; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_coord(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_COORD; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_region(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_REGION; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_mapchar(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_MAPCHAR; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_monst(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_MONST; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_obj(ov, val) -struct opvar *ov; -long val; -{ - if (ov) { - ov->spovartyp = SPOVAR_OBJ; - ov->vardata.l = val; - } - return ov; -} - -struct opvar * -set_opvar_str(ov, val) -struct opvar *ov; -const char *val; -{ - if (ov) { - ov->spovartyp = SPOVAR_STRING; - ov->vardata.str = (val) ? strdup(val) : NULL; - } - return ov; -} - -struct opvar * -set_opvar_var(ov, val) -struct opvar *ov; -const char *val; -{ - if (ov) { - ov->spovartyp = SPOVAR_VARIABLE; - ov->vardata.str = (val) ? strdup(val) : NULL; - } - return ov; -} - -#define New(type) \ - (type *) memset((genericptr_t) alloc(sizeof(type)), 0, sizeof(type)) - -#if defined(USE_STDARG) || defined(USE_VARARGS) -static void FDECL(vadd_opvars, (sp_lev *, const char *, va_list)); - -void add_opvars -VA_DECL2(sp_lev *, sp, const char *, fmt) -{ - VA_START(fmt); - VA_INIT(fmt, char *); - vadd_opvars(sp, fmt, VA_ARGS); - VA_END(); -} - -#ifdef USE_STDARG -static void -vadd_opvars(sp_lev *sp, const char *fmt, va_list the_args) - -#else -static void -vadd_opvars(sp, fmt, the_args) -sp_lev *sp; -const char *fmt; -va_list the_args; - -#endif - -#else /* USE_STDARG | USE_VARARG */ - -#define vadd_opvars add_opvars - -void add_opvars -VA_DECL2(sp_lev *, sp, const char *, fmt) -#endif /* USE_STDARG | USE_VARARG */ -{ - const char *p, *lp; - long la; - /* Do NOT use VA_START and VA_END in here... see above */ - - for (p = fmt; *p != '\0'; p++) { - switch (*p) { - case ' ': - break; - case 'i': /* integer (via plain 'int') */ - { - struct opvar *ov = New(struct opvar); - - set_opvar_int(ov, (long) VA_NEXT(la, int)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'l': /* integer (via 'long int') */ - { - struct opvar *ov = New(struct opvar); - - set_opvar_int(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'c': /* coordinate */ - { - struct opvar *ov = New(struct opvar); - set_opvar_coord(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'r': /* region */ - { - struct opvar *ov = New(struct opvar); - set_opvar_region(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'm': /* mapchar */ - { - struct opvar *ov = New(struct opvar); - set_opvar_mapchar(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'M': /* monster */ - { - struct opvar *ov = New(struct opvar); - set_opvar_monst(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'O': /* object */ - { - struct opvar *ov = New(struct opvar); - set_opvar_obj(ov, VA_NEXT(la, long)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 's': /* string */ - { - struct opvar *ov = New(struct opvar); - set_opvar_str(ov, VA_NEXT(lp, const char *)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'v': /* variable */ - { - struct opvar *ov = New(struct opvar); - set_opvar_var(ov, VA_NEXT(lp, const char *)); - add_opcode(sp, SPO_PUSH, ov); - break; - } - case 'o': /* opcode */ - { - long i = VA_NEXT(la, int); - if (i < 0 || i >= MAX_SP_OPCODES) - lc_pline("add_opvars: unknown opcode '%ld'.", VA_PASS1(i)); - add_opcode(sp, i, NULL); - break; - } - default: - lc_pline("add_opvars: illegal format character '%ld'.", - VA_PASS1((long) *p)); - break; - } - } - -#if !(defined(USE_STDARG) || defined(USE_VARARGS)) - /* provide closing brace for USE_OLDARGS nested block from VA_DECL2() */ - VA_END(); -#endif -} - -void -break_stmt_start() -{ - allow_break_statements++; -} - -void -break_stmt_end(splev) -sp_lev *splev; -{ - struct lc_breakdef *tmp = break_list; - struct lc_breakdef *prv = NULL; - - while (tmp) { - if (tmp->break_depth == allow_break_statements) { - struct lc_breakdef *nxt = tmp->next; - set_opvar_int(tmp->breakpoint, - splev->n_opcodes - tmp->breakpoint->vardata.l - 1); - tmp->next = NULL; - Free(tmp); - if (!prv) - break_list = NULL; - else - prv->next = nxt; - tmp = nxt; - } else { - prv = tmp; - tmp = tmp->next; - } - } - allow_break_statements--; -} - -void -break_stmt_new(splev, i) -sp_lev *splev; -long i; -{ - struct lc_breakdef *tmp = New(struct lc_breakdef); - - tmp->breakpoint = New(struct opvar); - tmp->break_depth = allow_break_statements; - tmp->next = break_list; - break_list = tmp; - set_opvar_int(tmp->breakpoint, i); - add_opcode(splev, SPO_PUSH, tmp->breakpoint); - add_opcode(splev, SPO_JMP, NULL); -} - -struct lc_funcdefs * -funcdef_new(addr, name) -long addr; -char *name; -{ - struct lc_funcdefs *f = New(struct lc_funcdefs); - - if (!f) { - lc_error("Could not alloc function definition for '%s'.", - VA_PASS1(name)); - return NULL; - } - f->next = NULL; - f->addr = addr; - f->name = strdup(name); - f->n_called = 0; - f->n_params = 0; - f->params = NULL; - f->code.opcodes = NULL; - f->code.n_opcodes = 0; - return f; -} - -void -funcdef_free_all(fchain) -struct lc_funcdefs *fchain; -{ - struct lc_funcdefs *tmp = fchain; - struct lc_funcdefs *nxt; - struct lc_funcdefs_parm *tmpparam; - - while (tmp) { - nxt = tmp->next; - Free(tmp->name); - while (tmp->params) { - tmpparam = tmp->params->next; - Free(tmp->params->name); - tmp->params = tmpparam; - } - /* FIXME: free tmp->code */ - Free(tmp); - tmp = nxt; - } -} - -char * -funcdef_paramtypes(f) -struct lc_funcdefs *f; -{ - int i = 0; - struct lc_funcdefs_parm *fp = f->params; - char *tmp = (char *) alloc((f->n_params) + 1); - - if (!tmp) - return NULL; - while (fp) { - tmp[i++] = fp->parmtype; - fp = fp->next; - } - tmp[i] = '\0'; - return tmp; -} - -struct lc_funcdefs * -funcdef_defined(f, name, casesense) -struct lc_funcdefs *f; -char *name; -int casesense; -{ - while (f) { - if (casesense) { - if (!strcmp(name, f->name)) - return f; - } else { - if (!case_insensitive_comp(name, f->name)) - return f; - } - f = f->next; - } - return NULL; -} - -struct lc_vardefs * -vardef_new(typ, name) -long typ; -char *name; -{ - struct lc_vardefs *f = New(struct lc_vardefs); - - if (!f) { - lc_error("Could not alloc variable definition for '%s'.", - VA_PASS1(name)); - return NULL; - } - f->next = NULL; - f->var_type = typ; - f->name = strdup(name); - f->n_used = 0; - return f; -} - -void -vardef_free_all(fchain) -struct lc_vardefs *fchain; -{ - struct lc_vardefs *tmp = fchain; - struct lc_vardefs *nxt; - - while (tmp) { - if (be_verbose && (tmp->n_used == 0)) - lc_warning("Unused variable '%s'", VA_PASS1(tmp->name)); - nxt = tmp->next; - Free(tmp->name); - Free(tmp); - tmp = nxt; - } -} - -struct lc_vardefs * -vardef_defined(f, name, casesense) -struct lc_vardefs *f; -char *name; -int casesense; -{ - while (f) { - if (casesense) { - if (!strcmp(name, f->name)) - return f; - } else { - if (!case_insensitive_comp(name, f->name)) - return f; - } - f = f->next; - } - return NULL; -} - -const char * -spovar2str(spovar) -long spovar; -{ - static int togl = 0; - static char buf[2][128]; - const char *n = NULL; - int is_array = (spovar & SPOVAR_ARRAY); - - spovar &= ~SPOVAR_ARRAY; - switch (spovar) { - default: - lc_error("spovar2str(%ld)", VA_PASS1(spovar)); - break; - case SPOVAR_INT: - n = "integer"; - break; - case SPOVAR_STRING: - n = "string"; - break; - case SPOVAR_VARIABLE: - n = "variable"; - break; - case SPOVAR_COORD: - n = "coordinate"; - break; - case SPOVAR_REGION: - n = "region"; - break; - case SPOVAR_MAPCHAR: - n = "mapchar"; - break; - case SPOVAR_MONST: - n = "monster"; - break; - case SPOVAR_OBJ: - n = "object"; - break; - } - - togl = ((togl + 1) % 2); - - Sprintf(buf[togl], "%s%s", n, (is_array ? " array" : "")); - return buf[togl]; -} - -void -vardef_used(vd, varname) -struct lc_vardefs *vd; -char *varname; -{ - struct lc_vardefs *tmp; - - if ((tmp = vardef_defined(vd, varname, 1)) != 0) - tmp->n_used++; -} - -void -check_vardef_type(vd, varname, vartype) -struct lc_vardefs *vd; -char *varname; -long vartype; -{ - struct lc_vardefs *tmp; - - if ((tmp = vardef_defined(vd, varname, 1)) != 0) { - if (tmp->var_type != vartype) - lc_error("Trying to use variable '%s' as %s, when it is %s.", - VA_PASS3(varname, - spovar2str(vartype), - spovar2str(tmp->var_type))); - } else - lc_error("Variable '%s' not defined.", VA_PASS1(varname)); -} - -struct lc_vardefs * -add_vardef_type(vd, varname, vartype) -struct lc_vardefs *vd; -char *varname; -long vartype; -{ - struct lc_vardefs *tmp; - - if ((tmp = vardef_defined(vd, varname, 1)) != 0) { - if (tmp->var_type != vartype) - lc_error("Trying to redefine variable '%s' as %s, when it is %s.", - VA_PASS3(varname, - spovar2str(vartype), - spovar2str(tmp->var_type))); - } else { - tmp = vardef_new(vartype, varname); - tmp->next = vd; - return tmp; - } - return vd; -} - -int -reverse_jmp_opcode(opcode) -int opcode; -{ - switch (opcode) { - case SPO_JE: - return SPO_JNE; - case SPO_JNE: - return SPO_JE; - case SPO_JL: - return SPO_JGE; - case SPO_JG: - return SPO_JLE; - case SPO_JLE: - return SPO_JG; - case SPO_JGE: - return SPO_JL; - default: - lc_error("Cannot reverse comparison jmp opcode %ld.", - VA_PASS1((long) opcode)); - return SPO_NULL; - } -} - -/* basically copied from src/sp_lev.c */ -struct opvar * -opvar_clone(ov) -struct opvar *ov; -{ - if (ov) { - struct opvar *tmpov = (struct opvar *) alloc(sizeof(struct opvar)); - - if (!tmpov) { /* lint suppression */ - /*NOTREACHED*/ -#if 0 - /* not possible; alloc() never returns Null */ - panic("could not alloc opvar struct"); - /*NOTREACHED*/ -#endif - return (struct opvar *) 0; - } - switch (ov->spovartyp) { - case SPOVAR_COORD: - case SPOVAR_REGION: - case SPOVAR_MAPCHAR: - case SPOVAR_MONST: - case SPOVAR_OBJ: - case SPOVAR_INT: { - tmpov->spovartyp = ov->spovartyp; - tmpov->vardata.l = ov->vardata.l; - } break; - case SPOVAR_VARIABLE: - case SPOVAR_STRING: { - int len = strlen(ov->vardata.str); - tmpov->spovartyp = ov->spovartyp; - tmpov->vardata.str = (char *) alloc(len + 1); - (void) memcpy((genericptr_t) tmpov->vardata.str, - (genericptr_t) ov->vardata.str, len); - tmpov->vardata.str[len] = '\0'; - } break; - default: { - lc_error("Unknown opvar_clone value type (%ld)!", - VA_PASS1((long) ov->spovartyp)); - } /* default */ - } /* switch */ - return tmpov; - } - return (struct opvar *) 0; -} - -void -splev_add_from(splev, from_splev) -sp_lev *splev; -sp_lev *from_splev; -{ - int i; - - if (splev && from_splev) - for (i = 0; i < from_splev->n_opcodes; i++) - add_opcode(splev, from_splev->opcodes[i].opcode, - opvar_clone(from_splev->opcodes[i].opdat)); -} - -void -start_level_def(splev, ldfname) -sp_lev **splev; -char *ldfname; -{ - struct lc_funcdefs *f; - - if (index(ldfname, '.')) - lc_error("Invalid dot ('.') in level name '%s'.", VA_PASS1(ldfname)); - if ((int) strlen(ldfname) > 14) - lc_error("Level names limited to 14 characters ('%s').", - VA_PASS1(ldfname)); - f = function_definitions; - while (f) { - f->n_called = 0; - f = f->next; - } - *splev = (sp_lev *) alloc(sizeof(sp_lev)); - (*splev)->n_opcodes = 0; - (*splev)->opcodes = NULL; - - vardef_free_all(vardefs); - vardefs = NULL; -} - -/* - * Find the type of floor, knowing its char representation. - */ -int -get_floor_type(c) -char c; -{ - int val; - - SpinCursor(3); - val = what_map_char(c); - if (val == INVALID_TYPE) { - val = ERR; - yywarning("Invalid fill character in MAZE declaration"); - } - return val; -} - -/* - * Find the type of a room in the table, knowing its name. - */ -int -get_room_type(s) -char *s; -{ - register int i; - - SpinCursor(3); - for (i = 0; room_types[i].name; i++) - if (!strcmp(s, room_types[i].name)) - return ((int) room_types[i].type); - return ERR; -} - -/* - * Find the type of a trap in the table, knowing its name. - */ -int -get_trap_type(s) -char *s; -{ - register int i; - - SpinCursor(3); - for (i = 0; trap_types[i].name; i++) - if (!strcmp(s, trap_types[i].name)) - return trap_types[i].type; - return ERR; -} - -/* - * Find the index of a monster in the table, knowing its name. - */ -int -get_monster_id(s, c) -char *s; -char c; -{ - register int i, class; - - SpinCursor(3); - class = c ? def_char_to_monclass(c) : 0; - if (class == MAXMCLASSES) - return ERR; - - for (i = LOW_PM; i < NUMMONS; i++) - if (!class || class == mons[i].mlet) - if (!strcmp(s, mons[i].mname)) - return i; - /* didn't find it; lets try case insensitive search */ - for (i = LOW_PM; i < NUMMONS; i++) - if (!class || class == mons[i].mlet) - if (!case_insensitive_comp(s, mons[i].mname)) { - if (be_verbose) - lc_warning("Monster type \"%s\" matches \"%s\".", - VA_PASS2(s, mons[i].mname)); - return i; - } - return ERR; -} - -/* - * Find the index of an object in the table, knowing its name. - */ -int -get_object_id(s, c) -char *s; -char c; /* class */ -{ - int i, class; - const char *objname; - - SpinCursor(3); - class = (c > 0) ? def_char_to_objclass(c) : 0; - if (class == MAXOCLASSES) - return ERR; - - for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) { - if (class && objects[i].oc_class != class) - break; - objname = obj_descr[i].oc_name; - if (objname && !strcmp(s, objname)) - return i; - } - for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) { - if (class && objects[i].oc_class != class) - break; - objname = obj_descr[i].oc_name; - if (objname && !case_insensitive_comp(s, objname)) { - if (be_verbose) - lc_warning("Object type \"%s\" matches \"%s\".", - VA_PASS2(s, objname)); - return i; - } - } - return ERR; -} - -static void -init_obj_classes() -{ - int i, class, prev_class; - - prev_class = -1; - for (i = 0; i < NUM_OBJECTS; i++) { - class = objects[i].oc_class; - if (class != prev_class) { - bases[class] = i; - prev_class = class; - } - } -} - -/* - * Is the character 'c' a valid monster class ? - */ -boolean -check_monster_char(c) -char c; -{ - return (def_char_to_monclass(c) != MAXMCLASSES); -} - -/* - * Is the character 'c' a valid object class ? - */ -boolean -check_object_char(c) -char c; -{ - return (def_char_to_objclass(c) != MAXOCLASSES); -} - -/* - * Convert .des map letter into floor type. - */ -char -what_map_char(c) -char c; -{ - SpinCursor(3); - switch (c) { - case ' ': - return (STONE); - case '#': - return (CORR); - case '.': - return (ROOM); - case '-': - return (HWALL); - case '|': - return (VWALL); - case '+': - return (DOOR); - case 'A': - return (AIR); - case 'B': - return (CROSSWALL); /* hack: boundary location */ - case 'C': - return (CLOUD); - case 'S': - return (SDOOR); - case 'H': - return (SCORR); - case '{': - return (FOUNTAIN); - case '\\': - return (THRONE); - case 'K': - return (SINK); - case '}': - return (MOAT); - case 'P': - return (POOL); - case 'L': - return (LAVAPOOL); - case 'I': - return (ICE); - case 'W': - return (WATER); - case 'T': - return (TREE); - case 'F': - return (IRONBARS); /* Fe = iron */ - case 'x': - return (MAX_TYPE); /* "see-through" */ - } - return (INVALID_TYPE); -} - -void -add_opcode(sp, opc, dat) -sp_lev *sp; -int opc; -genericptr_t dat; -{ - long nop = sp->n_opcodes; - _opcode *tmp; - - if ((opc < 0) || (opc >= MAX_SP_OPCODES)) - lc_error("Unknown opcode '%ld'", VA_PASS1((long) opc)); - - tmp = (_opcode *) alloc(sizeof(_opcode) * (nop + 1)); - if (!tmp) { /* lint suppression */ - /*NOTREACHED*/ -#if 0 - /* not possible; alloc() never returns Null */ - lc_error("%s", VA_PASS1("Could not alloc opcode space")); -#endif - return; - } - - if (sp->opcodes && nop) { - (void) memcpy(tmp, sp->opcodes, sizeof(_opcode) * nop); - free(sp->opcodes); - } - sp->opcodes = tmp; - - sp->opcodes[nop].opcode = opc; - sp->opcodes[nop].opdat = dat; - - sp->n_opcodes++; -} - -/* - * Yep! LEX gives us the map in a raw mode. - * Just analyze it here. - */ -void -scan_map(map, sp) -char *map; -sp_lev *sp; -{ - register int i, len; - register char *s1, *s2; - int max_len = 0; - int max_hig = 0; - char *tmpmap[MAP_Y_LIM+1]; - int dx, dy; - char *mbuf; - - /* First, strip out digits 0-9 (line numbering) */ - for (s1 = s2 = map; *s1; s1++) - if (*s1 < '0' || *s1 > '9') - *s2++ = *s1; - *s2 = '\0'; - - /* Second, find the max width of the map */ - s1 = map; - while (s1 && *s1) { - s2 = index(s1, '\n'); - if (s2) { - len = (int) (s2 - s1); - s1 = s2 + 1; - } else { - len = (int) strlen(s1); - s1 = (char *) 0; - } - if (len > max_len) - max_len = len; - } - - /* Then parse it now */ - while (map && *map) { - if (max_hig > MAP_Y_LIM) - break; - tmpmap[max_hig] = (char *) alloc(max_len); - s1 = index(map, '\n'); - if (s1) { - len = (int) (s1 - map); - s1++; - } else { - len = (int) strlen(map); - s1 = map + len; - } - for (i = 0; i < len; i++) - if ((tmpmap[max_hig][i] = what_map_char(map[i])) - == INVALID_TYPE) { - lc_warning( - "Invalid character '%ld' @ (%ld, %ld) - replacing with stone", - VA_PASS3((long) map[i], (long) max_hig, (long) i)); - tmpmap[max_hig][i] = STONE; - } - while (i < max_len) - tmpmap[max_hig][i++] = STONE; - map = s1; - max_hig++; - } - - /* Memorize boundaries */ - - max_x_map = max_len - 1; - max_y_map = max_hig - 1; - - if (max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) { - lc_error("Map too large at (%ld x %ld), max is (%ld x %ld)", - VA_PASS4((long) max_len, (long) max_hig, - (long) MAP_X_LIM, (long) MAP_Y_LIM)); - } - - mbuf = (char *) alloc(((max_hig - 1) * max_len) + (max_len - 1) + 2); - for (dy = 0; dy < max_hig; dy++) - for (dx = 0; dx < max_len; dx++) - mbuf[(dy * max_len) + dx] = (tmpmap[dy][dx] + 1); - - mbuf[((max_hig - 1) * max_len) + (max_len - 1) + 1] = '\0'; - - add_opvars(sp, "sllo", VA_PASS4(mbuf, (long) max_hig, (long) max_len, - SPO_MAP)); - - for (dy = 0; dy < max_hig; dy++) - Free(tmpmap[dy]); - Free(mbuf); -} - -/* - * Output some info common to all special levels. - */ -static boolean -write_common_data(fd) -int fd; -{ - static struct version_info version_data = { - VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, - VERSION_SANITY3 - }; - - Write(fd, &version_data, sizeof version_data); - return TRUE; -} - -/* - * Here we write the sp_lev structure in the specified file (fd). - * Also, we have to free the memory allocated via alloc(). - */ -static boolean -write_maze(fd, maze) -int fd; -sp_lev *maze; -{ - int i; - - if (!write_common_data(fd)) - return FALSE; - - Write(fd, &(maze->n_opcodes), sizeof(maze->n_opcodes)); - - for (i = 0; i < maze->n_opcodes; i++) { - _opcode tmpo = maze->opcodes[i]; - - Write(fd, &(tmpo.opcode), sizeof(tmpo.opcode)); - - if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES) - panic("write_maze: unknown opcode (%d).", tmpo.opcode); - - if (tmpo.opcode == SPO_PUSH) { - genericptr_t opdat = tmpo.opdat; - if (opdat) { - struct opvar *ov = (struct opvar *) opdat; - int size; - Write(fd, &(ov->spovartyp), sizeof(ov->spovartyp)); - switch (ov->spovartyp) { - case SPOVAR_NULL: - break; - case SPOVAR_COORD: - case SPOVAR_REGION: - case SPOVAR_MAPCHAR: - case SPOVAR_MONST: - case SPOVAR_OBJ: - case SPOVAR_INT: - Write(fd, &(ov->vardata.l), sizeof(ov->vardata.l)); - break; - case SPOVAR_VARIABLE: - case SPOVAR_STRING: - if (ov->vardata.str) - size = strlen(ov->vardata.str); - else - size = 0; - Write(fd, &size, sizeof(size)); - if (size) { - Write(fd, ov->vardata.str, size); - Free(ov->vardata.str); - } - break; - default: - panic("write_maze: unknown data type (%d).", - ov->spovartyp); - } - } else - panic("write_maze: PUSH with no data."); - } else { - /* sanity check */ - genericptr_t opdat = tmpo.opdat; - if (opdat) - panic("write_maze: opcode (%d) has data.", tmpo.opcode); - } - - Free(tmpo.opdat); - } - /* clear the struct for next user */ - Free(maze->opcodes); - maze->opcodes = NULL; - /*(void) memset((genericptr_t) &maze->init_lev, 0, sizeof - * maze->init_lev);*/ - - return TRUE; -} - -/* - * Open and write maze or rooms file, based on which pointer is non-null. - * Return TRUE on success, FALSE on failure. - */ -boolean -write_level_file(filename, lvl) -char *filename; -sp_lev *lvl; -{ - int fout; - char lbuf[60]; - - lbuf[0] = '\0'; -#ifdef PREFIX - Strcat(lbuf, PREFIX); -#endif - Strcat(lbuf, filename); - Strcat(lbuf, LEV_EXT); - -#if defined(MAC) && (defined(__SC__) || defined(__MRC__)) - fout = open(lbuf, O_WRONLY | O_CREAT | O_BINARY); -#else - fout = open(lbuf, O_WRONLY | O_CREAT | O_BINARY, OMASK); -#endif - if (fout < 0) - return FALSE; - - if (!lvl) - panic("write_level_file"); - - if (be_verbose) - fprintf(stdout, "File: '%s', opcodes: %ld\n", lbuf, lvl->n_opcodes); - - if (!write_maze(fout, lvl)) - return FALSE; - - (void) close(fout); - - return TRUE; -} - -static int -case_insensitive_comp(s1, s2) -const char *s1; -const char *s2; -{ - uchar u1, u2; - - for (;; s1++, s2++) { - u1 = (uchar) *s1; - if (isupper(u1)) - u1 = tolower(u1); - u2 = (uchar) *s2; - if (isupper(u2)) - u2 = tolower(u2); - if (u1 == '\0' || u1 != u2) - break; - } - return u1 - u2; -} - -#ifdef STRICT_REF_DEF -/* - * Any globals declared in hack.h and descendents which aren't defined - * in the modules linked into lev_comp should be defined here. These - * definitions can be dummies: their sizes shouldn't matter as long as - * as their types are correct; actual values are irrelevant. - */ -#define ARBITRARY_SIZE 1 -/* attrib.c */ -struct attribs attrmax, attrmin; -/* files.c */ -const char *configfile; -char lock[ARBITRARY_SIZE]; -char SAVEF[ARBITRARY_SIZE]; -#ifdef MICRO -char SAVEP[ARBITRARY_SIZE]; -#endif -/* termcap.c */ -struct tc_lcl_data tc_lcl_data; -#ifdef TEXTCOLOR -#ifdef TOS -const char *hilites[CLR_MAX]; -#else -char NEARDATA *hilites[CLR_MAX]; -#endif -#endif -/* trap.c */ -const char *traps[TRAPNUM]; -/* window.c */ -#ifdef HANGUPHANDLING -volatile -#endif - struct window_procs windowprocs; -/* xxxtty.c */ -#ifdef DEFINE_OSPEED -short ospeed; -#endif -#endif /* STRICT_REF_DEF */ - -/*lev_main.c*/ From f489eb96a3c04876c9f7f5d27aca27c6be18e7d6 Mon Sep 17 00:00:00 2001 From: Stephen Oman Date: Fri, 12 Jun 2026 15:08:23 +0100 Subject: [PATCH 2/3] Add nh5 util files - no NLE mods --- util/dlb_main.c | 128 ++- util/mdgrep.h | 261 +++--- util/mdgrep.pl | 51 +- util/panic.c | 18 +- util/recover.c | 203 +++-- util/sfctool.c | 1280 ++++++++++++++++++++++++++ util/sfexpasc.c | 1296 +++++++++++++++++++++++++++ util/sftags.c | 2285 +++++++++++++++++++++++++++++++++++++++++++++++ util/stripbs.c | 48 + 9 files changed, 5267 insertions(+), 303 deletions(-) create mode 100644 util/sfctool.c create mode 100644 util/sfexpasc.c create mode 100644 util/sftags.c create mode 100644 util/stripbs.c diff --git a/util/dlb_main.c b/util/dlb_main.c index 120de616c..a77277eea 100644 --- a/util/dlb_main.c +++ b/util/dlb_main.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dlb_main.c $NHDT-Date: 1570258542 2019/10/05 06:55:42 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 5.0 dlb_main.c $NHDT-Date: 1706213798 2024/01/25 20:16:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7,33 +7,34 @@ #include "config.h" #include "dlb.h" -#if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C) +#include "hacklib.h" + +#if !defined(O_WRONLY) && !defined(MACOS9) && !defined(AZTEC_C) #include #endif #if defined(__DJGPP__) #include #endif -static void FDECL(grow_ld, (libdir **, int *, int)); -static void FDECL(xexit, (int)) NORETURN; +ATTRNORETURN static void xexit(int) NORETURN; +ATTRNORETURN extern void panic(const char *, ...) NORETURN; +FILE *fopen_datafile(const char *, const char *, int); #ifdef DLB #ifdef DLBLIB +static void grow_ld(libdir **, int *, int); #define DLB_DIRECTORY "Directory" /* name of lib directory */ #define LIBLISTFILE "dlb.lst" /* default list file */ /* library functions (from dlb.c) */ -extern boolean FDECL(open_library, (const char *, library *)); -extern void FDECL(close_library, (library *)); - -char *FDECL(eos, (char *)); /* also used by dlb.c */ -FILE *FDECL(fopen_datafile, (const char *, const char *)); +extern boolean open_library(const char *, library *); +extern void close_library(library *); -static void FDECL(Write, (int, char *, long)); -static void NDECL(usage) NORETURN; -static void NDECL(verbose_help) NORETURN; -static void FDECL(write_dlb_directory, (int, int, libdir *, long, long, long)); +static void Write(int, char *, long); +ATTRNORETURN static void usage(void) NORETURN; +ATTRNORETURN static void verbose_help(void) NORETURN; +static void write_dlb_directory(int, int, libdir *, long, long, long); static char default_progname[] = "dlb"; static char *progname = default_progname; @@ -66,18 +67,18 @@ static char origdir[255] = ""; * * dlb COMMANDoptions arg... files... * commands: - * dlb x extract all files - * dlb c build the archive - * dlb t list the archive + * dlb x extract all files + * dlb c build the archive + * dlb t list the archive * options: - * v verbose - * f file specify archive file (default DLBFILE) - * I file specify file for list of files (default LIBLISTFILE) - * C dir chdir to dir (used ONCE, not like tar's -C) + * v verbose + * f file specify archive file (default DLBFILE) + * I file specify file for list of files (default LIBLISTFILE) + * C dir chdir to dir (used ONCE, not like tar's -C) */ -static void -usage() +ATTRNORETURN static void +usage(void) { (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname); (void) printf(" default library is %s\n", library_file); @@ -86,8 +87,8 @@ usage() /*NOTREACHED*/ } -static void -verbose_help() +ATTRNORETURN static void +verbose_help(void) { static const char *const long_help[] = { "", "dlb COMMANDoptions args... files...", " commands:", @@ -109,10 +110,7 @@ verbose_help() } static void -Write(out, buf, len) -int out; -char *buf; -long len; +Write(int out, char *buf, long len) { #if defined(MSDOS) && !defined(__DJGPP__) unsigned short slen; @@ -131,31 +129,26 @@ long len; xexit(EXIT_FAILURE); } } - -char * -eos(s) -char *s; -{ - while (*s) - s++; - return s; -} +#endif /* DLBLIB */ +#endif /* DLB */ /* open_library(dlb.c) needs this (which normally comes from src/files.c) */ FILE * -fopen_datafile(filename, mode) -const char *filename, *mode; +fopen_datafile(const char *filename, const char *mode, int prefix UNUSED) { return fopen(filename, mode); } -#endif /* DLBLIB */ -#endif /* DLB */ +#ifdef DLB +#define UNUSED_if_no_DLB /*empty*/ +#else +#define UNUSED_if_no_DLB UNUSED +#endif + +DISABLE_WARNING_UNREACHABLE_CODE int -main(argc, argv) -int argc; -char **argv; +main(int argc UNUSED_if_no_DLB, char **argv UNUSED_if_no_DLB) { #ifdef DLB #ifdef DLBLIB @@ -166,10 +159,12 @@ char **argv; char action = ' '; library lib; - if (argc > 0 && argv[0] && *argv[0]) + if (argc > 0) progname = argv[0]; + if (!progname || !*progname) + progname = default_progname; #ifdef VMS - progname = vms_basename(progname); + progname = vms_basename(progname, FALSE); #endif if (argc < 2) { @@ -316,9 +311,9 @@ char **argv; if (remainder > (long) sizeof(buf)) r = (int) sizeof(buf); else - r = remainder; + r = (int) remainder; - n = fread(buf, 1, r, lib.fdata); + n = (int) fread(buf, 1, r, lib.fdata); if (n != r) { printf("Read Error in '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); @@ -363,8 +358,7 @@ char **argv; for (; ap < argc; ap++, nfiles++) { if (nfiles == ldlimit) grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5); - ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1); - Strcpy(ld[nfiles].fname, argv[ap]); + ld[nfiles].fname = dupstr(argv[ap]); } } @@ -381,8 +375,7 @@ char **argv; if (nfiles == ldlimit) grow_ld(&ld, &ldlimit, DLB_FILES_ALLOC / 5); *(eos(buf) - 1) = '\0'; /* strip newline */ - ld[nfiles].fname = (char *) alloc(strlen(buf) + 1); - Strcpy(ld[nfiles].fname, buf); + ld[nfiles].fname = dupstr(buf); } fclose(list); } @@ -405,7 +398,7 @@ char **argv; ld[i].fsize = lseek(fd, 0, SEEK_END); ld[i].foffset = flen; - slen += strlen(ld[i].fname); /* don't add null (yet) */ + slen += (long) strlen(ld[i].fname); /* don't add null (yet) */ flen += ld[i].fsize; close(fd); } @@ -418,10 +411,10 @@ char **argv; xexit(EXIT_FAILURE); } - /* caculate directory size */ + /* calculate directory size */ dir_size = 40 /* header line (see below) */ + ((nfiles + 1) * 11) /* handling+file offset+SP+newline */ - + slen + strlen(DLB_DIRECTORY); /* file names */ + + slen + (long) strlen(DLB_DIRECTORY); /* file names */ /* write directory */ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen); @@ -438,7 +431,7 @@ char **argv; printf("%s\n", ld[i].fname); fsiz = 0L; - while ((r = read(fd, buf, sizeof buf)) != 0) { + while ((r = (int) read(fd, buf, sizeof buf)) != 0) { if (r == -1) { printf("Read Error in '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); @@ -482,14 +475,13 @@ char **argv; return 0; } +RESTORE_WARNING_UNREACHABLE_CODE + #ifdef DLB #ifdef DLBLIB static void -grow_ld(ld_p, ldlimit_p, alloc_incr) -libdir **ld_p; -int *ldlimit_p; -int alloc_incr; +grow_ld(libdir **ld_p, int *ldlimit_p, int alloc_incr) { static libdir zerolibdir; int i = 0, newlimit = *ldlimit_p + alloc_incr; @@ -506,10 +498,8 @@ int alloc_incr; } static void -write_dlb_directory(out, nfiles, ld, slen, dir_size, flen) -int out, nfiles; -libdir *ld; -long slen, dir_size, flen; +write_dlb_directory(int out, int nfiles, libdir *ld, + long slen, long dir_size, long flen) { char buf[BUFSIZ]; int i; @@ -538,9 +528,8 @@ long slen, dir_size, flen; #endif /* DLBLIB */ #endif /* DLB */ -static void -xexit(retcd) -int retcd; +ATTRNORETURN static void +xexit(int retcd) { #ifdef DLB #ifdef AMIGA @@ -552,9 +541,4 @@ int retcd; /*NOTREACHED*/ } -#ifdef AMIGA -#include "date.h" -const char amiga_version_string[] = AMIGA_VERSION_STRING; -#endif - /*dlb_main.c*/ diff --git a/util/mdgrep.h b/util/mdgrep.h index 382da338c..1b64de3db 100644 --- a/util/mdgrep.h +++ b/util/mdgrep.h @@ -1,282 +1,295 @@ /* - * NetHack 3.6 mdgrep.h $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ + * NetHack 5.0 mdgrep.h $NHDT-Date: 1710949914 2024/03/20 15:51:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ * Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008 * NetHack may be freely redistributed. See license for details. * - * This file generated by mdgrep.pl version 1.7. + * This file generated by mdgrep.pl version 1.24. * DO NOT EDIT! Your changes will be lost. */ -static struct grep_var grep_vars[] = { { "0", 0 }, - { "1", 1 }, + +static struct grep_var grep_vars[]={ + {"0", 0}, + {"1", 1}, #if defined(ALLDOCS) - { "ALLDOCS", 1 }, + {"ALLDOCS", 1}, #else - { "ALLDOCS", 0 }, + {"ALLDOCS", 0}, #endif #if defined(AMIGA) - { "AMIGA", 1 }, + {"AMIGA", 1}, #else - { "AMIGA", 0 }, + {"AMIGA", 0}, #endif #if defined(AMII_GRAPHICS) - { "AMII_GRAPHICS", 1 }, + {"AMII_GRAPHICS", 1}, #else - { "AMII_GRAPHICS", 0 }, + {"AMII_GRAPHICS", 0}, #endif #if defined(ASCIIGRAPH) - { "ASCIIGRAPH", 1 }, -#else - { "ASCIIGRAPH", 0 }, -#endif -#if defined(BETA) - { "BETA", 1 }, + {"ASCIIGRAPH", 1}, #else - { "BETA", 0 }, + {"ASCIIGRAPH", 0}, #endif #if defined(BSD_JOB_CONTROL) - { "BSD_JOB_CONTROL", 1 }, + {"BSD_JOB_CONTROL", 1}, #else - { "BSD_JOB_CONTROL", 0 }, + {"BSD_JOB_CONTROL", 0}, #endif #if defined(CLIPPING) - { "CLIPPING", 1 }, + {"CLIPPING", 1}, #else - { "CLIPPING", 0 }, + {"CLIPPING", 0}, #endif #if defined(COMPRESS) - { "COMPRESS", 1 }, + {"COMPRESS", 1}, +#else + {"COMPRESS", 0}, +#endif +#if defined(CRASHREPORT) + {"CRASHREPORT", 1}, #else - { "COMPRESS", 0 }, + {"CRASHREPORT", 0}, +#endif +#if defined(CROSSCOMPILE) + {"CROSSCOMPILE", 1}, +#else + {"CROSSCOMPILE", 0}, #endif #if defined(DLB) - { "DLB", 1 }, + {"DLB", 1}, #else - { "DLB", 0 }, + {"DLB", 0}, #endif - { "FALSE", 0 }, + {"FALSE", 0}, #if defined(GEM_GRAPHICS) - { "GEM_GRAPHICS", 1 }, + {"GEM_GRAPHICS", 1}, #else - { "GEM_GRAPHICS", 0 }, + {"GEM_GRAPHICS", 0}, #endif #if defined(GNOME_GRAPHICS) - { "GNOME_GRAPHICS", 1 }, + {"GNOME_GRAPHICS", 1}, #else - { "GNOME_GRAPHICS", 0 }, + {"GNOME_GRAPHICS", 0}, #endif #if defined(HANGUPHANDLING) - { "HANGUPHANDLING", 1 }, + {"HANGUPHANDLING", 1}, #else - { "HANGUPHANDLING", 0 }, + {"HANGUPHANDLING", 0}, #endif #if defined(INSURANCE) - { "INSURANCE", 1 }, -#else - { "INSURANCE", 0 }, -#endif -#if defined(LIFE) - { "LIFE", 1 }, + {"INSURANCE", 1}, #else - { "LIFE", 0 }, + {"INSURANCE", 0}, #endif #if defined(MAC) - { "MAC", 1 }, + {"MAC", 1}, #else - { "MAC", 0 }, + {"MAC", 0}, #endif #if defined(MAC_GRAPHICS) - { "MAC_GRAPHICS", 1 }, + {"MAC_GRAPHICS", 1}, #else - { "MAC_GRAPHICS", 0 }, + {"MAC_GRAPHICS", 0}, #endif #if defined(MAIL) - { "MAIL", 1 }, + {"MAIL", 1}, #else - { "MAIL", 0 }, + {"MAIL", 0}, #endif #if defined(MFLOPPY) - { "MFLOPPY", 1 }, + {"MFLOPPY", 1}, #else - { "MFLOPPY", 0 }, + {"MFLOPPY", 0}, #endif #if defined(MSDOS) - { "MSDOS", 1 }, + {"MSDOS", 1}, #else - { "MSDOS", 0 }, + {"MSDOS", 0}, #endif #if defined(MSWIN_GRAPHICS) - { "MSWIN_GRAPHICS", 1 }, + {"MSWIN_GRAPHICS", 1}, #else - { "MSWIN_GRAPHICS", 0 }, + {"MSWIN_GRAPHICS", 0}, #endif #if defined(NOCWD_ASSUMPTIONS) - { "NOCWD_ASSUMPTIONS", 1 }, + {"NOCWD_ASSUMPTIONS", 1}, #else - { "NOCWD_ASSUMPTIONS", 0 }, + {"NOCWD_ASSUMPTIONS", 0}, #endif #if defined(NOSAVEONHANGUP) - { "NOSAVEONHANGUP", 1 }, + {"NOSAVEONHANGUP", 1}, #else - { "NOSAVEONHANGUP", 0 }, + {"NOSAVEONHANGUP", 0}, #endif #if defined(OS2) - { "OS2", 1 }, + {"OS2", 1}, #else - { "OS2", 0 }, + {"OS2", 0}, #endif #if defined(POSIX_JOB_CONTROL) - { "POSIX_JOB_CONTROL", 1 }, + {"POSIX_JOB_CONTROL", 1}, #else - { "POSIX_JOB_CONTROL", 0 }, + {"POSIX_JOB_CONTROL", 0}, #endif #if defined(QT_GRAPHICS) - { "QT_GRAPHICS", 1 }, + {"QT_GRAPHICS", 1}, #else - { "QT_GRAPHICS", 0 }, + {"QT_GRAPHICS", 0}, #endif #if defined(RANDOM) - { "RANDOM", 1 }, + {"RANDOM", 1}, #else - { "RANDOM", 0 }, + {"RANDOM", 0}, #endif #if defined(SAFERHANGUP) - { "SAFERHANGUP", 1 }, + {"SAFERHANGUP", 1}, #else - { "SAFERHANGUP", 0 }, + {"SAFERHANGUP", 0}, #endif #if defined(SECURE) - { "SECURE", 1 }, + {"SECURE", 1}, #else - { "SECURE", 0 }, + {"SECURE", 0}, #endif #if defined(SHELL) - { "SHELL", 1 }, + {"SHELL", 1}, #else - { "SHELL", 0 }, + {"SHELL", 0}, #endif #if defined(SUSPEND) - { "SUSPEND", 1 }, + {"SUSPEND", 1}, #else - { "SUSPEND", 0 }, + {"SUSPEND", 0}, #endif -#if defined(TEXTCOLOR) - { "TEXTCOLOR", 1 }, +#if defined(TILES_IN_GLYPHMAP) + {"TILES_IN_GLYPHMAP", 1}, #else - { "TEXTCOLOR", 0 }, + {"TILES_IN_GLYPHMAP", 0}, #endif #if defined(TOS) - { "TOS", 1 }, + {"TOS", 1}, #else - { "TOS", 0 }, + {"TOS", 0}, #endif - { "TRUE", 1 }, + {"TRUE", 1}, #if defined(TTY_GRAPHICS) - { "TTY_GRAPHICS", 1 }, + {"TTY_GRAPHICS", 1}, #else - { "TTY_GRAPHICS", 0 }, + {"TTY_GRAPHICS", 0}, #endif #if defined(UNICODE_DRAWING) - { "UNICODE_DRAWING", 1 }, + {"UNICODE_DRAWING", 1}, #else - { "UNICODE_DRAWING", 0 }, + {"UNICODE_DRAWING", 0}, #endif #if defined(UNICODE_PLAYERTEXT) - { "UNICODE_PLAYERTEXT", 1 }, + {"UNICODE_PLAYERTEXT", 1}, #else - { "UNICODE_PLAYERTEXT", 0 }, + {"UNICODE_PLAYERTEXT", 0}, #endif #if defined(UNICODE_WIDEWINPORT) - { "UNICODE_WIDEWINPORT", 1 }, + {"UNICODE_WIDEWINPORT", 1}, #else - { "UNICODE_WIDEWINPORT", 0 }, + {"UNICODE_WIDEWINPORT", 0}, #endif #if defined(UNIX) - { "UNIX", 1 }, + {"UNIX", 1}, #else - { "UNIX", 0 }, + {"UNIX", 0}, #endif #if defined(USER_SOUNDS) - { "USER_SOUNDS", 1 }, + {"USER_SOUNDS", 1}, #else - { "USER_SOUNDS", 0 }, -#endif -#if defined(USE_TILES) - { "USE_TILES", 1 }, -#else - { "USE_TILES", 0 }, + {"USER_SOUNDS", 0}, #endif #if defined(VAR_PLAYGROUND) - { "VAR_PLAYGROUND", 1 }, + {"VAR_PLAYGROUND", 1}, #else - { "VAR_PLAYGROUND", 0 }, + {"VAR_PLAYGROUND", 0}, #endif #if defined(VMS) - { "VMS", 1 }, + {"VMS", 1}, #else - { "VMS", 0 }, + {"VMS", 0}, #endif #if defined(WIN32) - { "WIN32", 1 }, + {"WIN32", 1}, #else - { "WIN32", 0 }, + {"WIN32", 0}, #endif #if defined(WIN32_PLATFORM_HPCPRO) - { "WIN32_PLATFORM_HPCPRO", 1 }, + {"WIN32_PLATFORM_HPCPRO", 1}, #else - { "WIN32_PLATFORM_HPCPRO", 0 }, + {"WIN32_PLATFORM_HPCPRO", 0}, #endif #if defined(WIN32_PLATFORM_WFSP) - { "WIN32_PLATFORM_WFSP", 1 }, + {"WIN32_PLATFORM_WFSP", 1}, #else - { "WIN32_PLATFORM_WFSP", 0 }, + {"WIN32_PLATFORM_WFSP", 0}, #endif #if defined(WINNT) - { "WINNT", 1 }, + {"WINNT", 1}, #else - { "WINNT", 0 }, + {"WINNT", 0}, #endif #if defined(WIN_CE) - { "WIN_CE", 1 }, + {"WIN_CE", 1}, #else - { "WIN_CE", 0 }, + {"WIN_CE", 0}, #endif #if defined(WIN_CE_POCKETPC) - { "WIN_CE_POCKETPC", 1 }, + {"WIN_CE_POCKETPC", 1}, #else - { "WIN_CE_POCKETPC", 0 }, + {"WIN_CE_POCKETPC", 0}, #endif #if defined(WIN_CE_PS2xx) - { "WIN_CE_PS2xx", 1 }, + {"WIN_CE_PS2xx", 1}, #else - { "WIN_CE_PS2xx", 0 }, + {"WIN_CE_PS2xx", 0}, #endif #if defined(WIN_CE_SMARTPHONE) - { "WIN_CE_SMARTPHONE", 1 }, + {"WIN_CE_SMARTPHONE", 1}, #else - { "WIN_CE_SMARTPHONE", 0 }, + {"WIN_CE_SMARTPHONE", 0}, #endif - { "WIZARD", 1 }, #if defined(X11_GRAPHICS) - { "X11_GRAPHICS", 1 }, + {"X11_GRAPHICS", 1}, #else - { "X11_GRAPHICS", 0 }, + {"X11_GRAPHICS", 0}, #endif #if defined(ZEROCOMP) - { "ZEROCOMP", 1 }, + {"ZEROCOMP", 1}, #else - { "ZEROCOMP", 0 }, + {"ZEROCOMP", 0}, #endif #if defined(ZLIB_COMP) - { "ZLIB_COMP", 1 }, + {"ZLIB_COMP", 1}, #else - { "ZLIB_COMP", 0 }, + {"ZLIB_COMP", 0}, #endif #if defined(__BEOS__) - { "__BEOS__", 1 }, + {"__BEOS__", 1}, +#else + {"__BEOS__", 0}, +#endif + {"NH_DEVEL_STATUS", NH_DEVEL_STATUS}, +#if (NH_DEVEL_STATUS == NH_STATUS_RELEASED) + {"DSNH_STATUS_RELEASED", 1}, +#else + {"DSNH_STATUS_RELEASED", 0}, +#endif +#if (NH_DEVEL_STATUS == NH_STATUS_WIP) + {"DSNH_STATUS_WIP", 1}, +#else + {"DSNH_STATUS_WIP", 0}, +#endif +#if (NH_DEVEL_STATUS == NH_STATUS_BETA) + {"DSNH_STATUS_BETA", 1}, #else - { "__BEOS__", 0 }, + {"DSNH_STATUS_BETA", 0}, #endif - { 0, 0 } }; + {0,0} +}; /* Command ids */ #define TODO_GREP 1 diff --git a/util/mdgrep.pl b/util/mdgrep.pl index 076338549..24dd3d0a8 100644 --- a/util/mdgrep.pl +++ b/util/mdgrep.pl @@ -1,5 +1,5 @@ #!perl -# NetHack 3.6 mdgrep.pl $NHDT-Date: 1524684408 2018/04/25 19:26:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ +# NetHack 5.0 mdgrep.pl $NHDT-Date: 1710949914 2024/03/20 15:51:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -17,21 +17,27 @@ QT_GRAPHICS GNOME_GRAPHICS GEM_GRAPHICS/; # Game Features: -@feature = qw/ZEROCOMP USE_TILES ASCIIGRAPH CLIPPING TEXTCOLOR +@feature = qw/ZEROCOMP TILES_IN_GLYPHMAP ASCIIGRAPH CLIPPING COMPRESS ZLIB_COMP RANDOM SECURE USER_SOUNDS SAFERHANGUP MFLOPPY NOCWD_ASSUMPTIONS VAR_PLAYGROUND DLB SHELL SUSPEND NOSAVEONHANGUP HANGUPHANDLING BSD_JOB_CONTROL MAIL POSIX_JOB_CONTROL INSURANCE UNICODE_DRAWING UNICODE_WIDEWINPORT UNICODE_PLAYERTEXT + CRASHREPORT /; # Miscellaneous -@misc = qw/BETA/; +@misc = qw/CROSSCOMPILE/; # Meta @meta = qw/ALLDOCS/; # convention: use --grep-define ALLDOCS to notate # items that are conditionally available +# Special mappings (if key == value, define prefix_value, prefix is [0]) +$specials = { + NH_DEVEL_STATUS => [qw/DS NH_STATUS_RELEASED NH_STATUS_WIP NH_STATUS_BETA/] +}; + # JUNK: # MICRO BSD __GNUC__ NHSTDC TERMLIB __linux__ LINUX WIN32CON NO_TERMS # ULTRIX_PROTO TERMINFO _DCC DISPMAP OPT_DISPMAP TARGET_API_MAC_CARBON @@ -43,8 +49,7 @@ # GCC_WARN VOIDYYPUT FLEX_SCANNER FLEXHACK_SCANNER WIERD_LEX # NeXT __osf__ SVR4 _AIX32 _BULL_SOURCE AUX __sgi GNUDOS # TIMED_DELAY DEF_MAILREADER DEF_PAGER NO_SIGNAL PC_LOCKING LATTICE __GO32__ -# msleep NO_FILE_LINKS bsdi HPUX AMIFLUSH SYSFLAGS -# OVERLAY USE_TRAMPOLI USE_OVLx SPEC_LEV DGN_COMP +# msleep NO_FILE_LINKS bsdi HPUX AMIFLUSH # SCREEN_BIOS SCREEN_DJGPPFAST SCREEN_VGA SCREEN_8514 # EXEPATH NOTSTDC SELECTSAVED NOTPARMDECL @@ -54,23 +59,25 @@ $outfile = "mdgrep.h"; sub start_file { - ($rev) = ('$NHDT-Revision: 1.16 $') =~ m/: (.*) .$/; - my $date = '$NHDT-Date: 1524684408 2018/04/25 19:26:48 $'; - my $branch = '$NHDT-Branch: NetHack-3.6.0 $'; - my $revision = '$NHDT-Revision: 1.16 $'; + ($rev) = ('$NHDT-Revision: 1.26 $') =~ m/: (.*) .$/; + my $date = '$NHDT-Date: 1710949915 2024/03/20 15:51:55 $'; + my $branch = '$NHDT-Branch: NetHack-5.0 $'; + my $revision = '$NHDT-Revision: 1.26 $'; open(OUT, ">$outfile") || die "open $outfile: $!"; # NB: Date and Revision below will be modified when mdgrep.h is written to # git - this is correct (but it means you must commit changes to mdgrep.pl # before generating mdgrep.h and committing that file). print OUT < #endif #ifdef VMS -extern int FDECL(vms_creat, (const char *, unsigned)); -extern int FDECL(vms_open, (const char *, int, unsigned)); +extern int vms_creat(const char *, unsigned); +extern int vms_open(const char *, int, unsigned); #endif /* VMS */ -int FDECL(restore_savefile, (char *)); -void FDECL(set_levelfile_name, (int)); -int FDECL(open_levelfile, (int)); -int NDECL(create_savefile); -void FDECL(copy_bytes, (int, int)); +#ifndef nhUse +#define nhUse(arg) (void)(arg) +#endif + +/* copy_bytes() has been moved to hacklib */ + +int restore_savefile(char *); +void set_levelfile_name(int); +int open_levelfile(int); +int create_savefile(void); + +extern int get_critical_size_count(void); +extern uchar cscbuf[]; #ifndef WIN_CE #define Fprintf (void) fprintf @@ -37,36 +54,24 @@ static void nhce_message(FILE *, const char *, ...); #define Close (void) close -#ifdef UNIX -#define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ -#else -#ifdef VMS -#define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ -#else -#ifdef WIN32 -#define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ -#else -#define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ -#endif -#endif -#endif - #if defined(EXEPATH) -char *FDECL(exepath, (char *)); +char *exepath(char *); #endif #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif + +/* SAVESIZE is defined in "fnamesiz.h" */ char savename[SAVESIZE]; /* holds relative path of save file from playground */ +DISABLE_WARNING_UNREACHABLE_CODE + int -main(argc, argv) -int argc; -char *argv[]; +main(int argc, char *argv[]) { int argno; - const char *dir = (char *) 0; + const char *dir = (char *) 0, *progname = (char *) 0; #ifdef AMIGA char *startdir = (char *) 0; #endif @@ -79,14 +84,21 @@ char *argv[]; if (!dir) dir = exepath(argv[0]); #endif - if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) { + if (argc > 0) + progname = argv[0]; + if (!progname || !*progname) + progname = "recover"; +#ifdef VMS + /*progname = vms_basebame(progname, FALSE);*/ /* needs vmsfiles.obj */ +#endif + + if (argc < 2 || (argc == 2 && !strcmp(argv[1], "-"))) { Fprintf(stderr, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", - argv[0]); + progname); #if defined(WIN32) || defined(MSDOS) if (dir) { - Fprintf( - stderr, - "\t(Unless you override it with -d, recover will look \n"); + Fprintf(stderr, + "\t(Unless you override it with -d, recover will look \n"); Fprintf(stderr, "\t in the %s directory on your system)\n", dir); } #endif @@ -149,15 +161,16 @@ char *argv[]; return 0; } +RESTORE_WARNINGS + static char lock[256]; void -set_levelfile_name(lev) -int lev; +set_levelfile_name(int lev) { char *tf; - tf = rindex(lock, '.'); + tf = strrchr(lock, '.'); if (!tf) tf = lock + strlen(lock); (void) sprintf(tf, ".%d", lev); @@ -167,8 +180,7 @@ int lev; } int -open_levelfile(lev) -int lev; +open_levelfile(int lev) { int fd; @@ -182,7 +194,7 @@ int lev; } int -create_savefile() +create_savefile(void) { int fd; @@ -194,39 +206,19 @@ create_savefile() return fd; } -void -copy_bytes(ifd, ofd) -int ifd, ofd; -{ - char buf[BUFSIZ]; - int nfrom, nto; - - do { - nfrom = read(ifd, buf, BUFSIZ); - nto = write(ofd, buf, nfrom); - if (nto != nfrom) { - Fprintf(stderr, "file copy failed!\n"); - exit(EXIT_FAILURE); - } - } while (nfrom == BUFSIZ); -} - int -restore_savefile(basename) -char *basename; +restore_savefile(char *basename) { int gfd, lfd, sfd; int res = 0, lev, savelev, hpid, pltmpsiz; - xchar levc; + xint8 levc; struct version_info version_data; - struct savefile_info sfi; - char plbuf[PL_NSIZ]; + char plbuf[PL_NSIZ_PLUS], indicator, cscsize; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created - * savefile info * player name * and game state */ @@ -265,11 +257,16 @@ char *basename; } if ((read(gfd, (genericptr_t) savename, sizeof savename) != sizeof savename) + || (read(gfd, (genericptr_t) &indicator, sizeof indicator) + != sizeof indicator) + || (read(gfd, (genericptr_t) &cscsize, sizeof cscsize) + != sizeof cscsize) + || (read(gfd, (genericptr_t) &cscbuf, cscsize) + != cscsize) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) - || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) - != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) + != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ_PLUS) || (read(gfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz)) { Fprintf(stderr, "Error reading %s -- can't recover.\n", lock); Close(gfd); @@ -277,9 +274,12 @@ char *basename; } /* save file should contain: + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) * version info - * savefile info - * player name + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) * current level (including pets) * (non-level-based) game state * other levels @@ -299,19 +299,35 @@ char *basename; return -1; } - if (write(sfd, (genericptr_t) &version_data, sizeof version_data) - != sizeof version_data) { - Fprintf(stderr, "Error writing %s; recovery failed.\n", savename); + if (write(sfd, (genericptr_t) &indicator, sizeof indicator) + != sizeof indicator) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "indicator"); Close(gfd); Close(sfd); Close(lfd); return -1; } - - if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) { - Fprintf(stderr, - "Error writing %s; recovery failed (savefile_info).\n", - savename); + if (write(sfd, (genericptr_t) &cscsize, sizeof cscsize) != sizeof cscsize) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "cscsize"); + Close(gfd); + Close(sfd); + Close(lfd); + return -1; + } + if (write(sfd, (genericptr_t) &cscbuf, cscsize) != cscsize) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "critical bytes"); + Close(gfd); + Close(sfd); + Close(lfd); + return -1; + } + if (write(sfd, (genericptr_t) &version_data, sizeof version_data) + != sizeof version_data) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "version_data"); Close(gfd); Close(sfd); Close(lfd); @@ -329,6 +345,7 @@ char *basename; return -1; } + assert((size_t) pltmpsiz <= sizeof plbuf); if (write(sfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz) { Fprintf(stderr, "Error writing %s; recovery failed (player name).\n", savename); @@ -338,29 +355,39 @@ char *basename; return -1; } - copy_bytes(lfd, sfd); + if (!copy_bytes(lfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } Close(lfd); (void) unlink(lock); - copy_bytes(gfd, sfd); + if (!copy_bytes(gfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } Close(gfd); set_levelfile_name(0); (void) unlink(lock); for (lev = 1; lev < 256 && res == 0; lev++) { - /* level numbers are kept in xchars in save.c, so the + /* level numbers are kept in 'xint8's in save.c, so the * maximum level number (for the endlevel) must be < 256 */ if (lev != savelev) { lfd = open_levelfile(lev); if (lfd >= 0) { /* any or all of these may not exist */ - levc = (xchar) lev; + levc = (xint8) lev; if (write(sfd, (genericptr_t) &levc, sizeof levc) - != sizeof levc) + != sizeof levc) { res = -1; - else - copy_bytes(lfd, sfd); + } else { + if (!copy_bytes(lfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } + } Close(lfd); (void) unlink(lock); } @@ -382,7 +409,10 @@ char *basename; in = open("NetHack:default.icon", O_RDONLY); out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT); if (in > -1 && out > -1) { - copy_bytes(in, out); + if (!copy_bytes(in, out)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } } if (in > -1) close(in); @@ -405,14 +435,14 @@ char *basename; char exepathbuf[EXEPATHBUFSZ]; char * -exepath(str) -char *str; +exepath(char *str) { char *tmp, *tmp2; int bsize; if (!str) return (char *) 0; + nhUse(bsize); bsize = EXEPATHBUFSZ; tmp = exepathbuf; #if !defined(WIN32) @@ -435,11 +465,6 @@ char *str; } #endif /* EXEPATH */ -#ifdef AMIGA -#include "date.h" -const char amiga_version_string[] = AMIGA_VERSION_STRING; -#endif - #ifdef WIN_CE void nhce_message(FILE *f, const char *str, ...) diff --git a/util/sfctool.c b/util/sfctool.c new file mode 100644 index 000000000..2c7dc63ef --- /dev/null +++ b/util/sfctool.c @@ -0,0 +1,1280 @@ +/* NetHack 5.0 sfctool.c */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Utility for reading a binary save file in the native historical + * format of the accompanying NetHack executable, and writing it out + * in an export format, possibly destined for a different platform, + * architecture, or data model. + * + * The resulting export file will only be useful for transport + * between different platforms and architectures that share the exact + * same version of NetHack with the same features. That is, the same + * fields must be present in the NetHack data structures, in the same + * sequence. The fields do not have to be the same size or use the same + * data model. + * + */ + +#if defined(WIN32) && !defined(__GNUC__) +#include "win32api.h" +#endif + +#include "hack.h" + +#include +#include +#include +#ifdef UNIX +#include +#define O_BINARY 0 +#endif +#include "integer.h" +#include "sfprocs.h" + +#ifdef WIN32 +#include +#endif + +#ifndef RDTMODE +#define RDTMODE "r" +#endif +#ifndef WRTMODE +#if (defined(MSDOS) || defined(WIN32)) +#define WRTMODE "w+b" +#else +#define WRTMODE "w+" +#endif +#endif +#ifndef RDBMODE +#if (defined(MICRO) || defined(WIN32)) +#define RDBMODE "rb" +#else +#define RDBMODE "r" +#endif +#endif +#ifndef WRBMODE +#if (defined(MICRO) || defined(WIN32)) +#define WRBMODE "w+b" +#else +#define WRBMODE "w+" +#endif +#endif + +#ifdef PANICTRACE +#error PANICTRACE is defined +#endif +#ifdef CRASHREPORT +#error CRASHREPORT is defined +#endif + +/* functions in this file */ +static int process_savefile(const char *, enum saveformats, char *, enum saveformats, boolean); +static void my_sf_init(void); +static NHFILE *open_srcfile(const char *, enum saveformats); +static NHFILE *create_dstfile(char *, enum saveformats); +static const char *style_to_text(enum saveformats style); +static void read_sysconf(void); +static int length_without_val(const char *user_string, int len); +static void usage(int argc, char **argv); +static const char *briefname(const char *fnam); + +extern void init_nhfile(NHFILE *); /* files.c */ +extern NHFILE *new_nhfile(void); /* files.c */ +extern void free_nhfile(NHFILE *); /* files.c */ + +/* + * This is a replacement tempered down version of same-named + * function in files.c within #ifndef SFCTOOL blocks. + */ +int delete_savefile(void); + +// int nhclose(int fd); +int util_strncmpi(const char *s1, const char *s2, size_t sz); + +#ifdef UNIX +#define nethack_exit exit +ATTRNORETURN void nh_terminate(int) NORETURN; /* bwrite() calls this */ +//static void chdirx(const char *, boolean); +#else +ATTRNORETURN extern void nethack_exit(int) NORETURN; +#ifdef WIN32 +boolean get_user_home_folder(char *homebuf, size_t sz); +int GUILaunched; +#endif /* WIN32 */ +#endif +#define Fprintf (void) fprintf + +/* Global data */ + +struct link_compat1 { + volatile int done_hup; +}; + +/* worm segment structure */ +struct wseg { + struct wseg *nseg; + coordxy wx, wy; /* the segment's position */ +}; + +enum { UNCONVERTED = 0, CONVERTED }; +char *unconverted_filename = 0; +char *converted_filename = 0; + +/* from sfstruct.c */ +extern struct restore_info restoreinfo; +/* from sfbase.c */ +extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs zerosfoprocs, zerosfiprocs; +extern struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs zerosfodlprocs, zerosfidlprocs; +extern boolean close_check(int); +extern void bclose(int); +extern void config_error_init(boolean, const char *, boolean); /* files.c */ +extern boolean get_user_home_folder(char *, size_t); +extern void make_version(void); + +char plname[PL_NSIZ_PLUS]; +struct version_info vers_info; +int renidx = -1; + +const char *const rensuffixes[] = { + "IL32LLP64", /* (3) Windows x64 savefile on x86 */ + "I32LP64", /* (4) Unix 64 savefile on x86 */ + "ILP32LL64", /* (5) x86 savefile on Unix 64 */ + "ILP32LL64", /* (6) x86 savefile on Windows x64 */ + "I32LP64", /* (7) Unix 64 savefile on Windows x64 */ + "IL32LLP64", /* (8) Windows x64 savefile on Unix 64 */ + "OTHER", /* (9) */ +}; + +#ifdef WIN32 +extern boolean get_user_home_folder(char *homebuf, size_t sz); /* files.c */ +extern void set_default_prefix_locations(const char *programPath); +#endif +enum saveformats convertstyle = exportascii; + +boolean chosen_unconvert = FALSE, explicit_option = FALSE; +const char *thisdatamodel; +static char srclogfilenm[BUFSZ], dstlogfilenm[BUFSZ]; + +/********* + * main * + *********/ + +int +main(int argc, char *argv[]) +{ + int arg; + char folderbuf[5000]; + const char *suffix = (convertstyle == exportascii) ? ".exportascii" : ""; + boolean add_folder = TRUE, add_extension = FALSE; + +#ifdef WIN32 + const char *default_extension = ".NetHack-saved-game"; + size_t sz; +#else + const char *default_extension = ""; +#endif + + runtime_info_init(); /* mdlib.c */ +#ifdef UNIX + folderbuf[0] = '.'; + folderbuf[1] = '/'; + folderbuf[2] = '\0'; +#ifdef CHDIR + chdirx(HACKDIR, FALSE); +#endif +#endif +#ifdef UNIX + Strcpy(folderbuf, "save/"); +#endif +#ifdef WIN32 + if (!get_user_home_folder(folderbuf, sizeof folderbuf)) + exit(EXIT_FAILURE); + sz = strlen(folderbuf); + (void) snprintf(eos(folderbuf), sizeof folderbuf - sz, + "\\AppData\\Local\\NetHack\\5.0\\"); + // initoptions_init(); // This allows OPTIONS in syscf on Windows. + set_default_prefix_locations(argv[0]); +#endif + + read_sysconf(); + thisdatamodel = datamodel(0); + if (argc < 3 && !(argc == 2 && !strcmp(argv[1], "-d"))) { + usage(argc, argv); + exit(EXIT_FAILURE); + } + for (arg = 1; arg < argc; ++arg) { + if (arg == 1 && !strcmp(argv[arg], "-d")) { + fprintf( + stdout, + "\nThe historical savefile datamodel supported by this utility is %s (%s).\n", + thisdatamodel, datamodel(1)); + exit(EXIT_SUCCESS); + } + + if (arg == 1 && !strcmp(argv[arg], "-u")) { + explicit_option = TRUE; + chosen_unconvert = TRUE; + continue; + } + if (arg == 1 && !strcmp(argv[arg], "-c")) { + if (explicit_option && chosen_unconvert) { + fprintf(stderr, "\nsfctool error - conflicting options.\n"); + exit(EXIT_FAILURE); /* both -u and -c not allowed */ + } + explicit_option = TRUE; + chosen_unconvert = FALSE; + continue; + } + + if (arg == 2) { + size_t ln = strlen(argv[arg]); + boolean addseparator = FALSE; + + if (!contains_directory(argv[arg])) { + char finalchar = *(eos(folderbuf) - 1); + + if (!(finalchar == '\\' || finalchar == '/')) { + ln += 1; + addseparator = TRUE; + } + } else { + add_folder = FALSE; + } +#ifdef WIN32 + /* On Windows we allow specifying the savefile name without the extention + * in the arguments */ + if (strstr(argv[arg], default_extension) == 0) + add_extension = TRUE; +#endif + if (explicit_option) { + if (add_folder) + ln += strlen(folderbuf); + if (add_extension) + ln += strlen(default_extension); + unconverted_filename = (char *) alloc((int) ln + 1); + Snprintf(unconverted_filename, ln + 1, "%s%s%s%s", + add_folder ? folderbuf : "", + addseparator ? "/" : "", + argv[arg], + add_extension ? default_extension : ""); + ln += strlen(suffix); + converted_filename = (char *) alloc((int) ln + 1); + Snprintf(converted_filename, ln + 1, "%s%s", + unconverted_filename, suffix); + } else { + fprintf(stderr, "\nsfctool error - missing -c or -u before " + "save filename.\n"); + exit(EXIT_FAILURE); /* need both filenames */ + } + } + } + if (!converted_filename || !unconverted_filename) { + fprintf(stderr, "\nsfctool error - missing %sconverted file name.\n", + !converted_filename ? "" : "un"); + exit(EXIT_FAILURE); /* need both filenames */ + } + + my_sf_init(); + if (chosen_unconvert) { + process_savefile(converted_filename, convertstyle, + unconverted_filename, historical, chosen_unconvert); + } else { + process_savefile(unconverted_filename, historical, converted_filename, + convertstyle, chosen_unconvert); + } +} + +/* ======================================================================== */ +/* Process the src savefile and create the dst file */ +/* Return 1 for success, 0 for failure */ +/* ======================================================================== */ + +static int +process_savefile(const char *srcfnam, enum saveformats srcstyle, + char *dstfnam, enum saveformats cvtstyle, boolean unconvert) +{ + NHFILE *nhfp[2]; /* one for UNCONVERTED, one for CONVERTED */ + int srcidx = unconvert ? CONVERTED : UNCONVERTED, + dstidx = unconvert ? UNCONVERTED : CONVERTED, + sfstatus = 0, i; + char indicator, file_csc_count; + extern struct version_info vers_info; + extern uchar cscbuf[]; + /* nh_uncompress(fq_save); */ + const char *dmfile; + + if ((nhfp[srcidx] = open_srcfile(srcfnam, srcstyle)) == 0) + return 0; + sfstatus = validate(nhfp[srcidx], srcfnam, FALSE); + dmfile = what_datamodel_is_this(0, + cscbuf[1], /* short */ + cscbuf[2], /* int */ + cscbuf[3], /* long */ + cscbuf[4], /* long long */ + cscbuf[5]); /* ptr */ + if (sfstatus > SF_UPTODATE + && ((sfstatus <= SF_CRITICAL_BYTE_COUNT_MISMATCH) || !unconvert)) { + if (sfstatus == SF_OUTDATED) { + fprintf(stderr, + "The %s savefile is outdated with respect to this %d.%d.%d EDITLEVEL %ld " + "%s%s%s.\n", + briefname(srcfnam), + VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, + (long) EDITLEVEL, + thisdatamodel ? thisdatamodel : "", + thisdatamodel ? " " : "", + "sfctool"); + return 0; + } else { + fprintf(stderr, + "The %s savefile %s%s%s not compatible with this %s%s %s utility.\n", + briefname(srcfnam), + dmfile ? "is a " : "", + dmfile ? dmfile : "", + dmfile ? " savefile, thus" : " is", + thisdatamodel ? thisdatamodel : "", + thisdatamodel ? " " : "", + "sfctool"); + return 0; + } + } + if (sfstatus >= SF_DM_IL32LLP64_ON_ILP32LL64) { + renidx = sfstatus - SF_DM_IL32LLP64_ON_ILP32LL64; + } else if (sfstatus == SF_UPTODATE) { + renidx = -2; + } + if ((nhfp[dstidx] = create_dstfile(dstfnam, cvtstyle)) == 0) { + close_nhfile(nhfp[dstidx]); + nh_compress(unconverted_filename); + return 0; + } + if (unconvert) { + nhfp[srcidx]->nhfpconvert = nhfp[UNCONVERTED]; + } else { + /* converting */ + nhfp[srcidx]->nhfpconvert = nhfp[CONVERTED]; + } + if (unconvert) + fprintf(stdout, "\n\nunconverting %s to %s savefile called %s.\n", + briefname((const char *) converted_filename), + dmfile, + briefname((const char *) unconverted_filename)); + else + fprintf(stdout, "\n\nconverting %s %s format %s to %s format\n", + style_to_text(srcstyle), + thisdatamodel, + briefname((const char *) unconverted_filename), + style_to_text(cvtstyle)); + + rewind_nhfile(nhfp[srcidx]); +#ifdef SAVEFILE_DEBUGGING + nhfp[srcidx]->fplog = fopen(srclogfilenm, "w"); +#endif + if (unconvert) { + nhfp[srcidx]->mode |= UNCONVERTING; + } else { + /* converting */ + nhfp[srcidx]->mode |= CONVERTING; + } + nhfp[srcidx]->rcount = 0; + Sfi_char(nhfp[srcidx], &indicator, "indicate-format", 1); + Sfi_char(nhfp[srcidx], &file_csc_count, "count-critical_sizes", 1); + for (i = 0; i < (int) file_csc_count; ++i) { + Sfi_uchar(nhfp[srcidx], &cscbuf[i], "critical_sizes"); + } + rewind_nhfile(nhfp[dstidx]); +#ifdef SAVEFILE_DEBUGGING + nhfp[dstidx]->fplog = fopen(dstlogfilenm, "w"); +#endif + /* + * store_critical_bytes() will take care of inserting the + * indicate-format, count-critical_sizes, and critical_sizes for + * this platform/data-model destination, instead of copying those + * values from the savefile that was converted. + */ + store_critical_bytes(nhfp[dstidx]); + + Sfi_version_info(nhfp[srcidx], &vers_info, "version_info"); + svm.moves = 1L; /* match u_init.c */ + + /******************** + * player name info * + ********************/ + + get_plname_from_file(nhfp[srcidx], plname, TRUE); + + { + /******************** + * lev 0 * + ********************/ + xint8 lev = 0; + + getlev(nhfp[srcidx], lev, FALSE); + } + + + { + /******************** + * gamestate * + ********************/ +/* unsigned int stuckid, steedid; */ + (void) restgamestate(nhfp[srcidx]); + } + + { + /******************** + * Do all levels * + ********************/ + xint8 ltmp; + + restoreinfo.mread_flags = 1; /* return despite error */ + while (1) { + ltmp = -1; + Sfi_xint8(nhfp[srcidx], <mp, "gamestate-level_number"); + if (nhfp[srcidx]->eof || ltmp == -1) + break; + + getlev(nhfp[srcidx], 0, ltmp); + } + restoreinfo.mread_flags = 0; + } + nhfp[srcidx]->mode &= ~(CONVERTING | UNCONVERTING); + nhfp[srcidx]->nhfpconvert = (NHFILE *) 0; + close_nhfile(nhfp[srcidx]); + close_nhfile(nhfp[dstidx]); + nh_compress(dstfnam); + nh_compress(srcfnam); + return 1; +} + +/* open srcfile for reading */ +static NHFILE * +open_srcfile(const char *fnam, enum saveformats mystyle) +{ + int fd; + const char *fq_name; + NHFILE *nhfp = (NHFILE *) 0; + + nhfp = new_nhfile(); + if (nhfp) { + nhfp->mode = READING; + nhfp->structlevel = (mystyle == historical); + nhfp->fieldlevel = (mystyle > historical); + nhfp->ftype = NHF_SAVEFILE; + nhfp->fnidx = mystyle; + nhfp->fd = -1; + nhfp->addinfo = + (nhfp->fieldlevel && (mystyle = exportascii)) + ? TRUE + : FALSE; + (void) snprintf(srclogfilenm, sizeof srclogfilenm, "srcfile.%s.log", + (mystyle == historical) ? "historical" : "exportascii"); + } + + fq_name = fqname(fnam, SAVEPREFIX, 0); + nh_uncompress(fq_name); + if (nhfp && nhfp->structlevel) { + fd = open(fq_name, O_RDONLY | O_BINARY, 0); + if (fd < 0) { + free_nhfile(nhfp); + fprintf(stderr, + "\nsfctool error - unable to open historical-style " + "source file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + nh_compress(fq_name); + } else { + nhfp->fd = fd; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif + } + } + if (nhfp && nhfp->fieldlevel) { + /* char savenamebuf[BUFSZ]; */ + + nhfp->fpdef = fopen(fnam, RDBMODE); + if (!nhfp->fpdef) { + free_nhfile(nhfp); + fprintf(stderr, + "\nsfctool error - unable to open fieldlevel-style " + "source file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + nh_compress(fq_name); + } + } + return nhfp; +} + +/* create dst file, overwriting one if it already exists */ +static NHFILE * +create_dstfile(char *fnam, enum saveformats mystyle) +{ + int fd, ret; + unsigned ln = 0; + FILE *cf; + NHFILE *nhfp = (NHFILE *) 0; + const char *fq_name; + char dstfnam[2048]; + char *dsttmp; + boolean dst_file_exists = FALSE, ren_file_exists = FALSE; + + nhUse(ret); + Snprintf(dstfnam, sizeof dstfnam, "%s", fnam); + if ((cf = fopen(dstfnam, RDBMODE)) != (FILE *) 0) { + dst_file_exists = TRUE; + (void) fclose(cf); + } + + if (dst_file_exists) { + if (chosen_unconvert) { + ln = strlen(fnam); + if (renidx >= 0) { + ln += strlen(rensuffixes[renidx]) + 1; /* +1 for '.' */ + } else if (renidx == -2) { + ln += strlen(thisdatamodel) + 1; /* +1 for '.' */ + } else { + ln += strlen(thisdatamodel) + 1 + + 4; /* +1 for '.'; +4 for "not_" */ + } + dsttmp = (char *) alloc(ln + 1); + Strcpy(dsttmp, fnam); + Strcat(dsttmp, "."); + if (renidx >= 0) { + Strcat(dsttmp, rensuffixes[renidx]); + } else if (renidx == -2) { + Strcat(dsttmp, thisdatamodel); + } else { + Strcat(dsttmp, "not_"); + Strcat(dsttmp, thisdatamodel); + } + if ((cf = fopen(dsttmp, RDBMODE)) != (FILE *) 0) { + ren_file_exists = TRUE; + (void) fclose(cf); + } + if (ren_file_exists) { + (void) unlink(dsttmp); + } + ret = rename(fnam, dsttmp); + free((genericptr_t) dsttmp), dsttmp = 0; + } else { + if ((cf = fopen(dstfnam, RDBMODE)) != (FILE *) 0) { + ren_file_exists = TRUE; + (void) fclose(cf); + } + if (ren_file_exists) { + (void) unlink(dstfnam); + } + } + } + + nhfp = new_nhfile(); + if (nhfp) { + nhfp->mode = WRITING; + nhfp->ftype = NHF_SAVEFILE; + nhfp->structlevel = (mystyle == historical); + nhfp->fieldlevel = (mystyle > historical); + nhfp->fnidx = mystyle; + nhfp->fd = -1; + (void) snprintf(dstlogfilenm, sizeof dstlogfilenm, "dstfile.%s.log", + (mystyle == historical) ? "historical" : "exportascii"); + } + + if (nhfp && nhfp->structlevel) { + fq_name = fqname(dstfnam, SAVEPREFIX, 0); +#if defined(MICRO) || defined(WIN32) + fd = open(dstfnam, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); +#else + fd = creat(dstfnam, FCMASK); +#endif + if (fd < 0) { + free_nhfile(nhfp); + fprintf( + stderr, + "Unable to create historical-style destination file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + } else { + nhfp->fd = fd; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif + } + } else if (nhfp && nhfp->fieldlevel) { + fq_name = fqname(dstfnam, SAVEPREFIX, 0); + nhfp->fpdef = fopen(fq_name, WRBMODE); + if (!nhfp->fpdef) { + free_nhfile(nhfp); + fprintf( + stderr, + "Unable to create fieldlevel-style destination file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + } + } + return nhfp; +} + +static const char * +briefname(const char *fnam) +{ + const char *bn = fnam, *sep = (const char *) 0; + + if ((sep = strrchr(fnam, '/')) || (sep = strrchr(fnam, '\\')) + || (sep = strrchr(fnam, ':'))) + bn = sep + 1; + return bn; +} + +static const char * +style_to_text(enum saveformats style) +{ + const char *txt; + + switch (style) { + case historical: + txt = "historical"; + break; + case exportascii: + txt = "exportascii"; + break; + case invalid: + default: + txt = "invalid"; + break; + } + return txt; +} + +void +my_sf_init(void) +{ + decl_globals_init(); + sfoprocs[invalid] = zerosfoprocs; + sfiprocs[invalid] = zerosfiprocs; + sfoprocs[historical] = historical_sfo_procs; + sfiprocs[historical] = historical_sfi_procs; + sfoflprocs[exportascii] = exportascii_sfo_procs; + sfiflprocs[exportascii] = exportascii_sfi_procs; +} + +/* delete savefile */ +int +delete_savefile(void) +{ + return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ +} + +static void +read_sysconf(void) +{ +#ifdef SYSCF +/* someday there may be other SYSCF alternatives besides text file */ +#ifdef SYSCF_FILE + /* If SYSCF_FILE is specified, it _must_ exist... */ + assure_syscf_file(); + config_error_init(TRUE, SYSCF_FILE, FALSE); + if (!read_config_file(SYSCF_FILE, set_in_sysconf)) { + if (config_error_done() && !iflags.initoptions_noterminate) + nh_terminate(EXIT_FAILURE); + } + config_error_done(); + /* + * TODO [maybe]: parse the sysopt entries which are space-separated + * lists of usernames into arrays with one name per element. + */ +#endif +#endif /* SYSCF */ +} + +/* provided for linkage only */ + +DISABLE_WARNING_FORMAT_NONLITERAL + +void +raw_printf(const char *line, ...) +{ + va_list the_args; + + va_start(the_args, line); + vfprintf(stdout, line, the_args); + va_end(the_args); +} + +void +error(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + vprintf(s, the_args); + va_end(the_args); + exit(EXIT_FAILURE); +} + +void +pline(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + vprintf(s, the_args); + va_end(the_args); +} + +void +impossible(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + vprintf(s, the_args); + va_end(the_args); + exit(EXIT_FAILURE); +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +#ifdef UNIX +/* normalize file name - we don't like .'s, /'s, spaces */ +void +regularize(char *s) +{ + register char *lp; + + while ((lp = strchr(s, '.')) != 0 || (lp = strchr(s, '/')) != 0 + || (lp = strchr(s, ' ')) != 0) + *lp = '_'; +#if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) \ + && !defined(__APPLE__) +/* avoid problems with 14 character file name limit */ +#ifdef COMPRESS + /* leave room for .e from error and .Z from compress appended to + * save files */ + { +#ifdef COMPRESS_EXTENSION + int i = 12 - strlen(COMPRESS_EXTENSION); +#else + int i = 10; /* should never happen... */ +#endif + if (strlen(s) > i) + s[i] = '\0'; + } +#else + if (strlen(s) > 11) + /* leave room for .nn appended to level files */ + s[11] = '\0'; +#endif +#endif +} +#endif /* UNIX */ + +int +util_strncmpi(const char *s1, const char *s2, size_t sz) +{ + register char t1, t2; + + while (sz--) { + if (!*s2) + return (*s1 != 0); /* s1 >= s2 */ + else if (!*s1) + return -1; /* s1 < s2 */ + t1 = lowc(*s1++); + t2 = lowc(*s2++); + if (t1 != t2) + return (t1 > t2) ? 1 : -1; + } + return 0; /* s1 == s2 */ +} + +/* should be called with either EXIT_SUCCESS or EXIT_FAILURE */ +void +nh_terminate(int status) +{ + nethack_exit(status); +} + +#ifndef UNIX +void +nethack_exit(int code) +{ + exit(code); +} +#endif /* UNIX */ + +#ifdef UNIX +#ifdef CHDIR +void +chdirx(const char *dir, boolean wr UNUSED) +{ + if (dir) { +#ifdef SECURE + (void) setgid(getgid()); + (void) setuid(getuid()); /* Ron Wessels */ +#endif + } else { + /* non-default data files is a sign that scores may not be + * compatible, or perhaps that a binary not fitting this + * system's layout is being used. + */ +#ifdef VAR_PLAYGROUND + int len = strlen(VAR_PLAYGROUND); + + gf.fqn_prefix[SCOREPREFIX] = (char *) alloc(len + 2); + Strcpy(gf.fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND); + if (gf.fqn_prefix[SCOREPREFIX][len - 1] != '/') { + gf.fqn_prefix[SCOREPREFIX][len] = '/'; + gf.fqn_prefix[SCOREPREFIX][len + 1] = '\0'; + } + +#endif + } + +#ifdef HACKDIR + if (dir == (const char *) 0) + dir = HACKDIR; +#endif + + if (dir && chdir(dir) < 0) { + perror(dir); + error("Cannot chdir to %s.", dir); + } +} +#endif /* CHDIR */ +#endif /* UNIX */ + +#ifdef WIN32 + +/* + * Strip out troublesome file system characters. + */ + +void nt_regularize(char* s) /* normalize file name */ +{ + unsigned char *lp; + + for (lp = (unsigned char *) s; *lp; lp++) + if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' + || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' + || *lp == ':' || (*lp > 127)) + *lp = '_'; +} +#endif /* WIN32 */ + +/* duplicated code from options.c */ +/* most environment variables will eventually be printed in an error + * message if they don't work, and most error message paths go through + * BUFSZ buffers, which could be overflowed by a maliciously long + * environment variable. If a variable can legitimately be long, or + * if it's put in a smaller buffer, the responsible code will have to + * bounds-check itself. + */ +char * +nh_getenv(const char *ev) +{ + char *getev = getenv(ev); + + if (getev && strlen(getev) <= (BUFSZ / 2)) + return getev; + else + return (char *) 0; +} + +void +done1(int sig_unused UNUSED) +{ +#ifndef NO_SIGNAL + (void) signal(SIGINT, SIG_IGN); +#endif + if (flags.ignintr) { +#ifndef NO_SIGNAL + (void) signal(SIGINT, (SIG_RET_TYPE) done1); +#endif + } +} + +/* + * I hate having to duplicate this code here, but it is much simpler to + * add these here than take steps to link with mkobj.c, do_name.c, priest.c, + * vault.c, shknam.c, minion.c, dog.c, etc. + */ + +/* allocate space for a monster's name; removes old name if there is one */ +void +new_mgivenname(struct monst *mon, + int lth) /* desired length (caller handles adding 1 + for terminator) */ +{ + if (lth) { + /* allocate mextra if necessary; otherwise get rid of old name */ + if (!mon->mextra) + mon->mextra = newmextra(); + else + free_mgivenname(mon); /* already has mextra, might also have name */ + MGIVENNAME(mon) = (char *) alloc((unsigned) lth); + } else { + /* zero length: the new name is empty; get rid of the old name */ + if (has_mgivenname(mon)) + free_mgivenname(mon); + } +} + +/* release a monster's name; retains mextra even if all fields are now null */ +void +free_mgivenname(struct monst *mon) +{ + if (has_mgivenname(mon)) { + free((genericptr_t) MGIVENNAME(mon)); + MGIVENNAME(mon) = (char *) 0; + } +} +void +newegd(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EGD(mtmp)) { + EGD(mtmp) = (struct egd *) alloc(sizeof (struct egd)); + (void) memset((genericptr_t) EGD(mtmp), 0, sizeof (struct egd)); + } +} + +void +free_egd(struct monst *mtmp) +{ + if (mtmp->mextra && EGD(mtmp)) { + free((genericptr_t) EGD(mtmp)); + EGD(mtmp) = (struct egd *) 0; + } + mtmp->isgd = 0; +} +void +newepri(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EPRI(mtmp)) { + EPRI(mtmp) = (struct epri *) alloc(sizeof(struct epri)); + (void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri)); + } +} + +void +free_epri(struct monst *mtmp) +{ + if (mtmp->mextra && EPRI(mtmp)) { + free((genericptr_t) EPRI(mtmp)); + EPRI(mtmp) = (struct epri *) 0; + } + mtmp->ispriest = 0; +} +void +neweshk(struct monst* mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!ESHK(mtmp)) + ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk)); + (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk)); + ESHK(mtmp)->bill_p = (struct bill_x *) 0; +} + +void +free_eshk(struct monst* mtmp) +{ + if (mtmp->mextra && ESHK(mtmp)) { + free((genericptr_t) ESHK(mtmp)); + ESHK(mtmp) = (struct eshk *) 0; + } + mtmp->isshk = 0; +} + +void +newemin(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EMIN(mtmp)) { + EMIN(mtmp) = (struct emin *) alloc(sizeof(struct emin)); + (void) memset((genericptr_t) EMIN(mtmp), 0, sizeof(struct emin)); + } +} + +void +free_emin(struct monst *mtmp) +{ + if (mtmp->mextra && EMIN(mtmp)) { + free((genericptr_t) EMIN(mtmp)); + EMIN(mtmp) = (struct emin *) 0; + } + mtmp->isminion = 0; +} + +void +newedog(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EDOG(mtmp)) { + EDOG(mtmp) = (struct edog *) alloc(sizeof(struct edog)); + (void) memset((genericptr_t) EDOG(mtmp), 0, sizeof(struct edog)); + } +} + +void +free_edog(struct monst *mtmp) +{ + if (mtmp->mextra && EDOG(mtmp)) { + free((genericptr_t) EDOG(mtmp)); + EDOG(mtmp) = (struct edog *) 0; + } + mtmp->mtame = 0; +} + +void +newebones(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EBONES(mtmp)) { + EBONES(mtmp) = (struct ebones *) alloc(sizeof(struct ebones)); + (void) memset((genericptr_t) EBONES(mtmp), 0, sizeof(struct ebones)); + } +} + +void +free_ebones(struct monst *mtmp) +{ + if (mtmp->mextra && EBONES(mtmp)) { + free((genericptr_t) EBONES(mtmp)); + EBONES(mtmp) = (struct ebones *) 0; + } +} + +static const struct mextra zeromextra = DUMMY; + +static void +init_mextra(struct mextra *mex) +{ + *mex = zeromextra; + mex->mcorpsenm = NON_PM; +} + +struct mextra * +newmextra(void) +{ + struct mextra *mextra; + + mextra = (struct mextra *) alloc(sizeof(struct mextra)); + init_mextra(mextra); + return mextra; +} + +void +newomonst(struct obj* otmp) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + + if (!OMONST(otmp)) { + struct monst *m = newmonst(); + + *m = cg.zeromonst; + OMONST(otmp) = m; + } +} + +void +free_omonst(struct obj* otmp) +{ + if (otmp->oextra) { + struct monst *m = OMONST(otmp); + + if (m) { + if (m->mextra) + dealloc_mextra(m); + free((genericptr_t) m); + OMONST(otmp) = (struct monst *) 0; + } + } +} + +void +newomid(struct obj* otmp) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + OMID(otmp) = 0; +} + +void +free_omid(struct obj* otmp) +{ + OMID(otmp) = 0; +} + +void +new_omailcmd(struct obj* otmp, const char * response_cmd) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + if (OMAILCMD(otmp)) + free_omailcmd(otmp); + OMAILCMD(otmp) = dupstr(response_cmd); +} + +void +free_omailcmd(struct obj* otmp) +{ + if (otmp->oextra && OMAILCMD(otmp)) { + free((genericptr_t) OMAILCMD(otmp)); + OMAILCMD(otmp) = (char *) 0; + } +} + +static const struct oextra zerooextra = DUMMY; + +static void +init_oextra(struct oextra* oex) +{ + *oex = zerooextra; +} + + +struct oextra * +newoextra(void) +{ + struct oextra *oextra; + + oextra = (struct oextra *) alloc(sizeof (struct oextra)); + init_oextra(oextra); + return oextra; +} + +void +dealloc_mextra(struct monst* m) +{ + struct mextra *x = m->mextra; + + if (x) { + if (x->mgivenname) + free((genericptr_t) x->mgivenname); + if (x->egd) + free((genericptr_t) x->egd); + if (x->epri) + free((genericptr_t) x->epri); + if (x->eshk) + free((genericptr_t) x->eshk); + if (x->emin) + free((genericptr_t) x->emin); + if (x->edog) + free((genericptr_t) x->edog); + if (x->ebones) + free((genericptr_t) x->ebones); + /* [no action needed for x->mcorpsenm] */ + + free((genericptr_t) x); + m->mextra = (struct mextra *) 0; + } +} + +void +dealloc_monst(struct monst* mon) +{ + if (mon->mextra) + dealloc_mextra(mon); + free((genericptr_t) mon); +} + +/* allocate space for an object's name; removes old name if there is one */ +void +new_oname(struct obj *obj, + int lth) /* desired length (caller handles adding 1 + for terminator) */ +{ + if (lth) { + /* allocate oextra if necessary; otherwise get rid of old name */ + if (!obj->oextra) + obj->oextra = newoextra(); + else + free_oname(obj); /* already has oextra, might also have name */ + ONAME(obj) = (char *) alloc((unsigned) lth); + } else { + /* zero length: the new name is empty; get rid of the old name */ + if (has_oname(obj)) + free_oname(obj); + } +} + +/* release an object's name; retains oextra even if all fields are now null */ +void +free_oname(struct obj *obj) +{ + if (has_oname(obj)) { + free((genericptr_t) ONAME(obj)); + ONAME(obj) = (char *) 0; + } +} + +#ifdef WIN32 +void +win32_abort(void) +{ + abort(); +} +#endif + +static int +length_without_val(const char *user_string, int len) +{ + const char *p = strchr(user_string, ':'), *q = strchr(user_string, '='); + + if (!p || (q && q < p)) + p = q; + if (p) { + /* 'user_string' hasn't necessarily been through mungspaces() + so might have tabs or consecutive spaces */ + while (p > user_string && isspace((uchar) * (p - 1))) + p--; + len = (int) (p - user_string); + } + return len; +} + +/* check whether a user-supplied option string is a proper leading + substring of a particular option name; option string might have + a colon or equals sign and arbitrary value appended to it */ +boolean +match_optname(const char *user_string, const char *optn_name, int min_length, + boolean val_allowed) +{ + int len = (int) strlen(user_string); + + if (val_allowed) + len = length_without_val(user_string, len); + + return (boolean) (len >= min_length + && !strncmpi(optn_name, user_string, len)); +} + +staticfn void +usage(int argc UNUSED, char **argv) +{ + char *cp = argv[0], *sep = (char *) 0; + + if ((sep = strrchr(cp, '/')) || (sep = strrchr(cp, '\\')) + || (sep = strrchr(cp, ':'))) + cp = sep + 1; + fprintf(stderr, + "\nTo convert a savefile to export format:\n %s %s %s\n", cp, + "-c", "savefile"); + fprintf(stderr, + "\nTo unconvert an exported savefile back into a savefile:\n %s %s %s\n", cp, + "-u", "savefile"); +} +/* sfctool.c */ diff --git a/util/sfexpasc.c b/util/sfexpasc.c new file mode 100644 index 000000000..c27878020 --- /dev/null +++ b/util/sfexpasc.c @@ -0,0 +1,1296 @@ +/* NetHack 5.0 sfexpasc.c.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* avoid the global.h define */ +#define STRNCMPI + +#include "hack.h" +#include "integer.h" +#include "sfprocs.h" +#include "sfproto.h" + +#if defined(MACOSX) || defined(VMS) +extern long long atoll(const char *); +#endif + +static void put_savefield(NHFILE *, char *, size_t); +char *get_savefield(NHFILE *, char *, size_t); +#ifdef SAVEFILE_DEBUGGING +void report_problem_exportascii(NHFILE *, const char *, const char *, + const char *); +#endif + +#ifdef _MSC_VER +#define strcmpi _stricmp +#else +#define strcmpi strcasecmp +#endif + +static char linebuf[BUFSZ * 10]; +static char outbuf[BUFSZ * 10]; + +#if 0 +void exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfo_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED); +void exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int); +void exportascii_sfo_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED); +void exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED); +void exportascii_sfo_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED); +void exportascii_sfo_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED); +void exportascii_sfo_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED); +void exportascii_sfo_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED); +void exportascii_sfo_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED); +void exportascii_sfo_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED); +void exportascii_sfo_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfo_uint(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfo_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED); +void exportascii_sfo_uint(NHFILE *nhfp, unsigned int *d_uint, const char *myname UNUSED); +void exportascii_sfo_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED); +void exportascii_sfo_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED); +void exportascii_sfo_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED); +void exportascii_sfo_char(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED); +void exportascii_sfo_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED); +void exportascii_sfo_char(NHFILE *nhfp, char *d_str, const char *myname UNUSED, int cnt); +void exportascii_sfo_addinfo(NHFILE *nhfp UNUSED, const char *parent UNUSED, const char *action UNUSED, const char *myname UNUSED, int indx UNUSED); +void exportascii_sfi_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED); +void exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int); +void exportascii_sfi_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED); +void exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED); +void exportascii_sfi_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED); +void exportascii_sfi_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED); +void exportascii_sfi_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED); +void exportascii_sfi_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED); +void exportascii_sfi_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED); +void exportascii_sfi_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED); +void exportascii_sfi_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfi_uint(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfi_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED); +void exportascii_sfi_uint(NHFILE *nhfp, unsigned int *d_uint, const char *myname UNUSED); +void exportascii_sfi_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED); +void exportascii_sfi_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED); +void exportascii_sfi_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED); +void exportascii_sfi_xint8(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED); +void exportascii_sfi_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED); +void exportascii_sfi_cnt(NHFILE *nhfp, char *d_str, const char *myname UNUSED, int cnt); +#endif + +#define SFO_BODY(dt) \ +{ \ +} + +#define SFI_BODY(dt) \ +{ \ +} + +#define SF_A(dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, \ + const char *); \ +void exportascii_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, \ + const char *); + +/* +void exportascii_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) +*/ + +#define SF_C(keyw, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp UNUSED, \ + const char *); \ +void exportascii_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ + const char *); \ + \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_X(xxx, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *); \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *); \ + \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, xxx *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_BF(xxx, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *, int); \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *, int); + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) +/* SF_C(union, any) */ +void exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); + +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) +void exportascii_sfo_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt); +void exportascii_sfi_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt); +void exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, + const char *myname UNUSED, int bflen UNUSED); +void exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, + const char *myname UNUSED, int bflen UNUSED); +int critical_members_count_core(NHFILE *nhfp); + + +/* + *---------------------------------------------------------------------------- + * Sfo_def_ routines + * + * Default output routines. + * + *---------------------------------------------------------------------------- + */ + + +void +exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED) +{ + /* const char *parent = "any"; */ + + /* nhUse(parent); */ + Sprintf(outbuf, "%llx", (unsigned long long) d_any->a_void); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%lu", d_any->a_ulong); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%ld", d_any->a_long); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%d", d_any->a_uint); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%d", d_any->a_int);; + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%hd", (short) d_any->a_char); + put_savefield(nhfp, outbuf, sizeof outbuf); + +#if 0 + Sfo_genericptr(nhfp, d_any->a_void, parent, "a_void", 1); /* (genericptr_t) */ + Sfo_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1); /* (struct obj *) */ + Sfo_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1); /* (struct monst *) */ + Sfo_int32(nhfp, &d_any->a_int, parent, "a_int", 1); /* (int) */ + Sfo_char(nhfp, &d_any->a_char, parent, "a_char", 1); /* (char) */ + Sfo_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1); /* (schar) */ + Sfo_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1); /* (uchar) */ + Sfo_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1); /* (unsigned int) */ + Sfo_long(nhfp, &d_any->a_long, parent, "a_long", 1); /* (long) */ + Sfo_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1); /* (unsigned long) */ + Sfo_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1); /* (int *) */ + Sfo_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1); /* (long *) */ + Sfo_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1); /* (unsigned long *) */ + Sfo_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1); /* (unsigned *) */my + Sfo_genericptr(nhfp, d_any->a_string, parent, "a_string", 1); /* (const char *) */ + Sfo_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1); /* (unsigned long) */ +#endif +} + +void +exportascii_sfo_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED) +{ + int itmp; + itmp = (int) *d_aligntyp; + Sprintf(outbuf, "%d", (short) itmp); + put_savefield(nhfp, outbuf, sizeof outbuf); +} + +void +exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int bflen UNUSED) +{ + /* for bitfields, cnt is the number of bits, not an array */ + Sprintf(outbuf, "%hu", (unsigned short) *d_bitfield); + put_savefield(nhfp, outbuf, sizeof outbuf); +} + +void +exportascii_sfo_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED) +{ + if (nhfp->fpdebug) + fprintf(nhfp->fpdebug, "(%s)\n", (*d_boolean) ? "TRUE" : "FALSE"); + Sprintf(outbuf, "%s", *d_boolean ? "true" : "false"); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_boolean++; +} + +void exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, + const char *myname UNUSED); + +void +exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED) +{ + unsigned long tmp; + char *byteptr = (char *) d_genericptr; + /* + * sbrooms is an array of pointers to mkroom. + * That array dimension is MAX_SUBROOMS. + * Even though the pointers themselves won't + * be valid, we need to account for the existence + * of that array and perhaps zero or non-zero. + */ + tmp = (*d_genericptr) ? 1UL : 0UL; + Sprintf(outbuf, "%08lu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + byteptr += sizeof(void *); + d_genericptr = (genericptr_t) byteptr; +} + +#if 0 +void +exportascii_sfo_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int++; +} +#endif + +void +exportascii_sfo_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED) +{ + Sprintf(outbuf, "%ld", *d_long); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_long++; +} + +void +exportascii_sfo_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED) +{ + int itmp; + itmp = (int) *d_schar; + Sprintf(outbuf, "%d", itmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_schar++; +} + +void +exportascii_sfo_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + Sprintf(outbuf, "%hd", *d_short); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_short++; +} + +void +exportascii_sfo_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED) +{ + unsigned long ul = (unsigned long) *d_size_t; + + Sprintf(outbuf, "%lu", ul); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_size_t++; +} + +void +exportascii_sfo_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED) +{ + Sprintf(outbuf, "%s", yyyymmddhhmmss(*d_time_t)); + put_savefield(nhfp, outbuf, sizeof outbuf); +} +void +exportascii_sfo_xint8(NHFILE *nhfp, int8 *d_int8, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_int8); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int8++; +} +#if 0 +void +exportascii_sfo_int16(NHFILE *nhfp, int16 *d_int16, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_int16); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint16++; +} +#endif + +#if 0 +void +exportascii_sfo_char(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED, int cnt) +{ + short tmp; + + tmp = (int) *d_xint8; + Sprintf(outbuf, "%d", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_xint8++; +} +#endif + +void +exportascii_sfo_int32(NHFILE *nhfp, int32 *d_int32, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int32++; +} + +void +exportascii_sfo_int64(NHFILE *nhfp, int64 *d_int64, const char *myname UNUSED) +{ + Sprintf(outbuf, "%lld", (long long) *d_int64); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int64++; +} + +void +exportascii_sfo_int(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int++; +} +void +exportascii_sfo_short(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_short); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_short++; +} +/* aka exportascii_sfo_uint8 */ +void +exportascii_sfo_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED) +{ + unsigned x_uint32 = (uint32) *d_uchar; + + Sprintf(outbuf, "%u", x_uint32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uchar++; +} + +void +exportascii_sfo_uint16(NHFILE *nhfp, uint16 *d_uint16, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", (uint32) *d_uint16); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint16++; +} + +void +exportascii_sfo_uint32(NHFILE *nhfp, uint32 *d_uint32, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", *d_uint32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint32++; +} + +void +exportascii_sfo_uint64(NHFILE *nhfp, uint64 *d_uint64, const char *myname UNUSED) +{ + Sprintf(outbuf, "%llu", (unsigned long long) *d_uint64); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint64++; +} + +void +exportascii_sfo_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED) +{ + Sprintf(outbuf, "%lu", *d_ulong); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_ulong++; +} + + +void +exportascii_sfo_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED) +{ + Sprintf(outbuf, "%hu", *d_ushort); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_ushort++; +} + +void +exportascii_sfo_unsigned(NHFILE *nhfp, unsigned *d_unsigned, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", *d_unsigned); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_unsigned++; +} + +void +exportascii_sfo_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED) +{ + short tmp; + + tmp = (short) *d_coordxy; + Sprintf(outbuf, "%hu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_coordxy++; +} + + +void +exportascii_sfo_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED) +{ + short tmp; + + tmp = (short) *d_xint16; + Sprintf(outbuf, "%hu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_xint16++; +} + +static char strbuf[BUFSZ * 10]; + +void +exportascii_sfo_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt) +{ + int i, j; + uint uintval; + char sval[QBUFSZ]; + uchar *usrc = (uchar *) d_char, *udest = (uchar *)strbuf; + + /* cnt is the number of characters */ + for (i = 0; i < cnt; ++i) { + if ((*usrc < 32) || (*usrc == '\\') || (*usrc == '|')) { + *udest++ = '\\'; + uintval = *usrc++; + Sprintf(sval, "%03u", uintval); + for (j = 0; j < 3; ++j) + *udest++ = (uchar) sval[j]; + } else { + *udest++ = *usrc++; + } + } + *udest = '\0'; + put_savefield(nhfp, strbuf, strlen(strbuf)); +} + +static void +put_savefield(NHFILE *nhfp, char *obuf, size_t outbufsz UNUSED) +{ + nhfp->wcount++; + fprintf(nhfp->fpdef, "%07ld|%s\n", nhfp->wcount, obuf); + fflush(nhfp->fpdef); +} + +/* + *---------------------------------------------------------------------------- + * exportascii_sfi_ routines called from functions in Sfi_base.c + *---------------------------------------------------------------------------- + */ + +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); + +void +exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED) +{ + char *rstr; + long long tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_uint64 = (uint64) tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_ulong = (unsigned long) tmp; + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_long = atol(rstr); + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_uint = (unsigned int) tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_int = atoi(rstr); + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_char = (char) atoi(rstr); + +#if 0 + Sfi_genericptr(nhfp, d_any->a_void, parent, "a_void", 1); + Sfi_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1); + Sfi_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1); + Sfi_int32(nhfp, &d_any->a_int, parent, "a_int", 1); + Sfi_char(nhfp, &d_any->a_char, parent, "a_char", 1); + Sfi_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1); + Sfi_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1); + Sfi_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1); + Sfi_long(nhfp, &d_any->a_long, parent, "a_long", 1); + Sfi_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1); + Sfi_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1); + Sfi_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1); + Sfi_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1); + Sfi_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1); + Sfi_genericptr(nhfp, d_any->a_string, parent, "a_string", 1); + Sfi_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1); +#endif +} + +void +exportascii_sfi_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED) +{ + char *rstr; + aligntyp tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (aligntyp) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_aligntyp) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_aligntyp = tmp; +} + +void +exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int bflen UNUSED) +{ + char *rstr; + uint8_t tmp; + + /* cnt is the number of bits in the bitfield, not an array dimension */ + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (uint8_t) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_bitfield) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_bitfield = tmp; +} + +void +exportascii_sfi_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED) +{ + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); +#ifdef SAVEFILE_DEBUGGING + if (!strcmpi(rstr, "false") && + !strcmpi(rstr, "true")) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + if (!strcmpi(rstr, "false")) + *d_boolean = FALSE; + else + *d_boolean = TRUE; + d_boolean++; +} + +void exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, + const char *myname UNUSED); + +void +exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED) +{ + long long lltmp; + char *rstr; + static const char *glorkum = "glorkum"; + + /* + * sbrooms is an array of pointers to mkroom. + * That array dimension is MAX_SUBROOMS. + * Even though the pointers themselves won't + * be valid, we need to account for the existence + * of that array. + */ + /* these pointers can't actually be valid */ + rstr = get_savefield(nhfp, linebuf, sizeof linebuf); + lltmp = atoll(rstr); + *d_genericptr = lltmp ? (genericptr_t) glorkum : (genericptr_t) 0; +} + +void +exportascii_sfi_int32(NHFILE *nhfp, int32 *d_int32, const char *myname UNUSED) +{ + int32 tmp; + char *rstr; + long ltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + ltmp = atol(rstr); + tmp = (int32) ltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int32) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int32 = (int32) tmp; + d_int32++; +} + +void +exportascii_sfi_int(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + int tmp; + char *rstr; + long ltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + ltmp = atol(rstr); + tmp = (int) ltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int = (int32) tmp; + d_int++; +} +void +exportascii_sfi_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED) +{ + long tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (long) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_long) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_long = tmp; + d_long++; +} + +void +exportascii_sfi_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED) +{ + schar tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (schar) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_schar) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_schar = tmp; + d_schar++; +} + +void +exportascii_sfi_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + short tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (short) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_short) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_short = tmp; + d_short++; +} + +void +exportascii_sfi_int64(NHFILE *nhfp, int64 *d_int64, const char *myname UNUSED) +{ + int64 tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (int64) atol(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int64) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int64 = tmp; + d_int64++; +} +void +exportascii_sfi_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED) +{ + size_t tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (size_t) atol(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_size_t) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_size_t = tmp; + d_size_t++; +} + +void +exportascii_sfi_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED) +{ + time_t tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = time_from_yyyymmddhhmmss(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_time_t) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_time_t = tmp; + d_time_t++; +} + +#if 0 +void +exportascii_sfi_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname) +{ + /* deferal */ + exportascii_sfi_uint(nhfp, d_unsigned, myname); +} +#endif + +void +exportascii_sfi_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED) +{ + uchar tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (char ) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uchar) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uchar = tmp; + d_uchar++; +} + +void +exportascii_sfi_uint16(NHFILE *nhfp, uint16 *d_uint16, const char *myname UNUSED) +{ + char *rstr; + unsigned int tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned int) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint16 = tmp; + d_uint16++; +} + +void +exportascii_sfi_uint32(NHFILE *nhfp, uint32 *d_uint32, const char *myname UNUSED) +{ + char *rstr; + uint32 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint32) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint32 = tmp; + d_uint32++; +} + +void +exportascii_sfi_uint64(NHFILE *nhfp, uint64 *d_uint64, const char *myname UNUSED) +{ + char *rstr; + uint64 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint64) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint64 = tmp; + d_uint64++; +} + +void +exportascii_sfi_unsigned(NHFILE *nhfp, unsigned *d_unsigned, const char *myname UNUSED) +{ + char *rstr; + uint32 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint32) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_unsigned) + report_problem_ascii(nhfp, "", myname, parent); + else +#endif + *d_unsigned = tmp; + d_unsigned++; +} + +void +exportascii_sfi_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED) +{ + unsigned long tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned long) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_ulong) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_ulong = tmp; + d_ulong++; +} + +void +exportascii_sfi_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED) +{ + short tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned short) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_ushort) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_ushort = tmp; + d_ushort++; +} + +void +exportascii_sfi_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED) +{ + coordxy tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (coordxy) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_coordxy) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_coordxy = tmp; + d_coordxy++; +} + +void +exportascii_sfi_xint8(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED) +{ + xint8 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + if (!nhfp->eof) { + itmp = atoi(rstr); + tmp = (xint8) itmp; + } else { + return; + } +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_xint8) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_xint8 = tmp; + d_xint8++; +} + +void +exportascii_sfi_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED) +{ + xint16 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (xint16) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_xint16) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_xint16 = tmp; + d_xint16++; +} + +void +exportascii_sfi_short(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + xint16 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (xint16) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_short) + report_problem_ascii(nhfp, "", myname, parent); + else +#endif + *d_short = tmp; + d_short++; +} + + +void +exportascii_sfi_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt) +{ + int i, j, sval; + char n[4], *rstr; + char *src, *dest; + + /* cnt is the length of the string */ + rstr = get_savefield(nhfp, strbuf, sizeof strbuf); + if (!rstr) { + nhfp->eof = TRUE; + return; + } + src = rstr; + dest = +#ifdef SAVEFILE_DEBUGGING + testbuf; +#else + d_char; +#endif + + for (i = 0; i < cnt; ++i) { + if (*src == '\\') { + src++; + for (j = 0; j < 4; ++j) { + if (j < 3) + n[j] = *src++; + else + n[j] = '\0'; + } + sval = atoi(n); + *dest++ = (char) sval; + } else + *dest++ = *src++; + } +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel) { + src = testbuf; + dest = d_char; + match = TRUE; + for (i = 0; i < cnt; ++i) { + if (*src++ != *dest++) + match = FALSE; + } + if (!match) + report_problem_ascii(nhfp, myparent, myname, parent); + else { + src = testbuf; + dest = d_char; + for (i = 0; i < cnt; ++i) + *dest++ = *src++; + } + } +#endif +} + +char * +get_savefield(NHFILE *nhfp, char *inbuf, size_t inbufsz) +{ + char *ep, *sep; + char *res = 0; + + if ((res =fgets(inbuf, (int) inbufsz, nhfp->fpdef)) != 0) { + nhfp->rcount++; + ep = strchr(inbuf, '\n'); + if (!ep) { /* newline missing */ + if (strlen(inbuf) < (inbufsz - 2)) { + /* likely the last line of file is just + missing a newline; process it anyway */ + ep = eos(inbuf); + } + } + if (ep) + *ep = '\0'; /* remove newline */ + sep = strchr(inbuf, '|'); + if (sep) + sep++; + + return sep; + } + inbuf[0] = '\0'; + nhfp->eof = TRUE; + return inbuf; +} + +#ifdef SAVEFILE_DEBUGGING +void +report_problem_ascii(NHFILE *nhfp, const char *s1, const char *s2, const char *s3) +{ + fprintf(nhfp->fpdebug, "faulty value preservation " + "(%ld, %s, %s, %s)\n", + ((nhfp->mode & READING) != 0) ? nhfp->rcount : nhfp->wcount, s1, s2, s3); +} +#endif + +int exportascii_critical_members_count(void); + +int +exportascii_critical_members_count(void) +{ + return 0; +} + +struct sf_fieldlevel_procs exportascii_sfo_procs = { + "exportascii", + /* sf_x */ + { + sfo_x_arti_info, + sfo_x_nhrect, + sfo_x_branch, + sfo_x_bubble, + sfo_x_cemetery, + sfo_x_context_info, + sfo_x_nhcoord, + sfo_x_damage, + sfo_x_dest_area, + sfo_x_dgn_topology, + sfo_x_dungeon, + sfo_x_d_level, + sfo_x_ebones, + sfo_x_edog, + sfo_x_egd, + sfo_x_emin, + sfo_x_engr, + sfo_x_epri, + sfo_x_eshk, + sfo_x_fe, + sfo_x_flag, + sfo_x_fruit, + sfo_x_gamelog_line, + sfo_x_kinfo, + sfo_x_levelflags, + sfo_x_ls_t, + sfo_x_linfo, + sfo_x_mapseen_feat, + sfo_x_mapseen_flags, + sfo_x_mapseen_rooms, + sfo_x_mkroom, + sfo_x_monst, + sfo_x_mvitals, + sfo_x_obj, + sfo_x_objclass, + sfo_x_q_score, + sfo_x_rm, + sfo_x_spell, + sfo_x_stairway, + sfo_x_s_level, + sfo_x_trap, + sfo_x_version_info, + sfo_x_you, + + exportascii_sfo_any, + exportascii_sfo_aligntyp, + exportascii_sfo_boolean, + exportascii_sfo_coordxy, + exportascii_sfo_genericptr, + exportascii_sfo_int, + exportascii_sfo_int16, + exportascii_sfo_int32, + exportascii_sfo_int64, + exportascii_sfo_long, + exportascii_sfo_schar, + exportascii_sfo_short, + exportascii_sfo_size_t, + exportascii_sfo_time_t, + exportascii_sfo_uchar, + exportascii_sfo_uint16, + exportascii_sfo_uint32, + exportascii_sfo_uint64, + exportascii_sfo_ulong, + exportascii_sfo_unsigned, + exportascii_sfo_ushort, + exportascii_sfo_xint16, + exportascii_sfo_xint8, + exportascii_sfo_char, + exportascii_sfo_bitfield, + } +}; + +struct sf_fieldlevel_procs exportascii_sfi_procs = { + "le", + /* sf_x */ + { + sfi_x_arti_info, + sfi_x_nhrect, + sfi_x_branch, + sfi_x_bubble, + sfi_x_cemetery, + sfi_x_context_info, + sfi_x_nhcoord, + sfi_x_damage, + sfi_x_dest_area, + sfi_x_dgn_topology, + sfi_x_dungeon, + sfi_x_d_level, + sfi_x_ebones, + sfi_x_edog, + sfi_x_egd, + sfi_x_emin, + sfi_x_engr, + sfi_x_epri, + sfi_x_eshk, + sfi_x_fe, + sfi_x_flag, + sfi_x_fruit, + sfi_x_gamelog_line, + sfi_x_kinfo, + sfi_x_levelflags, + sfi_x_ls_t, + sfi_x_linfo, + sfi_x_mapseen_feat, + sfi_x_mapseen_flags, + sfi_x_mapseen_rooms, + sfi_x_mkroom, + sfi_x_monst, + sfi_x_mvitals, + sfi_x_obj, + sfi_x_objclass, + sfi_x_q_score, + sfi_x_rm, + sfi_x_spell, + sfi_x_stairway, + sfi_x_s_level, + sfi_x_trap, + sfi_x_version_info, + sfi_x_you, + + exportascii_sfi_any, + exportascii_sfi_aligntyp, + exportascii_sfi_boolean, + exportascii_sfi_coordxy, + exportascii_sfi_genericptr, + exportascii_sfi_int, + exportascii_sfi_int16, + exportascii_sfi_int32, + exportascii_sfi_int64, + exportascii_sfi_long, + exportascii_sfi_schar, + exportascii_sfi_short, + exportascii_sfi_size_t, + exportascii_sfi_time_t, + exportascii_sfi_uchar, + exportascii_sfi_uint16, + exportascii_sfi_uint32, + exportascii_sfi_uint64, + exportascii_sfi_ulong, + exportascii_sfi_unsigned, + exportascii_sfi_ushort, + exportascii_sfi_xint16, + exportascii_sfi_xint8, + exportascii_sfi_char, + exportascii_sfi_bitfield, + } +}; diff --git a/util/sftags.c b/util/sftags.c new file mode 100644 index 000000000..9d204cdb3 --- /dev/null +++ b/util/sftags.c @@ -0,0 +1,2285 @@ +/* NetHack 3.6 sftags.c $Date$ $Revision$ */ +/* Copyright (c) Michael Allison, 2025 */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Read the given ctags file and generate: + * Intermediate temp files: + * include/sfo_proto.tmp + * include/sfi_proto.tmp + * util/sfi_data.tmp + * util/sfo_data.tmp + * util/sfnormalize.tmp + * Final files: + * sfdata.c + * sfproto.h + * + */ + +/* avoid global.h define */ +#define STRNCMPI + +#include "hack.h" +#include "integer.h" +#include "wintype.h" + +#ifdef __GNUC__ +#include +#ifndef WIN32 +#define strncmpi strncasecmp +#endif +#define strcmpi strcasecmp +#elif defined(_MSC_VER) +#define strcmpi _stricmp +#ifndef strncmpi +#define strncmpi _strnicmp +#endif +#endif + +#if 0 +/* version information */ +#ifdef SHORT_FILENAMES +#include "patchlev.h" +#else +#include "patchlevel.h" +#endif +#endif + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 +struct nhdatatypes_t { + uint dtclass; + char *dtype; + size_t dtsize; +}; + +struct tagstruct { + uint marker; + int linenum; + char ptr[128]; + char tag[100]; + char filename[128]; + char searchtext[255]; + char tagtype; + char parent[100]; + char parenttype[100]; + char arraysize1[100]; + char arraysize2[100]; + struct tagstruct *next; +}; + +struct needs_array_handling { + const char *nm; + const char *parent; +}; + +#define SFO_DATA c_sfodata +#define SFI_DATA c_sfidata +#define SFDATATMP c_sfdatatmp +#define SFO_PROTO c_sfoproto +#define SFI_PROTO c_sfiproto +#define SFDATA c_sfdata +#define SFPROTO c_sfproto +#define SF_NORMALIZE_POINTERS c_sfnormalize +#define SFPROTO_NAME "../include/sfproto.h" +#define SFDATA_NAME "../util/sfdata.c" + +static char *fgetline(FILE*); +ATTRNORETURN static void quit(void) NORETURN; +static void out_of_memory(void); +static void doline(char *); +static void chain(struct tagstruct *); +#if 0 +static void showthem(void); +static char *stripspecial(char *); +#endif +static char *deblank(char *); +static char *deeol(char *); +static void generate_c_files(void); +static char *findtype(char *, char *); +#if 0 +static boolean is_prim(char *); +#endif +static void taglineparse(char *, struct tagstruct *); +static void parseExtensionFields(struct tagstruct *, char *); +static void set_member_array_size(struct tagstruct *); +#if 0 +static char *member_array_dims(struct tagstruct *, char *); +static char *member_array_size(struct tagstruct *, char *); +#endif +static void output_types(FILE *); +#if 0 +static char *dtmacro(const char *,int); +#endif +static char *dtfn(const char *,int, boolean *); +static char *bfsize(const char *); +static char *fieldfix(char *,char *); +static boolean listed(struct tagstruct *t); +static const char *fn(const char *f); +static boolean no_x(const char *s); + +#ifdef VMS +static FILE *vms_fopen(name, mode) const char *name, *mode; +{ + return fopen(name, mode, "mbc=64", "shr=nil"); +} +# define fopen(f,m) vms_fopen(f,m) +#endif + +#define Fprintf (void) fprintf +#ifndef __GO32__ +#define DEFAULTTAGNAME "../util/sf.tags" +#else +#define DEFAULTTAGNAME "../util/sftags.tag" +#endif +#ifndef _MAX_PATH +#define _MAX_PATH 120 +#endif + +#define TAB '\t' +#define SPACE ' ' + +#ifdef MACOS +#define ALIGN32 __attribute__((aligned(32))) +#else +#define ALIGN32 +#endif + +struct tagstruct *first; +struct tagstruct zerotag = { 0 }; + +static int tagcount; +static const char *infilenm; +static FILE *infile; +static char line[2048]; +static long lineno; +static char ssdef[BUFSZ]; +static char fieldfixbuf[BUFSZ]; +static boolean suppress_count; +static char folderprefix[BUFSZ]; +static char filenmbuf[ +#if defined(UNIX) && defined(PATHLEN) + PATHLEN +#elif defined(WIN32) && defined(_MAX_PATH) + _MAX_PATH +#else + BUFSZ * 4 +#endif + ]; + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 + +struct nhdatatypes_t readtagstypes[] = { + { NHTYPE_SIMPLE, (char *) "any", sizeof(anything) }, + { NHTYPE_SIMPLE, (char *) "genericptr_t", sizeof(genericptr_t) }, + { NHTYPE_SIMPLE, (char *) "aligntyp", sizeof(aligntyp) }, + { NHTYPE_SIMPLE, (char *) "Bitfield", sizeof(uint8_t) }, + { NHTYPE_SIMPLE, (char *) "boolean", sizeof(boolean) }, + { NHTYPE_SIMPLE, (char *) "char", sizeof(char) }, + { NHTYPE_SIMPLE, (char *) "int", sizeof(int) }, + { NHTYPE_SIMPLE, (char *) "long", sizeof(long) }, + { NHTYPE_SIMPLE, (char *) "schar", sizeof(schar) }, + { NHTYPE_SIMPLE, (char *) "short", sizeof(short) }, + { NHTYPE_SIMPLE, (char *) "size_t", sizeof(size_t) }, + { NHTYPE_SIMPLE, (char *) "string", 1 }, + { NHTYPE_SIMPLE, (char *) "time_t", sizeof(time_t) }, + { NHTYPE_SIMPLE, (char *) "uchar", sizeof(uchar) }, + { NHTYPE_SIMPLE, (char *) "unsigned char", sizeof(unsigned char) }, + { NHTYPE_SIMPLE, (char *) "uint", sizeof(uint) }, + { NHTYPE_SIMPLE, (char *) "unsigned long", sizeof(unsigned long) }, + { NHTYPE_SIMPLE, (char *) "unsigned short", sizeof(unsigned short) }, + { NHTYPE_SIMPLE, (char *) "unsigned", sizeof(unsigned) }, + { NHTYPE_SIMPLE, (char *) "xint8", sizeof(xint8) }, + { NHTYPE_SIMPLE, (char *) "xint16", sizeof(xint16) }, + { NHTYPE_SIMPLE, (char *) "coordxy", sizeof(coordxy) }, + { NHTYPE_COMPLEX, (char *) "align", sizeof(struct align) }, + /* { NHTYPE_COMPLEX, (char *) "attack", sizeof(struct attack) }, */ + /* ^ permonst affil */ + { NHTYPE_COMPLEX, (char *) "arti_info", sizeof(struct arti_info) }, + { NHTYPE_COMPLEX, (char *) "attribs", sizeof(struct attribs) }, + { NHTYPE_COMPLEX, (char *) "bill_x", sizeof(struct bill_x) }, + { NHTYPE_COMPLEX, (char *) "branch", sizeof(struct branch) }, + { NHTYPE_COMPLEX, (char *) "bubble", sizeof(struct bubble) }, + { NHTYPE_COMPLEX, (char *) "cemetery", sizeof(struct cemetery) }, + /*{ NHTYPE_COMPLEX, (char *) "container", sizeof(struct container) }, */ + { NHTYPE_COMPLEX, (char *) "context_info", sizeof(struct context_info) }, + /* context sub-structures */ + { NHTYPE_COMPLEX, (char *) "achievement_tracking", + sizeof(struct achievement_tracking) }, + { NHTYPE_COMPLEX, (char *) "book_info", sizeof(struct book_info) }, + { NHTYPE_COMPLEX, (char *) "dig_info", + sizeof(struct dig_info) }, /* context */ + { NHTYPE_COMPLEX, (char *) "engrave_info", sizeof(struct engrave_info) }, + { NHTYPE_COMPLEX, (char *) "lifelists", sizeof(struct lifelists) }, + { NHTYPE_COMPLEX, (char *) "obj_split", sizeof(struct obj_split) }, + { NHTYPE_COMPLEX, (char *) "polearm_info", sizeof(struct polearm_info) }, + { NHTYPE_COMPLEX, (char *) "takeoff_info", sizeof(struct takeoff_info) }, + { NHTYPE_COMPLEX, (char *) "tin_info", sizeof(struct tin_info) }, + { NHTYPE_COMPLEX, (char *) "tribute_info", sizeof(struct tribute_info) }, + { NHTYPE_COMPLEX, (char *) "victual_info", sizeof(struct victual_info) }, + { NHTYPE_COMPLEX, (char *) "warntype_info", + sizeof(struct warntype_info) }, + /* end of context sub-structures */ + { NHTYPE_COMPLEX, (char *) "d_flags", sizeof(struct d_flags) }, + { NHTYPE_COMPLEX, (char *) "d_level", sizeof(struct d_level) }, + { NHTYPE_COMPLEX, (char *) "damage", sizeof(struct damage) }, + { NHTYPE_COMPLEX, (char *) "dest_area", sizeof(struct dest_area) }, + { NHTYPE_COMPLEX, (char *) "dgn_topology", sizeof(struct dgn_topology) }, + { NHTYPE_COMPLEX, (char *) "dungeon", sizeof(struct dungeon) }, + { NHTYPE_COMPLEX, (char *) "ebones", sizeof(struct ebones) }, + { NHTYPE_COMPLEX, (char *) "edog", sizeof(struct edog) }, + { NHTYPE_COMPLEX, (char *) "egd", sizeof(struct egd) }, + { NHTYPE_COMPLEX, (char *) "emin", sizeof(struct emin) }, + { NHTYPE_COMPLEX, (char *) "engr", sizeof(struct engr) }, + { NHTYPE_COMPLEX, (char *) "epri", sizeof(struct epri) }, + { NHTYPE_COMPLEX, (char *) "eshk", sizeof(struct eshk) }, + { NHTYPE_COMPLEX, (char *) "fakecorridor", sizeof(struct fakecorridor) }, + { NHTYPE_COMPLEX, (char *) "fe", sizeof(struct fe) }, + { NHTYPE_COMPLEX, (char *) "flag", sizeof(struct flag) }, + { NHTYPE_COMPLEX, (char *) "fruit", sizeof(struct fruit) }, + { NHTYPE_COMPLEX, (char *) "gamelog_line", sizeof(struct gamelog_line) }, + { NHTYPE_COMPLEX, (char *) "kinfo", sizeof(struct kinfo) }, + { NHTYPE_COMPLEX, (char *) "levelflags", sizeof(struct levelflags) }, + { NHTYPE_COMPLEX, (char *) "linfo", sizeof(struct linfo) }, + { NHTYPE_COMPLEX, (char *) "ls_t", sizeof(struct ls_t) }, + { NHTYPE_COMPLEX, (char *) "mapseen_feat", sizeof(struct mapseen_feat) }, + { NHTYPE_COMPLEX, (char *) "mapseen_flags", + sizeof(struct mapseen_flags) }, + { NHTYPE_COMPLEX, (char *) "mapseen_rooms", + sizeof(struct mapseen_rooms) }, + { NHTYPE_COMPLEX, (char *) "mapseen", sizeof(mapseen) }, + { NHTYPE_COMPLEX, (char *) "mextra", sizeof(struct mextra) }, + { NHTYPE_COMPLEX, (char *) "mkroom", sizeof(struct mkroom) }, + { NHTYPE_COMPLEX, (char *) "monst", sizeof(struct monst) }, + { NHTYPE_COMPLEX, (char *) "mvitals", sizeof(struct mvitals) }, + { NHTYPE_COMPLEX, (char *) "nhcoord", sizeof(struct nhcoord) }, + { NHTYPE_COMPLEX, (char *) "nhrect", sizeof(struct nhrect) }, + { NHTYPE_COMPLEX, (char *) "novel_tracking", + sizeof(struct novel_tracking) }, + { NHTYPE_COMPLEX, (char *) "obj", sizeof(struct obj) }, + { NHTYPE_COMPLEX, (char *) "objclass", sizeof(struct objclass) }, + { NHTYPE_COMPLEX, (char *) "oextra", sizeof(struct oextra) }, + /* {NHTYPE_COMPLEX, (char *) "permonst", sizeof(struct permonst)}, */ + { NHTYPE_COMPLEX, (char *) "prop", sizeof(struct prop) }, + { NHTYPE_COMPLEX, (char *) "q_score", sizeof(struct q_score) }, + { NHTYPE_COMPLEX, (char *) "rm", sizeof(struct rm) }, + { NHTYPE_COMPLEX, (char *) "s_level", sizeof(struct s_level) }, + { NHTYPE_COMPLEX, (char *) "skills", sizeof(struct skills) }, + { NHTYPE_COMPLEX, (char *) "spell", sizeof(struct spell) }, + { NHTYPE_COMPLEX, (char *) "stairway", sizeof(struct stairway) }, +#ifdef SYSFLAGS + { NHTYPE_COMPLEX, (char *) "sysflag", sizeof(struct sysflag) }, +#endif + { NHTYPE_COMPLEX, (char *) "trap", sizeof(struct trap) }, + /* {NHTYPE_COMPLEX, (char *) "u_achieve", sizeof(struct u_achieve)}, */ + { NHTYPE_COMPLEX, (char *) "u_conduct", sizeof(struct u_conduct) }, + { NHTYPE_COMPLEX, (char *) "u_event", sizeof(struct u_event) }, + { NHTYPE_COMPLEX, (char *) "u_have", sizeof(struct u_have) }, + { NHTYPE_COMPLEX, (char *) "u_realtime", sizeof(struct u_realtime) }, + { NHTYPE_COMPLEX, (char *) "u_roleplay", sizeof(struct u_roleplay) }, + { NHTYPE_COMPLEX, (char *) "version_info", sizeof(struct version_info) }, + { NHTYPE_COMPLEX, (char *) "vlaunchinfo", sizeof(union vlaunchinfo) }, + { NHTYPE_COMPLEX, (char *) "vptrs", sizeof(union vptrs) }, + { NHTYPE_COMPLEX, (char *) "you", sizeof(struct you) }, +}; + + +/* + * These have arrays of other structs, not just arrays of + * simple types. We need to put array handling right into + * the code for these ones. + */ +struct needs_array_handling nah[] = { + {"fakecorr", (char *) "egd"}, + {"bill", "eshk"}, + {"msrooms", "mapseen"}, + {"mtrack", "monst"}, + {"ualignbase", "you"}, + {"weapon_skills", "you"}, +}; + +/* conditional code tags - eecch */ +const char *condtag[] = { +#ifdef SYSFLAGS + "sysflag","altmeta","#ifdef AMIFLUSH", "", + "sysflag","amiflush","","#endif /*AMIFLUSH*/", + "sysflag","numcols", "#ifdef AMII_GRAPHICS", "", + "sysflag","amii_dripens","","", + "sysflag","amii_curmap","","#endif", + "sysflag","fast_map", "#ifdef OPT_DISMAP", "#endif", + "sysflag","asksavedisk","#ifdef MFLOPPY","#endif", + "sysflag","page_wait", "#ifdef MAC", "#endif", +#endif + "linfo","where","#ifdef MFLOPPY","", + "linfo","time","","", + "linfo","size","","#endif /*MFLOPPY*/", + "obj","oinvis","#ifdef INVISIBLE_OBJECTS", "#endif", + (char *)0,(char *)0,(char *)0, (char *)0 +}; + +DISABLE_WARNING_UNREACHABLE_CODE + +int main(int argc, char *argv[]) +{ + tagcount = 0; +#if defined(WIN32) + char fbuf[_MAX_PATH]; +#endif + + folderprefix[0] = '\0'; + if (argc > 1) infilenm = argv[1]; + if (!infilenm || !*infilenm) infilenm = DEFAULTTAGNAME; + +#if defined(WIN32) + if (!file_exists(infilenm)) { + /* (void) GetCurrentDirectoryA(sizeof cdir, (LPSTR) cdir); */ + Strcpy(folderprefix, "../../../"); + (void) snprintf(fbuf, sizeof fbuf, "%s%s", folderprefix, DEFAULTTAGNAME); + if (!file_exists(fbuf)) { + fprintf(stdout, "%s doesn't exist\n", fbuf); + exit(EXIT_SUCCESS); + } + infilenm = (const char *) fbuf; + } +#endif + + infile = fopen(infilenm,"r"); + if (!infile) { + printf("%s not found or unavailable\n", infilenm); + quit(); + } else { + while (fgets(line, sizeof line, infile)) { + ++lineno; + /* if (lineno == 868) DebugBreak(); */ + doline(line); + } + + fclose(infile); + printf("\nRead in %ld lines and stored %d tags in memory.\n", lineno, + tagcount); +#if 0 + showthem(); +#endif + generate_c_files(); + printf("Created %s\n", SFDATA_NAME); + printf("Created %s\n", SFPROTO_NAME); + exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; + } +} + +#ifdef WIN32 +boolean +file_exists(const char *path) +{ + struct stat sb; + + /* Just see if it's there */ + if (stat(path, &sb)) { + return FALSE; + } + return TRUE; +} +#endif + +RESTORE_WARNINGS + +static void doline(char *aline) +{ + char buf[255], *cp; + struct tagstruct * ALIGN32 tmptag; + size_t slen; + + if (!aline || (aline && *aline == '!')) { + return; + } + cp = deeol(aline); + slen = strlen(cp); + if (slen > sizeof buf - 1) { + slen = sizeof buf - 1; + } + + tmptag = malloc(sizeof *tmptag); + if (!tmptag) { + out_of_memory(); + } + assert(tmptag != 0); + *tmptag = zerotag; + tmptag->marker = 0xDEADBEEF; + + strncpy(buf, cp, slen); + buf[sizeof buf - 1] = '\0'; + taglineparse(buf, tmptag); + chain(tmptag); + return; +} + +struct tagstruct * ALIGN32 prevtag = 0; + +static void +chain(struct tagstruct *tag) +{ + if (!first) { + tag->next = (struct tagstruct *) 0; + first = tag; + } else { + tag->next = (struct tagstruct *) 0; + + if (prevtag->marker == 0xDEADBEEF) { + prevtag->next = tag; + } else { + printf("Error - No previous tag at %s\n", tag->tag); + } + } + prevtag = tag; + ++tagcount; +} +static void quit(void) +{ + exit(EXIT_FAILURE); +} + +static void out_of_memory(void) +{ + printf("maketags: out of memory at line %ld of %s\n", + lineno, infilenm); + quit(); +} + +#if 0 +static char empt[] = {0, 0, 0, 0, 0, 0, 0, 0}; +#endif + +#if 0 +static char *member_array_dims(struct tagstruct *tmptag, char *buf) +{ + if (buf && tmptag) { + if (tmptag->arraysize1[0]) + Sprintf(buf, "[%s]", tmptag->arraysize1); + if (tmptag->arraysize2[0]) + Sprintf(eos(buf), "[%s]", tmptag->arraysize2); + return buf; + } + return empt; +} + +static char *member_array_size(struct tagstruct *tmptag, char *buf) +{ + if (buf && tmptag) { + if (tmptag->arraysize1[0]) + strcpy(buf, tmptag->arraysize1); + if (tmptag->arraysize2[0]) + Sprintf(eos(buf), " * %s", tmptag->arraysize2); + return buf; + } + return empt; +} +#endif + +void set_member_array_size(struct tagstruct *tmptag) +{ + char buf[BUFSZ]; + /* static char result[49]; */ + char *arr1 = (char *)0, *arr2 = (char *)0, *tmp; + int cnt = 0; + + if (!tmptag) return; + strcpy(buf, tmptag->searchtext); + + tmptag->arraysize1[0] = '\0'; + tmptag->arraysize2[0] = '\0'; + + /* find left-open square bracket */ + tmp = strchr(buf, '['); + if (tmp) { + arr1 = tmp; + *tmp = '\0'; + --tmp; + /* backup and make sure the [] are on the right tag */ + while (!(*tmp == SPACE || *tmp == TAB || *tmp ==',' || cnt > 50)) { + --tmp; + cnt++; + } + if (cnt > 50) return; + tmp++; + if (strcmp(tmp, tmptag->tag) == 0) { + ++arr1; + tmp = strchr(arr1, ']'); + if (tmp) { + arr2 = tmp; + ++arr2; + *tmp = '\0'; + if (*arr2 == '[') { /* two-dimensional array */ + ++arr2; + tmp = strchr(arr2, ']'); + if (tmp) *tmp = '\0'; + } else { + arr2 = (char *)0; + } + } + } else { + arr1 = (char *)0; + } + } + if (arr1) (void)strcpy(tmptag->arraysize1, arr1); + if (arr2) (void)strcpy(tmptag->arraysize2, arr2); +} + +static void parseExtensionFields (struct tagstruct *tmptag, char *buf) +{ + char *p = buf; +#ifdef WIN32 + int debug_catch = 0; +#endif + + while (p != (char *)0 && *p != '\0') { + while (*p == TAB) + *p++ = '\0'; + if (*p != '\0') { + char *colon; + char *field = p; + + p = strchr (p, TAB); + if (p != (char *)0) + *p++ = '\0'; + colon = strchr (field, ':'); + if (colon == (char *)0) { + tmptag->tagtype = *field; + } else { + char *key = field; + char *value = colon + 1; + *colon = '\0'; + if ((strcmp (key, "struct") == 0) || + (strcmp (key, "union") == 0)) { +#ifdef WIN32 + if (!strcmp(key, "union")) + debug_catch = 1; +#endif + colon = strstr(value,"::"); + if (colon) + value = colon +2; + strcpy(tmptag->parenttype, key); + strcpy(tmptag->parent, value); + } + } + } + } +} + +void +taglineparse(char *p, struct tagstruct *tmptag) +{ + int fieldsPresent = 0; + char *pattern = 0, *tmp1 = 0; + int linenumber = 0; + char *tab = strchr (p, TAB); + + if (tab != NULL) { + *tab = '\0'; + strcpy(tmptag->tag,p); + p = tab + 1; + tab = strchr (p, TAB); + if (tab != NULL) { + *tab = '\0'; + p = tab + 1; + if (*p == '/' || *p == '?') { + /* parse pattern */ + int delimiter = *(unsigned char *) p; + linenumber = 0; + pattern = p; + do { + p = strchr (p + 1, delimiter); + } while (p != (char *)0 && *(p - 1) == '\\'); + + if (p == (char *)0) { + /* invalid pattern */ + } else + ++p; + } else if (isdigit ((int) *(unsigned char *) p)) { + /* parse line number */ + pattern = p; + linenumber = atol(p); + while (isdigit((int) *(unsigned char *) p)) + ++p; + } else { + /* invalid pattern */ + } + fieldsPresent = (strncmp (p, ";\"", 2) == 0); + *p = '\0'; + + if (fieldsPresent) + parseExtensionFields (tmptag, p + 2); + } + } + assert(pattern != NULL); + + strcpy(tmptag->searchtext, pattern); + tmptag->linenum = linenumber; + + /* add the array dimensions */ + set_member_array_size(tmptag); + + /* determine if this is a pointer and mark it as such */ + if (tmptag->searchtext[0] && + (tmptag->tagtype == 'm' || tmptag->tagtype == 's')) { + char ptrbuf[BUFSZ], searchbuf[BUFSZ]; + + (void) strcpy(ptrbuf, tmptag->searchtext); + Sprintf(searchbuf,"*%s", tmptag->tag); + tmp1 = strstr(ptrbuf, searchbuf); + if (!tmp1) { + Sprintf(searchbuf,"* %s", tmptag->tag); + tmp1 = strstr(ptrbuf, searchbuf); + } + if (tmp1) { + while ((tmp1 > ptrbuf) && (*tmp1 != SPACE) && + (*tmp1 != TAB) && (*tmp1 != ',')) + tmp1--; + tmp1++; + while (*tmp1 == '*') + tmp1++; + *tmp1 = '\0'; + /* now find the first * before this in case multiple things + are declared on this line */ + tmp1 = strchr(ptrbuf+2, '*'); + if (tmp1) { + tmp1++; + *tmp1 = '\0'; + tmp1 = ptrbuf + 2; + while (*tmp1 == SPACE || *tmp1 == TAB || *tmp1 == ',') + ++tmp1; + (void)strcpy(tmptag->ptr, tmp1); + } + } + } +} + +static char stripbuf[255]; + +#if 0 +static char *stripspecial(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if (*st >= SPACE) + *out++ = *st++; + else + st++; + } + *out = '\0'; + return stripbuf; +} +#endif + +static char *deblank(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if (*st == SPACE) { + *out++ = '_'; + st++; + } else + *out++ = *st++; + } + *out = '\0'; + return stripbuf; +} + +static char *deeol(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if ((*st == '\r') || (*st == '\n')) { + st++; + } else + *out++ = *st++; + } + *out = '\0'; + return stripbuf; +} + +#if 0 +static void showthem(void) +{ + char buf[BUFSZ], *tmp; + struct tagstruct *t = first; + while(t) { + printf("%-28s %c, %-16s %-10s", t->tag, t->tagtype, + t->parent, t->parenttype); +#if 0 + t->parent[0] ? t->searchtext : ""); +#endif + buf[0] = '\0'; + tmp = member_array_dims(t,buf); + if (tmp) printf("%s", tmp); + printf("%s","\n"); + t = t->next; + } +} +#endif + +#if 0 +static boolean +is_prim(char *sdt) +{ + int k = 0; + if (sdt) { + /* special case where we don't match entire thing */ + if (!strncmpi(sdt, "Bitfield",8)) + return TRUE; + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (!strcmpi(readtagstypes[k].dtype, sdt)) { + if (readtagstypes[k].dtclass == NHTYPE_SIMPLE) + return TRUE; + else + return FALSE; + } + } + } + return FALSE; +} +#endif + +char * +findtype(char *st, char *tag) +{ + static char ftbuf[512]; + static char prevbuf[512]; + char *tmp1, *tmp2, *tmp3, *tmp4; + const char *r; + + if (!st) return (char *)0; + +#if 0 + if (st && strstr(st, "mapseen")) { + int xx = 0; + + xx++; + } +#endif + if (st[0] == '/' && st[1] == '^') { + tmp2 = tmp3 = tmp4 = (char *)0; + tmp1 = &st[3]; + while (*tmp1) { + if (isspace(*tmp1)) + ; /* skip it */ + else + break; + ++tmp1; + } + if (!strncmp(tmp1, tag, strlen(tag))) { + if(strlen(tag) == 1) { + char *sc = tmp1; + /* Kludge: single char match is too iffy, + check to make sure its a complete + token that we're comparing to. */ + ++sc; + if (!(*sc == '_' || (*sc > 'a' && *sc < 'z') || + (*sc > 'A' && *sc < 'Z') || (*sc > '0' && *sc < '9'))) + return (char *)0; + } else { + return (char *)0; + } + } + if (*tmp1) { + if (!strncmp(tmp1, "Bitfield", 8)) { + strcpy(ftbuf, tmp1); + tmp1 = ftbuf; + tmp3 = strchr(tmp1, ')'); + if (tmp3) { + tmp3++; + *tmp3 = '\0'; + return ftbuf; + } + return (char *)0; + } + } + if (*tmp1) { + int prevchar = 0; + strcpy(ftbuf, tmp1); + tmp1 = ftbuf; + /* find space separating first word with second */ + while (!isspace(*tmp1)) { + prevchar = *tmp1; + ++tmp1; + } + + prevchar = 0; + /* some oddball cases */ + if (prevchar == ',' || prevchar == ';') { + tmp3 = strchr(ftbuf, ','); + tmp2 = strstr(ftbuf, tag); + return prevbuf; + } else { + int chkcnt = 0; + + /* a comma means that more than one thing declared on ine */ + tmp3 = strchr(tmp1, ','); + while (chkcnt < 3 && (tmp2 = strstr(tmp1, tag)) + && (prevchar = *(tmp2 - 1)) + && ((prevchar == '_') + || (prevchar >= 'a' && prevchar <= 'z') + || (prevchar >= 'A' && prevchar <= 'Z') + || (prevchar >= '0' && prevchar <= '9'))) { + tmp1 = tmp2 + 1; + chkcnt++; + } + } + /* make sure we're matching a complete token */ + if (tmp2) { + tmp4 = tmp2 + strlen(tag); + if ((*tmp4 == '_') || (*tmp4 >= 'a' && *tmp4 <= 'z') || + (*tmp4 >= 'A' && *tmp4 <= 'Z') || (*tmp4 >= '0' && *tmp4 <= '9')) + /* jump to next occurence then */ + tmp2 = strstr(tmp4, tag); + } + /* tag w/o comma OR tag found w comma and tag before comma */ + if ((tmp2 && !tmp3) || ((tmp2 && tmp3) && (tmp2 < tmp3))) { + *tmp2 = '\0'; + --tmp2; + while (isspace(*tmp2)) + --tmp2; + tmp2++; + *tmp2 = '\0'; + } + /* comma and no tag OR tag w comma and comma before tag */ + else if ((tmp3 && !tmp2) || ((tmp2 && tmp3) && (tmp3 < tmp2))) { + --tmp3; + if (isspace(*tmp3)) { + while (isspace(*tmp3)) + --tmp3; + } + while (!isspace(*tmp3) && (*tmp3 != '*')) + --tmp3; + while (isspace(*tmp3)) + --tmp3; + tmp3++; + *tmp3 = '\0'; + } + /* comma or semicolon immediately following tag */ + else { + volatile int y = 0; + nhUse(y); + y = 1; + } + if (strncmpi(ftbuf, "struct ", 7) == 0) + r = (const char *) (ftbuf + 7); + else if (strncmpi(ftbuf, "union ", 6) == 0) + r = (const char *) (ftbuf + 6); + /* a couple of kludges follow unfortunately */ + else if (strncmpi(ftbuf, "coord", 5) == 0 + && strncmpi(ftbuf, "coordxy", 7) != 0) + r = "nhcoord"; + else if (strncmpi(ftbuf, "anything", 8) == 0) + r = "any"; + else if (strncmpi(ftbuf, "const char", 10) == 0) + r = "char"; + else + r = (const char *) ftbuf; + strcpy(prevbuf, r); + return prevbuf; + } + } + prevbuf[0] = '\0'; + return (char *)0; +} + +int current_type = 64, gotit = 0; + +boolean +listed(struct tagstruct *t) +{ + int k; + + if ((strncmpi(t->tag, "Bitfield", 8) == 0) || + (strcmpi(t->tag, "string") == 0)) + return TRUE; + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (k == current_type) + gotit = k; + /* This needs to be case-sensitive to avoid generating collision + * between 'align' and 'Align'. + */ + if (strcmp(readtagstypes[k].dtype, t->tag) == 0) + return TRUE; + } + return FALSE; +} + +/* TIME_type: type of the argument to time(); we actually use &(time_t) */ +#if defined(BSD) && !defined(POSIX_TYPES) +#define TIME_type long * +#else +#define TIME_type time_t * +#endif +/* LOCALTIME_type: type of the argument to localtime() */ +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ + || (defined(BSD) && !defined(POSIX_TYPES)) +#define LOCALTIME_type long * +#else +#define LOCALTIME_type time_t * +#endif + +const char *preamble[] = { + "/* Copyright (c) NetHack Development Team %d. */\n", + "/* NetHack may be freely redistributed. See license for details. */\n\n", + "/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE! */\n\n", + "#include \"hack.h\"\n", + "#include \"artifact.h\"\n", + "#include \"func_tab.h\"\n", + "#include \"integer.h\"\n", + "#include \"wintype.h\"\n", + (char *)0 +}; +char crbuf[BUFSZ]; + +DISABLE_WARNING_FORMAT_NONLITERAL + +static const char *get_preamble(int n) +{ + const char *r = preamble[n]; + + if (!n) { + time_t datetime = 0; + struct tm *lt; + + (void) time((TIME_type) &datetime); + lt = localtime((LOCALTIME_type) &datetime); + Sprintf(crbuf, preamble[0], (1900 + lt->tm_year)); + r = crbuf; + } + return r; +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +static void output_types(FILE *fp1) +{ + int k, cnt /*, hcnt = 1 */; + struct tagstruct *t = first; + + Fprintf(fp1, "%s", + "struct nhdatatypes_t nhdatatypes[] = {\n"); + + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (readtagstypes[k].dtclass == NHTYPE_SIMPLE) { + Fprintf(fp1," {NHTYPE_SIMPLE, (char *) \"%s\", sizeof(%s)},\n", + readtagstypes[k].dtype, + (strncmpi(readtagstypes[k].dtype, "Bitfield", 8) == 0) ? + "uint8_t" : + (strcmpi(readtagstypes[k].dtype, "string") == 0) ? + "uchar" : + (strcmpi(readtagstypes[k].dtype, "any") == 0) ? + "anything" : readtagstypes[k].dtype); +/* dtmacro(readtagstypes[k].dtype,0)); */ +#if 0 + Fprintf(fp2, "#define %s %s%d\n", dtmacro(readtagstypes[k].dtype,1), + (strlen(readtagstypes[k].dtype) > 12) ? "" : + (strlen(readtagstypes[k].dtype) < 5) ? " " : + " ", hcnt++); +#endif + } + } + cnt = 0; + while(t) { + if (listed(t) && ((t->tagtype == 's') || (t->tagtype == 'u'))) { + if (!strcmp(t->tag, "any")) { + t = t->next; + continue; + } + if (cnt > 0) + Fprintf(fp1, "%s", ",\n"); + Fprintf(fp1, " {NHTYPE_COMPLEX, (char *) \"%s\", sizeof(%s %s)}", + t->tag, + (t->tagtype == 's') ? "struct" : "union", t->tag); + cnt += 1; + } + t = t->next; + } + Fprintf(fp1, "%s", "\n};\n\n"); + Fprintf(fp1, "int nhdatatypes_size(void)\n{\n return SIZE(nhdatatypes);\n}\n\n"); +} + +static void generate_c_files(void) +{ + struct tagstruct *t = first; +#ifdef KR1ED + long clocktim = 0; +#else + time_t clocktim = 0; +#endif + char *c, cbuf[60], sfparent[BUFSZ], funcnam[2][BUFSZ], *substruct, *gline, + norm_param_buf[BUFSZ]; + FILE *SFO_DATA, *SFI_DATA, *SFDATATMP, *SFO_PROTO, *SFI_PROTO, + *SFDATA, *SFPROTO, *SF_NORMALIZE_POINTERS; + int k = 0, j /*, opening, , closetag = 0 */; + const char *pt; + /* char *layout; */ + char *ft, *last_ft = (char *)0; + int okeydokey, x, a; + boolean did_i; + boolean normalize_param_used; + +#ifdef WIN32 + int debug_catch = 0; +#endif + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix,SFDATA_NAME); + SFDATA = fopen(filenmbuf, "w"); + if (!SFDATA) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, SFPROTO_NAME); + SFPROTO = fopen(filenmbuf, "w"); + if (!SFPROTO) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfo_data.tmp"); + SFO_DATA = fopen(filenmbuf, "w"); + if (!SFO_DATA) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, "../include/sfo_proto.tmp"); + SFO_PROTO = fopen(filenmbuf, "w"); + if (!SFO_PROTO) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfi_proto.tmp"); + SFI_PROTO = fopen(filenmbuf, "w"); + if (!SFI_PROTO) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfi_data.tmp"); + SFI_DATA = fopen(filenmbuf, "w"); + if (!SFI_DATA) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfdata.tmp"); + SFDATATMP = fopen(filenmbuf, "w"); + if (!SFDATATMP) return; + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfnormptrs.tmp"); + SF_NORMALIZE_POINTERS = fopen(filenmbuf, "w"); + if (!SF_NORMALIZE_POINTERS) return; + + (void) time(&clocktim); + Strcpy(cbuf, ctime(&clocktim)); + + for (c = cbuf; *c; c++) + if (*c == '\n') + break; + *c = '\0'; /* strip off the '\n' */ + + /* begin sfproto.h */ + Fprintf(SFPROTO,"/* NetHack %d.%d sfproto.h */\n", + VERSION_MAJOR, VERSION_MINOR); + for (j = 0; j < 3; ++j) + Fprintf(SFPROTO, "%s", get_preamble(j)); + Fprintf(SFPROTO, "#ifndef SFPROTO_H\n#define SFPROTO_H\n\n"); + Fprintf(SFPROTO, "#include \"hack.h\"\n#include \"integer.h\"\n#include \"wintype.h\"\n\n"); + + Fprintf(SFPROTO,"%s\n", "extern int critical_members_count(void);"); + Fprintf(SFPROTO,"%s\n", "extern void sfo_bitfield(NHFILE *, uint8_t *, const char *, int);"); + Fprintf(SFPROTO,"%s\n", "extern void sfi_bitfield(NHFILE *, uint8_t *, const char *, int);"); + Fprintf(SFO_PROTO, "/* generated output functions */\n"); + Fprintf(SFI_PROTO, "/* generated input functions */\n"); + + /* begin sfdata.c */ + Fprintf(SFDATA,"/* NetHack %d.%d sfdata.c */\n", + VERSION_MAJOR, VERSION_MINOR); + for (j = 0; preamble[j]; ++j) + Fprintf(SFDATA, "%s", get_preamble(j)); + Fprintf(SFDATA, "#include \"sfprocs.h\"\n"); + Fprintf(SFDATA, "#include \"sfproto.h\"\n\n"); + Fprintf(SFDATA, "#define NHTYPE_SIMPLE 1\n"); + Fprintf(SFDATA, "#define NHTYPE_COMPLEX 2\n\n"); + Fprintf(SFDATA, "struct nhdatatypes_t {\n"); + Fprintf(SFDATA, " uint dtclass;\n"); + Fprintf(SFDATA, " char *dtype;\n"); + Fprintf(SFDATA, " size_t dtsize;\n};\n\n"); + Fprintf(SFDATA,"static uint8_t bitfield = 0;\n"); + + /* begin sfnormptrs.tmp */ + Fprintf(SF_NORMALIZE_POINTERS, + "void norm_ptrs_any(union any *d_any);\n\n"); + Fprintf(SF_NORMALIZE_POINTERS, + "void\n" + "norm_ptrs_any(union any *d_any UNUSED)\n" + "{\n" + "}\n"); + + output_types(SFDATATMP); + Fprintf(SFDATATMP, "const char *critical_members[] = {\n"); + + k = 0; + did_i = FALSE; + while(k < SIZE(readtagstypes)) { + boolean insert_const = FALSE; + suppress_count = TRUE; + + if (readtagstypes[k].dtclass == NHTYPE_COMPLEX) { + + + if (!strncmpi(readtagstypes[k].dtype,"Bitfield",8)) { + Fprintf(SFO_DATA, + "\nvoid\nsfo_bitfield(nhfp,\n" + "NHFILE *nhfp,\n" + "uint8_t *d_bitfield,\n" + "const char *myname\n" + "int bflen)\n" + "{\n"); + + Fprintf(SFI_DATA, + "\nvoid\nsfi_bitfield(\n" + "NHFILE *nhfp,\n" + "uint8_t *d_bitfield,\n" + "const char *myname\n" + "int bflen)\n" + "{\n"); + } + + +#if 0 + if (!strncmpi(readtagstypes[k].dtype,"version_info",8)) + insert_const = TRUE; +#endif +#ifdef WIN32 + if (!strncmpi(readtagstypes[k].dtype, "vlaunchinfo", 11) + || !strncmpi(readtagstypes[k].dtype, "vptrs", 5) + || k == SIZE(readtagstypes) - 2) + debug_catch = TRUE; +#endif + + pt = (const char *) 0; + t = first; + while(t) { + if (!strcmp(t->tag, readtagstypes[k].dtype)) { + pt = (t->tagtype == 'u') ? "union" : "struct"; + break; + } + t = t->next; + } + if (!pt) { + pt = "struct"; + } + + (void) snprintf(funcnam[0], sizeof funcnam[0], "sfo_x_%s", readtagstypes[k].dtype); + Fprintf(SFO_PROTO, + "extern void %s(NHFILE *, %s%s %s *, const char *);\n", + fn(funcnam[0]), + insert_const ? "const " : "", + pt, readtagstypes[k].dtype); + + Fprintf(SFO_DATA, + "\nvoid\n%s(\n" + "NHFILE *nhfp,\n" + "%s%s %s *d_%s,\n" + "const char *myname)\n" + "{\n", + fn(funcnam[0]), +/* deblank(readtagstypes[k].dtype), */ + insert_const ? "const " : "", + pt, readtagstypes[k].dtype, + deblank(readtagstypes[k].dtype)); + +#if 0 + Fprintf(SFO_DATA, + " const char *parent = \"%s\";\n", + readtagstypes[k].dtype); +#endif + + (void) snprintf(funcnam[0], sizeof funcnam[0], "sfi_x_%s", + readtagstypes[k].dtype); + Fprintf(SFI_PROTO, + "extern void %s(NHFILE *, %s%s %s *, const char *);\n", + fn(funcnam[0]), + insert_const ? "const " : "", + pt, readtagstypes[k].dtype); + + Fprintf(SFI_DATA, + "\nvoid\n%s(\n" + "NHFILE *nhfp,\n" + "%s%s %s *d_%s,\n" + "const char *myname)\n" + "{\n", + fn(funcnam[0]), +/* deblank(readtagstypes[k].dtype), */ + insert_const ? "const " : "", + pt, readtagstypes[k].dtype, + deblank(readtagstypes[k].dtype)); + +#if 0 + Fprintf(SFI_DATA, + " const char *parent = \"%s\";\n", + readtagstypes[k].dtype); +#endif + + Sprintf(sfparent, "%s %s", pt, readtagstypes[k].dtype); + + + Fprintf(SF_NORMALIZE_POINTERS, + "\nvoid norm_ptrs_%s(%s " + "*d_%s);\n", + readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); + Fprintf(SF_NORMALIZE_POINTERS, + "\nvoid\nnorm_ptrs_%s(%s " + "*d_%s)\n{\n", + readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); + Snprintf(norm_param_buf, sizeof norm_param_buf, "d_%s", + readtagstypes[k].dtype); + + for (a = 0; a < SIZE(nah); ++a) { + if (!strcmp(nah[a].parent, readtagstypes[k].dtype)) { + if (!did_i) { + Fprintf(SFO_DATA, " int i;\n"); + Fprintf(SFI_DATA, " int i;\n"); + did_i = TRUE; + } + } + } + + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + Fprintf(SFO_DATA, " nhUse(myname);\n"); + Fprintf(SFI_DATA, " nhUse(myname);\n"); + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + /******************************************************** + * cycle through all the tags and find every tag with * + * a parent matching readtagstypes[k].dtype * + ********************************************************/ + + t = first; + normalize_param_used = FALSE; + + while(t) { + x = 0; + okeydokey = 0; +/* + if (!strcmp(t->tag, "nextc") + && !strcmp(readtagstypes[k].dtype, "engrave_info")) + __debugbreak(); +*/ + + if (t->tagtype == 's') { + char *ss = strstr(t->searchtext,"{$/"); + + if (ss) { + strcpy(ssdef, t->tag); + } + t = t->next; + continue; + } + + /************insert opening conditional if needed ********/ + while(condtag[x]) { + if (!strcmp(condtag[x],readtagstypes[k].dtype) && + !strcmp(condtag[x+1],t->tag)) { + okeydokey = 1; + break; + } + x = x + 4; + } + + /* some structs are entirely defined within another struct declaration. + * Legal, but a greater challenge for us here. + */ + substruct = strstr(t->parent, "::"); + if (substruct) { + substruct += 2; + } + + if ((strcmp(readtagstypes[k].dtype, t->parent) == 0) || + (substruct && strcmp(readtagstypes[k].dtype, substruct) == 0)) { + ft = (char *)0; + + if (t->ptr[0] != '\0') + ft = &t->ptr[0]; + else + ft = findtype(t->searchtext, t->tag); + + if (ft) { + last_ft = ft; + if (okeydokey && condtag[x+2] && strlen(condtag[x+2]) > 0) { + Fprintf(SFO_DATA,"%s\n", condtag[x+2]); + Fprintf(SFI_DATA,"%s\n", condtag[x+2]); + Fprintf(SFDATATMP,"%s\n", condtag[x+2]); + } + } else { + /* use the last found one as last resort then */ + ft = last_ft; + } + + /***************** Bitfield *******************/ + if (!strncmpi(ft, "Bitfield", 8)) { + char lbuf[BUFSZ]; + int j2, z; + + Sprintf(lbuf, + " " + "bitfield = d_%s->%s;", + readtagstypes[k].dtype, t->tag); + z = (int) strlen(lbuf); + for (j2 = 0; j2 < (65 - z); ++j2) + Strcat(lbuf, " "); + Sprintf(eos(lbuf), "/* (%s) */\n", ft); + Fprintf(SFO_DATA, "%s", lbuf); + Fprintf(SFO_DATA, + " " + "sfo_bitfield(nhfp, &bitfield, \"%s\", %s);\n", + t->tag, bfsize(ft)); +#if 0 + Fprintf(SFI_DATA, + " " + "bitfield = 0;\n"); +#else + Fprintf(SFI_DATA, + " " + "bitfield = d_%s->%s; /* set it to current value for testing */\n", + readtagstypes[k].dtype, t->tag); +#endif + Fprintf(SFI_DATA, + " " + "sfi_bitfield(nhfp, &bitfield, \"%s\", %s);\n", + t->tag, bfsize(ft)); + + Fprintf(SFI_DATA, + " " + "d_%s->%s = bitfield;\n\n", + readtagstypes[k].dtype, t->tag); + Fprintf(SFDATATMP, + " \"%s:%s:%s\",\n", + sfparent, t->tag, ft); + } else { + /**************** not a bitfield ****************/ + char arrbuf[BUFSZ]; + char lbuf[BUFSZ * 2]; /* sprintf target for others, gcc + complaint */ + char fnbuf[BUFSZ]; + char altbuf[BUFSZ]; + boolean isptr = FALSE, kludge_sbrooms = FALSE, array_of_ptrs = FALSE; + boolean insert_loop = FALSE; + int j2, z; + + altbuf[0] = '\0'; + /*************** kludge for sbrooms *************/ + if (!strcmp(t->tag, "sbrooms")) { + kludge_sbrooms = TRUE; + (void) strcpy(t->arraysize1, "MAX_SUBROOMS"); + insert_loop = TRUE; + array_of_ptrs = TRUE; + } + if (!strcmp(t->parent, "engr") + && !strcmp(t->tag, "engr_txt")) { + (void) strcpy(t->arraysize1, "text_states"); + insert_loop = TRUE; + array_of_ptrs = TRUE; + } + if (t->arraysize2[0]) { + Sprintf(arrbuf, "(%s * %s)", t->arraysize1, + t->arraysize2); + isptr = TRUE; /* suppress the & in function args */ + } else if (t->arraysize1[0]) { + Sprintf(arrbuf, "%s", t->arraysize1); + isptr = TRUE; /* suppress the & in function args */ + } else { + Strcpy(arrbuf, "1"); + } + Strcpy(fnbuf, dtfn(ft, 0, &isptr)); + /* + * determine if this is one of the special cases + * where there's an array of structs instead of + * an array of simple types. We need to insert + * a for loop in those cases. + */ + for (a = 0; a < SIZE(nah); ++a) { + if (!strcmp(nah[a].parent, t->parent)) + if (!strcmp(nah[a].nm, t->tag)) + insert_loop = TRUE; + } + if (isptr && !strcmp(fnbuf, readtagstypes[k].dtype)) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->ptr, "struct permonst *") + || !strcmp(t->ptr, "struct monst *") + || !strcmp(t->ptr, "struct obj *") + || !strcmp(t->ptr, "struct cemetery *") + || !strcmp(t->ptr, "struct container *") + || !strcmp(t->ptr, "struct mextra *") + || !strcmp(t->ptr, "struct oextra *") + || !strcmp(t->ptr, "struct s_level *") + || !strcmp(t->ptr, "struct bill_x *") + || !strcmp(t->ptr, "struct trap *") + || !strcmp(t->ptr, "struct egd *") + || !strcmp(t->ptr, "struct epri *") + || !strcmp(t->ptr, "struct eshk *") + || !strcmp(t->ptr, "struct emin *") + || !strcmp(t->ptr, "struct ebones *") + || !strcmp(t->ptr, "struct edog *"))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->parent, "engr") + && !strcmp(t->tag, "engr_txt"))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "br"))) { + Strcpy(altbuf, "genericptr"); + + // } else if (isptr + // && + // (!strcmp(t->parent, + // "engrave_info") + // && + // !strcmp(t->tag, + // "nextc"))) { + // Strcpy(altbuf, + // "genericptr"); + + } else if ( + (isptr && !strcmp(t->ptr, "char *")) + && ((!strcmp(t->parent, "engrave_info") + && !strcmp(t->tag, "nextc")) + || (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "custom")) + || (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "custom")) + || (!strcmp(t->parent, "mextra") + && !strcmp(t->tag, "mgivenname")) + || (!strcmp(t->parent, "gamelog_line") + && !strcmp(t->tag, "text")) + || (!strcmp(t->parent, "oextra") + && !strcmp(t->tag, "oname")) + || (!strcmp(t->parent, "oextra") + && !strcmp(t->tag, "omailcmd")))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr && !strcmp(t->tag, "oc_uname")) { + Strcpy(altbuf, "genericptr"); + } else { + Strcpy(altbuf, fnbuf); + } + if (isptr && (strcmp(altbuf, "genericptr") != 0) + && (t->ptr[0] != 0 + && (*(t->ptr + (strlen(t->ptr) - 1)) == '*') + && (strcmp(t->ptr, altbuf) != 0))) { + fprintf( + stderr, + "WARNING - \"%s\" in %s called \"%s\" " + "resulted in an unexpected set of inputs/outputs " + "(%s)\n", + (t->ptr[0] != 0 && strlen(t->ptr)) ? t->ptr : "unknown", + (t->parent[0] != 0 && strlen(t->parent)) ? t->parent + : "?", + (t->tag[0] != 0 && strlen(t->tag)) ? t->tag : "?", + altbuf); + } + /* kludge for attribs */ + if (!strcmp(readtagstypes[k].dtype, "attribs") + && !strcmp(arrbuf, "A_MAX")) { + insert_loop = TRUE; + } + if (insert_loop) { + Fprintf(SFO_DATA, " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + Fprintf(SFI_DATA, " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + if (array_of_ptrs) { + Fprintf(SF_NORMALIZE_POINTERS, + " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + } + arrbuf[0] = '1'; + arrbuf[1] = '\0'; + } + if (isptr + && (t->ptr[0] != 0 + && (*(t->ptr + (strlen(t->ptr) - 1)) == '*') + && (strcmp(t->ptr, altbuf) != 0))) { + Fprintf( + SF_NORMALIZE_POINTERS, + " %sd_%s->%s%s%s%s = d_%s->%s%s%s%s ? (%s) 1 : (%s) 0;\n", + (insert_loop && array_of_ptrs) ? " " : "", + t->parent, t->tag, + (insert_loop && array_of_ptrs) ? "[" : "", + (insert_loop && array_of_ptrs) ? "i" : "", + (insert_loop && array_of_ptrs) ? "]" : "", + t->parent, t->tag, + (insert_loop && array_of_ptrs) ? "[" : "", + (insert_loop && array_of_ptrs) ? "i" : "", + (insert_loop && array_of_ptrs) ? "]" : "", + t->ptr, + t->ptr); + normalize_param_used = TRUE; + } + Snprintf(lbuf, sizeof lbuf, + " " + "%ssfo%s_%s(nhfp, %s%sd_%s->%s%s, \"%s\"%s%s);", + insert_loop ? " " : "", + (readtagstypes[k].dtclass == NHTYPE_SIMPLE || no_x(altbuf)) ? "" + : "_x", + altbuf, + (isptr && !strcmp(altbuf, "genericptr")) + ? "(genericptr_t) " + : "", + (isptr && !insert_loop && !kludge_sbrooms + && strcmp(altbuf, "genericptr")) + ? "" + : "&", + readtagstypes[k].dtype, t->tag, + insert_loop ? "[i]" + : "", + t->tag, strcmp(altbuf, "char") != 0 ? "" : ", ", + strcmp(altbuf, "char") != 0 ? "" : arrbuf); + /* align comments */ + z = (int) strlen(lbuf); + for (j2 = 0; j2 < (65 - z); ++j2) + Strcat(lbuf, " "); + Sprintf(eos(lbuf), "/* (%s) */\n", ft); + Fprintf(SFO_DATA, "%s", lbuf); + + Snprintf( + lbuf, sizeof lbuf, + " " + "%ssfi%s_%s(nhfp, %s%sd_%s->%s%s, \"%s\"%s%s);\n", + insert_loop ? " " : "", + (readtagstypes[k].dtclass == NHTYPE_SIMPLE + || no_x(altbuf)) + ? "" + : "_x", + altbuf, + (isptr && !strcmp(altbuf, "genericptr")) + ? "(genericptr_t) " + : "", + (isptr && !insert_loop && !kludge_sbrooms + && strcmp(altbuf, "genericptr")) + ? "" + : "&", + readtagstypes[k].dtype, t->tag, + kludge_sbrooms ? "[0]" + : insert_loop ? "[i]" + : "", + t->tag, strcmp(altbuf, "char") != 0 ? "" : ", ", + strcmp(altbuf, "char") != 0 ? "" : arrbuf); + Fprintf(SFI_DATA, "%s", lbuf); + Fprintf(SFDATATMP, + " \"%s:%s:%s\",\n", + sfparent, t->tag,fieldfix(ft,ssdef)); + kludge_sbrooms = FALSE; + array_of_ptrs = FALSE; + altbuf[0] = '\0'; + } + + /************insert closing conditional if needed ********/ + if (okeydokey && condtag[x+3] && strlen(condtag[x+3]) > 0) { + Fprintf(SFO_DATA,"%s\n", condtag[x+3]); + Fprintf(SFI_DATA,"%s\n", condtag[x+3]); + Fprintf(SFDATATMP,"%s\n", condtag[x+3]); + } + } + t = t->next; + } + + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + Fprintf(SFO_DATA, "}\n"); + Fprintf(SFI_DATA, "}\n"); + if (!normalize_param_used) { + Fprintf(SF_NORMALIZE_POINTERS, " nhUse(%s);\n", + norm_param_buf); + } + Fprintf(SF_NORMALIZE_POINTERS, "}\n"); + } + ++k; + did_i = FALSE; + } + + Fprintf(SFDATATMP,"};\n\n"); + Fprintf(SFDATATMP, "int critical_members_count(void)\n{\n return SIZE(critical_members);\n}\n\n"); + + fclose(SFO_DATA); + fclose(SFI_DATA); + fclose(SFO_PROTO); + fclose(SFI_PROTO); + fclose(SFDATATMP); + fclose(SF_NORMALIZE_POINTERS); + + /* Consolidate SFO_* and SFI_* etc into single files */ + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfo_data.tmp"); + SFO_DATA = fopen(filenmbuf, "r"); + if (!SFO_DATA) return; + while ((gline = fgetline(SFO_DATA)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFO_DATA); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfi_data.tmp"); + SFI_DATA = fopen(filenmbuf, "r"); + if (!SFI_DATA) return; + while ((gline = fgetline(SFI_DATA)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFI_DATA); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfo_proto.tmp"); + SFO_PROTO = fopen(filenmbuf, "r"); + if (!SFO_PROTO) return; + while ((gline = fgetline(SFO_PROTO)) != 0) { + (void) fputs(gline, SFPROTO); + free(gline); + } + (void) fclose(SFO_PROTO); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfi_proto.tmp"); + SFI_PROTO = fopen(filenmbuf, "r"); + if (!SFI_PROTO) return; + while ((gline = fgetline(SFI_PROTO)) != 0) { + (void) fputs(gline, SFPROTO); + free(gline); + } + (void) fclose(SFI_PROTO); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfdata.tmp"); + SFDATATMP = fopen(filenmbuf, "r"); + if (!SFDATATMP) return; + while ((gline = fgetline(SFDATATMP)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFDATATMP); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfnormptrs.tmp"); + SF_NORMALIZE_POINTERS = fopen(filenmbuf, "r"); + if (!SF_NORMALIZE_POINTERS) + return; + while ((gline = fgetline(SF_NORMALIZE_POINTERS)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SF_NORMALIZE_POINTERS); + (void) remove(filenmbuf); + + Fprintf(SFDATA, "/*sfdata.c*/\n"); + Fprintf(SFPROTO,"#endif /* SFPROTO_H */\n"); + (void) fclose(SFDATA); + (void) fclose(SFPROTO); +} + +#if 0 +static char * +dtmacro(const char *str, + int n) /* 1 = supress appending |SF_PTRMASK */ +{ + static char buf[128], buf2[128]; + char *nam, *c; + int ispointer = 0; + + if (!str) + return (char *)0; + (void)strncpy(buf, str, 127); + + c = buf; + while (*c) + c++; /* eos */ + + c--; + if (*c == '*') { + ispointer = 1; + *c = '\0'; + c--; + } + while(isspace(*c)) { + c--; + } + *(c+1) = '\0'; + c = buf; + + if (strncmpi(c, "Bitfield", 8) == 0) { + *(c+8) = '\0'; + } else if (strcmpi(c, "genericptr_t") == 0) { + ispointer = 1; + } else if (strncmpi(c, "const ", 6) == 0) { + c = buf + 6; + } else if ((strncmpi(c, "struct ", 7) == 0) || + (strncmpi(c, "struct ", 7) == 0)) { + c = buf + 7; + } else if (strncmpi(c, "union ", 6) == 0) { + c = buf + 6; + } + + /* end of substruct within struct definition */ + if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) { + strcpy(buf,ssdef); + c = buf; + } + + for (nam = c; *c; c++) { + if (*c >= 'a' && *c <= 'z') + *c -= (char)('a' - 'A'); + else if (*c < 'A' || *c > 'Z') + *c = '_'; + } + (void)sprintf(buf2, "SF_%s%s", nam, + (ispointer && (n == 0)) ? " | SF_PTRMASK" : ""); + return buf2; +} +#endif + +static char * +dtfn(const char *str, + int n, /* 1 = supress appending |SF_PTRMASK */ + boolean *isptr) +{ + static char buf[128], buf2[128]; + const char *nam; + char *c; + int ispointer = 0; + + if (!str) + return (char *)0; + (void)strncpy(buf, str, 127); + buf[sizeof buf - 1] = '\0'; + + c = buf; + while (*c) c++; /* eos */ + + c--; + if (*c == '*') { + ispointer = 1; + *c = '\0'; + c--; + } + while(isspace(*c)) { + c--; + } + *(c+1) = '\0'; + c = buf; + + if (strncmpi(c, "Bitfield", 8) == 0) { + *(c+8) = '\0'; + } else if (strcmpi(c, "genericptr_t") == 0) { + ispointer = 1; + } else if (strncmpi(c, "const ", 6) == 0) { + c = buf + 6; + } else if ((strncmpi(c, "struct ", 7) == 0) || + (strncmpi(c, "struct ", 7) == 0)) { + c = buf + 7; + } else if (strncmpi(c, "union ", 6) == 0) { + c = buf + 6; + } + + /* end of substruct within struct definition */ + if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) { + strcpy(buf,ssdef); + c = buf; + } + + for (nam = (const char *) c; *c; c++) { + if (*c >= 'A' && *c <= 'Z') + *c = tolower(*c); + else if (*c == ' ') + *c = '_'; + } + /* some fix-ups */ + if (!strcmp(nam, "genericptr_t")) + nam = "genericptr"; + else if (!strcmp(nam, "unsigned_int")) + nam = "uint"; + else if (!strcmp(nam, "unsigned_long")) + nam = "ulong"; + else if (!strcmp(nam, "unsigned_char")) + nam = "uchar"; + else if (!strcmp(nam, "unsigned_short")) + nam = "ushort"; + + if (ispointer && isptr && n == 0) + *isptr = TRUE; + (void)sprintf(buf2, "%s%s", nam, ""); + return buf2; +} + +static char * +fieldfix(char *f, char *ss) +{ + char *c /*, *dest = fieldfixbuf */; + + if (strcmp(f,"}") == 0 && strlen(ss) > 0 && strlen(ss) < BUFSZ - 1) { + /* (void)sprintf(fieldfixbuf,"struct %s", ss); */ + strcpy(fieldfixbuf,ss); + } else { + if (strlen(f) < BUFSZ - 1) strcpy(fieldfixbuf,f); + } + + /* converting any tabs to space */ + for (c = fieldfixbuf; *c; c++) + if (*c == TAB) *c = SPACE; + + return fieldfixbuf; +} + +static char * +bfsize(const char *str) +{ + static char buf[128]; + char *copy_str, *c1, *c2, *subst; + char *retval = buf; + + if (!str) + return (char *)0; + + copy_str = dupstr(str); + /* kludge */ + subst = strstr(copy_str, ",$/"); + if (subst != 0) { + subst++; + *subst++ = ' '; + *subst++ = '1'; + } + + c2 = buf; + c1 = copy_str; + while (*c1) { + if (*c1 == ',') + break; + c1++; + } + + if (*c1 == ',') { + c1++; + while (*c1 && *c1 != ')') { + *c2++ = *c1++; + } + *c2 = '\0'; + } else { + retval = (char *) 0; + } + free((genericptr_t) copy_str); + return retval; +} + +/* Read one line from input, up to and including the next newline + * character. Returns a pointer to the heap-allocated string, or a + * null pointer if no characters were read. + */ +static char * +fgetline(FILE *fd) +{ + static const int inc = 256; + int len = inc; + char *c = malloc(len), *ret, *loc, *avoidleak; + + if (!c) { + fprintf(stderr, "Memory issue\n"); + quit(); + } + for (;;) { + loc = c + len - inc; + if (!loc) { + quit(); + } + ret = fgets(loc, inc, fd); + if (!ret) { + free(c); + c = NULL; + break; + } else if (strchr(c, '\n')) { + /* normal case: we have a full line */ + break; + } + len += inc; + avoidleak = c; + c = realloc(c, len); + if (!c) { + free(avoidleak); + quit(); + } + } + return c; +} + +#ifndef _MSC_VER +int +strncmpi(const char *s1, const char *s2, size_t n) +{ + register char t1, t2; + + while (n--) { + if (!*s2) + return (*s1 != 0); /* s1 >= s2 */ + else if (!*s1) + return -1; /* s1 < s2 */ + t1 = lowc(*s1++); + t2 = lowc(*s2++); + if (t1 != t2) + return (t1 > t2) ? 1 : -1; + } + return 0; /* s1 == s2 */ +} +#endif + + +struct already_in_sfbase { + int typ; + const char *actual; + const char *replacement; +}; + +/* The ones that can't be broken down into subfields + * are NHTYPE_SIMPLE. + */ +const struct already_in_sfbase already[] = { + /* input */ + { NHTYPE_SIMPLE, "Sfi_any", "Sfi_any" }, + { NHTYPE_SIMPLE, "Sfi_boolean", "Sfi_boolean" }, + { NHTYPE_SIMPLE, "Sfi_char", "Sfi_char" }, + { NHTYPE_SIMPLE, "Sfi_coordxy", "Sfi_coordxy" }, + { NHTYPE_SIMPLE, "Sfi_int16", "Sfi_int16" }, + { NHTYPE_SIMPLE, "Sfi_int32", "Sfi_int32" }, + { NHTYPE_SIMPLE, "Sfi_long", "Sfi_long" }, + { NHTYPE_SIMPLE, "Sfi_nhcoord", "Sfi_nhcoord" }, + { NHTYPE_SIMPLE, "Sfi_schar", "Sfi_schar" }, + { NHTYPE_SIMPLE, "Sfi_uint32", "Sfi_uint32" }, + { NHTYPE_SIMPLE, "Sfi_ulong", "Sfi_ulong" }, + { NHTYPE_SIMPLE, "Sfi_xint8", "Sfi_xint8" }, + { NHTYPE_COMPLEX, "Sfi_arti_info", "Sfi_x_arti_info" }, + { NHTYPE_COMPLEX, "Sfi_branch", "Sfi_x_branch" }, + { NHTYPE_COMPLEX, "Sfi_bubble", "Sfi_x_bubble" }, + { NHTYPE_COMPLEX, "Sfi_cemetery", "Sfi_x_cemetery" }, + { NHTYPE_COMPLEX, "Sfi_context_info", "Sfi_x_context_info" }, + { NHTYPE_COMPLEX, "Sfi_d_level", "Sfi_x_d_level" }, + { NHTYPE_COMPLEX, "Sfi_damage", "Sfi_x_damage" }, + { NHTYPE_COMPLEX, "Sfi_dest_area", "Sfi_x_dest_area" }, + { NHTYPE_COMPLEX, "Sfi_dgn_topology", "Sfi_x_dgn_topology" }, + { NHTYPE_COMPLEX, "Sfi_dungeon", "Sfi_x_dungeon" }, + { NHTYPE_COMPLEX, "Sfi_ebones", "Sfi_x_ebones" }, + { NHTYPE_COMPLEX, "Sfi_edog", "Sfi_x_edog" }, + { NHTYPE_COMPLEX, "Sfi_egd", "Sfi_x_egd" }, + { NHTYPE_COMPLEX, "Sfi_emin", "Sfi_x_emin" }, + { NHTYPE_COMPLEX, "Sfi_engr", "Sfi_x_engr" }, + { NHTYPE_COMPLEX, "Sfi_epri", "Sfi_x_epri" }, + { NHTYPE_COMPLEX, "Sfi_eshk", "Sfi_x_eshk" }, + { NHTYPE_COMPLEX, "Sfi_fe", "Sfi_x_fe" }, + { NHTYPE_COMPLEX, "Sfi_flag", "Sfi_x_flag" }, + { NHTYPE_COMPLEX, "Sfi_fruit", "Sfi_x_fruit" }, + { NHTYPE_COMPLEX, "Sfi_gamelog_line", "Sfi_x_gamelog_line" }, + { NHTYPE_COMPLEX, "Sfi_kinfo", "Sfi_x_kinfo" }, + { NHTYPE_COMPLEX, "Sfi_levelflags", "Sfi_x_levelflags" }, + { NHTYPE_COMPLEX, "Sfi_linfo", "Sfi_x_linfo" }, + { NHTYPE_COMPLEX, "Sfi_ls_t", "Sfi_x_ls_t" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_feat", "Sfi_x_mapseen_feat" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_flags", "Sfi_x_mapseen_flags" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_rooms", "Sfi_x_mapseen_rooms" }, + { NHTYPE_COMPLEX, "Sfi_mkroom", "Sfi_x_mkroom" }, + { NHTYPE_COMPLEX, "Sfi_monst", "Sfi_x_monst" }, + { NHTYPE_COMPLEX, "Sfi_mvitals", "Sfi_x_mvitals" }, + { NHTYPE_COMPLEX, "Sfi_nhrect", "Sfi_x_nhrect" }, + { NHTYPE_COMPLEX, "Sfi_obj", "Sfi_x_obj" }, + { NHTYPE_COMPLEX, "Sfi_objclass", "Sfi_x_objclass" }, + { NHTYPE_COMPLEX, "Sfi_q_score", "Sfi_x_q_score" }, + { NHTYPE_COMPLEX, "Sfi_rm", "Sfi_x_rm" }, + { NHTYPE_COMPLEX, "Sfi_s_level", "Sfi_x_s_level" }, + { NHTYPE_COMPLEX, "Sfi_spell", "Sfi_x_spell" }, + { NHTYPE_COMPLEX, "Sfi_stairway", "Sfi_x_stairway" }, + { NHTYPE_COMPLEX, "Sfi_trap", "Sfi_x_trap" }, + { NHTYPE_COMPLEX, "Sfi_version_info", "Sfi_x_version_info" }, + { NHTYPE_COMPLEX, "Sfi_you", "Sfi_x_you" }, + /* output */ + { NHTYPE_SIMPLE, "Sfo_any", "Sfo_any" }, + { NHTYPE_SIMPLE, "Sfo_boolean", "Sfo_boolean" }, + { NHTYPE_SIMPLE, "Sfo_char", "Sfo_char" }, + { NHTYPE_SIMPLE, "Sfo_coordxy", "Sfo_coordxy" }, + { NHTYPE_SIMPLE, "Sfo_int16", "Sfo_int16" }, + { NHTYPE_SIMPLE, "Sfo_int32", "Sfo_int32" }, + { NHTYPE_SIMPLE, "Sfo_long", "Sfo_long" }, + { NHTYPE_SIMPLE, "Sfo_nhcoord", "Sfo_nhcoord" }, + { NHTYPE_SIMPLE, "Sfo_schar", "Sfo_schar" }, + { NHTYPE_SIMPLE, "Sfo_uint32", "Sfo_uint32" }, + { NHTYPE_SIMPLE, "Sfo_ulong", "Sfo_ulong" }, + { NHTYPE_SIMPLE, "Sfo_xint8", "Sfo_xint8" }, + { NHTYPE_COMPLEX, "Sfo_arti_info", "Sfo_x_arti_info" }, + { NHTYPE_COMPLEX, "Sfo_branch", "Sfo_x_branch" }, + { NHTYPE_COMPLEX, "Sfo_bubble", "Sfo_x_bubble" }, + { NHTYPE_COMPLEX, "Sfo_cemetery", "Sfo_x_cemetery" }, + { NHTYPE_COMPLEX, "Sfo_context_info", "Sfo_x_context_info" }, + { NHTYPE_COMPLEX, "Sfo_d_level", "Sfo_x_d_level" }, + { NHTYPE_COMPLEX, "Sfo_damage", "Sfo_x_damage" }, + { NHTYPE_COMPLEX, "Sfo_dest_area", "Sfo_x_dest_area" }, + { NHTYPE_COMPLEX, "Sfo_dgn_topology", "Sfo_x_dgn_topology" }, + { NHTYPE_COMPLEX, "Sfo_dungeon", "Sfo_x_dungeon" }, + { NHTYPE_COMPLEX, "Sfo_ebones", "Sfo_x_ebones" }, + { NHTYPE_COMPLEX, "Sfo_edog", "Sfo_x_edog" }, + { NHTYPE_COMPLEX, "Sfo_egd", "Sfo_x_egd" }, + { NHTYPE_COMPLEX, "Sfo_emin", "Sfo_x_emin" }, + { NHTYPE_COMPLEX, "Sfo_engr", "Sfo_x_engr" }, + { NHTYPE_COMPLEX, "Sfo_epri", "Sfo_x_epri" }, + { NHTYPE_COMPLEX, "Sfo_eshk", "Sfo_x_eshk" }, + { NHTYPE_COMPLEX, "Sfo_fe", "Sfo_x_fe" }, + { NHTYPE_COMPLEX, "Sfo_flag", "Sfo_x_flag" }, + { NHTYPE_COMPLEX, "Sfo_fruit", "Sfo_x_fruit" }, + { NHTYPE_COMPLEX, "Sfo_gamelog_line", "Sfo_x_gamelog_line" }, + { NHTYPE_COMPLEX, "Sfo_kinfo", "Sfo_x_kinfo" }, + { NHTYPE_COMPLEX, "Sfo_levelflags", "Sfo_x_levelflags" }, + { NHTYPE_COMPLEX, "Sfo_linfo", "Sfo_x_linfo" }, + { NHTYPE_COMPLEX, "Sfo_ls_t", "Sfo_x_ls_t" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_feat", "Sfo_x_mapseen_feat" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_flags", "Sfo_x_mapseen_flags" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_rooms", "Sfo_x_mapseen_rooms" }, + { NHTYPE_COMPLEX, "Sfo_mkroom", "Sfo_x_mkroom" }, + { NHTYPE_COMPLEX, "Sfo_monst", "Sfo_x_monst" }, + { NHTYPE_COMPLEX, "Sfo_mvitals", "Sfo_x_mvitals" }, + { NHTYPE_COMPLEX, "Sfo_nhrect", "Sfo_x_nhrect" }, + { NHTYPE_COMPLEX, "Sfo_obj", "Sfo_x_obj" }, + { NHTYPE_COMPLEX, "Sfo_objclass", "Sfo_x_objclass" }, + { NHTYPE_COMPLEX, "Sfo_q_score", "Sfo_x_q_score" }, + { NHTYPE_COMPLEX, "Sfo_rm", "Sfo_x_rm" }, + { NHTYPE_COMPLEX, "Sfo_s_level", "Sfo_x_s_level" }, + { NHTYPE_COMPLEX, "Sfo_spell", "Sfo_x_spell" }, + { NHTYPE_COMPLEX, "Sfo_stairway", "Sfo_x_stairway" }, + { NHTYPE_COMPLEX, "Sfo_trap", "Sfo_x_trap" }, + { NHTYPE_COMPLEX, "Sfo_version_info", "Sfo_x_version_info" }, + { NHTYPE_COMPLEX, "Sfo_you", "Sfo_x_you" }, +}; + +static const char * +fn(const char *f) +{ + int i; + + for (i = 0; i < SIZE(already); ++i) { + if (!strcmp(already[i].actual, f)) + return already[i].replacement; + } + return f; +} + +const char *force_no_x[] = { + "aligntyp", "any", "boolean", "char", "coordxy", "genericptr", + "int", "int16", "int32", "int64", "long", "schar", + "short", "size_t", "time_t", "uchar", "uint32", "uint64", + "ulong", "unsigned", "ushort", "xint16", "xint8", +}; + +static boolean +no_x(const char *s) +{ + int i; + + for (i = 0; i < SIZE(force_no_x); ++i) { + if (!strcmp(force_no_x[i], s)) + return TRUE; + } + return FALSE; +} + +struct nh_classification { + int in_sfbase; + uint dtclass; + const char *fn; + const char *replacement_fn; +}; + +struct nh_classification nhdatatypes[] = { + { 0, NHTYPE_COMPLEX, "sfi_achievement_tracking", + "sfi_achievement_tracking" }, + { 0, NHTYPE_COMPLEX, "sfi_align", "sfi_align" }, + { 0, NHTYPE_COMPLEX, "sfi_attribs", "sfi_attribs" }, + { 0, NHTYPE_COMPLEX, "sfi_bill_x", "sfi_bill_x" }, + { 0, NHTYPE_COMPLEX, "sfi_book_info", "sfi_book_info" }, + { 0, NHTYPE_COMPLEX, "sfi_branch", "sfi_branch" }, + { 0, NHTYPE_COMPLEX, "sfi_bubble", "sfi_bubble" }, + { 0, NHTYPE_COMPLEX, "sfi_cemetery", "sfi_cemetery" }, + { 0, NHTYPE_COMPLEX, "sfi_context_info", "sfi_context_info" }, + { 0, NHTYPE_COMPLEX, "sfi_d_flags", "sfi_d_flags" }, + { 0, NHTYPE_COMPLEX, "sfi_d_level", "sfi_d_level" }, + { 0, NHTYPE_COMPLEX, "sfi_damage", "sfi_damage" }, + { 0, NHTYPE_COMPLEX, "sfi_dest_area", "sfi_dest_area" }, + { 0, NHTYPE_COMPLEX, "sfi_dgn_topology", "sfi_dgn_topology" }, + { 0, NHTYPE_COMPLEX, "sfi_dig_info", "sfi_dig_info" }, + { 0, NHTYPE_COMPLEX, "sfi_dungeon", "sfi_dungeon" }, + { 0, NHTYPE_COMPLEX, "sfi_ebones", "sfi_ebones" }, + { 0, NHTYPE_COMPLEX, "sfi_edog", "sfi_edog" }, + { 0, NHTYPE_COMPLEX, "sfi_egd", "sfi_egd" }, + { 0, NHTYPE_COMPLEX, "sfi_emin", "sfi_emin" }, + { 0, NHTYPE_COMPLEX, "sfi_engr", "sfi_engr" }, + { 0, NHTYPE_COMPLEX, "sfi_engrave_info", "sfi_engrave_info" }, + { 0, NHTYPE_COMPLEX, "sfi_epri", "sfi_epri" }, + { 0, NHTYPE_COMPLEX, "sfi_eshk", "sfi_eshk" }, + { 0, NHTYPE_COMPLEX, "sfi_fakecorridor", "sfi_fakecorridor" }, + { 0, NHTYPE_COMPLEX, "sfi_fe", "sfi_fe" }, + { 0, NHTYPE_COMPLEX, "sfi_flag", "sfi_flag" }, + { 0, NHTYPE_COMPLEX, "sfi_fruit", "sfi_fruit" }, + { 0, NHTYPE_COMPLEX, "sfi_kinfo", "sfi_kinfo" }, + { 0, NHTYPE_COMPLEX, "sfi_levelflags", "sfi_levelflags" }, + { 0, NHTYPE_COMPLEX, "sfi_linfo", "sfi_linfo" }, + { 0, NHTYPE_COMPLEX, "sfi_ls_t", "sfi_ls_t" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen", "sfi_mapseen" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_feat", "sfi_mapseen_feat" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_flags", "sfi_mapseen_flags" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_rooms", "sfi_mapseen_rooms" }, + { 0, NHTYPE_COMPLEX, "sfi_mextra", "sfi_mextra" }, + { 0, NHTYPE_COMPLEX, "sfi_mkroom", "sfi_mkroom" }, + { 0, NHTYPE_COMPLEX, "sfi_monst", "sfi_monst" }, + { 0, NHTYPE_COMPLEX, "sfi_mvitals", "sfi_mvitals" }, + { 0, NHTYPE_COMPLEX, "sfi_nhcoord", "sfi_nhcoord" }, + { 0, NHTYPE_COMPLEX, "sfi_nhrect", "sfi_nhrect" }, + { 0, NHTYPE_COMPLEX, "sfi_novel_tracking", "sfi_novel_tracking" }, + { 0, NHTYPE_COMPLEX, "sfi_obj", "sfi_obj" }, + { 0, NHTYPE_COMPLEX, "sfi_obj_split", "sfi_obj_split" }, + { 0, NHTYPE_COMPLEX, "sfi_objclass", "sfi_objclass" }, + { 0, NHTYPE_COMPLEX, "sfi_oextra", "sfi_oextra" }, + { 0, NHTYPE_COMPLEX, "sfi_polearm_info", "sfi_polearm_info" }, + { 0, NHTYPE_COMPLEX, "sfi_prop", "sfi_prop" }, + { 0, NHTYPE_COMPLEX, "sfi_q_score", "sfi_q_score" }, + { 0, NHTYPE_COMPLEX, "sfi_rm", "sfi_rm" }, + { 0, NHTYPE_COMPLEX, "sfi_s_level", "sfi_s_level" }, + { 0, NHTYPE_COMPLEX, "sfi_skills", "sfi_skills" }, + { 0, NHTYPE_COMPLEX, "sfi_spell", "sfi_spell" }, + { 0, NHTYPE_COMPLEX, "sfi_stairway", "sfi_stairway" }, + { 0, NHTYPE_COMPLEX, "sfi_takeoff_info", "sfi_takeoff_info" }, + { 0, NHTYPE_COMPLEX, "sfi_tin_info", "sfi_tin_info" }, + { 0, NHTYPE_COMPLEX, "sfi_trap", "sfi_trap" }, + { 0, NHTYPE_COMPLEX, "sfi_tribute_info", "sfi_tribute_info" }, + { 0, NHTYPE_COMPLEX, "sfi_u_conduct", "sfi_u_conduct" }, + { 0, NHTYPE_COMPLEX, "sfi_u_event", "sfi_u_event" }, + { 0, NHTYPE_COMPLEX, "sfi_u_have", "sfi_u_have" }, + { 0, NHTYPE_COMPLEX, "sfi_u_realtime", "sfi_u_realtime" }, + { 0, NHTYPE_COMPLEX, "sfi_u_roleplay", "sfi_u_roleplay" }, + { 0, NHTYPE_COMPLEX, "sfi_version_info", "sfi_version_info" }, + { 0, NHTYPE_COMPLEX, "sfi_victual_info", "sfi_victual_info" }, + { 0, NHTYPE_COMPLEX, "sfi_vlaunchinfo", "sfi_vlaunchinfo" }, + { 0, NHTYPE_COMPLEX, "sfi_vptrs", "sfi_vptrs" }, + { 0, NHTYPE_COMPLEX, "sfi_warntype_info", "sfi_warntype_info" }, + { 0, NHTYPE_COMPLEX, "sfi_you", "sfi_you" }, + { 0, NHTYPE_COMPLEX, "sfo_achievement_tracking", + "sfo_achievement_tracking" }, + { 0, NHTYPE_COMPLEX, "sfo_align", "sfo_align" }, + { 0, NHTYPE_COMPLEX, "sfo_attribs", "sfo_attribs" }, + { 0, NHTYPE_COMPLEX, "sfo_bill_x", "sfo_bill_x" }, + { 0, NHTYPE_COMPLEX, "sfo_book_info", "sfo_book_info" }, + { 0, NHTYPE_COMPLEX, "sfo_branch", "sfo_branch" }, + { 0, NHTYPE_COMPLEX, "sfo_bubble", "sfo_bubble" }, + { 0, NHTYPE_COMPLEX, "sfo_cemetery", "sfo_cemetery" }, + { 0, NHTYPE_COMPLEX, "sfo_context_info", "sfo_context_info" }, + { 0, NHTYPE_COMPLEX, "sfo_d_flags", "sfo_d_flags" }, + { 0, NHTYPE_COMPLEX, "sfo_d_level", "sfo_d_level" }, + { 0, NHTYPE_COMPLEX, "sfo_damage", "sfo_damage" }, + { 0, NHTYPE_COMPLEX, "sfo_dest_area", "sfo_dest_area" }, + { 0, NHTYPE_COMPLEX, "sfo_dgn_topology", "sfo_dgn_topology" }, + { 0, NHTYPE_COMPLEX, "sfo_dig_info", "sfo_dig_info" }, + { 0, NHTYPE_COMPLEX, "sfo_dungeon", "sfo_dungeon" }, + { 0, NHTYPE_COMPLEX, "sfo_ebones", "sfo_ebones" }, + { 0, NHTYPE_COMPLEX, "sfo_edog", "sfo_edog" }, + { 0, NHTYPE_COMPLEX, "sfo_egd", "sfo_egd" }, + { 0, NHTYPE_COMPLEX, "sfo_emin", "sfo_emin" }, + { 0, NHTYPE_COMPLEX, "sfo_engr", "sfo_engr" }, + { 0, NHTYPE_COMPLEX, "sfo_engrave_info", "sfo_engrave_info" }, + { 0, NHTYPE_COMPLEX, "sfo_epri", "sfo_epri" }, + { 0, NHTYPE_COMPLEX, "sfo_eshk", "sfo_eshk" }, + { 0, NHTYPE_COMPLEX, "sfo_fakecorridor", "sfo_fakecorridor" }, + { 0, NHTYPE_COMPLEX, "sfo_fe", "sfo_fe" }, + { 0, NHTYPE_COMPLEX, "sfo_flag", "sfo_flag" }, + { 0, NHTYPE_COMPLEX, "sfo_fruit", "sfo_fruit" }, + { 0, NHTYPE_COMPLEX, "sfo_kinfo", "sfo_kinfo" }, + { 0, NHTYPE_COMPLEX, "sfo_levelflags", "sfo_levelflags" }, + { 0, NHTYPE_COMPLEX, "sfo_linfo", "sfo_linfo" }, + { 0, NHTYPE_COMPLEX, "sfo_ls_t", "sfo_ls_t" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen", "sfo_mapseen" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_feat", "sfo_mapseen_feat" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_flags", "sfo_mapseen_flags" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_rooms", "sfo_mapseen_rooms" }, + { 0, NHTYPE_COMPLEX, "sfo_mextra", "sfo_mextra" }, + { 0, NHTYPE_COMPLEX, "sfo_mkroom", "sfo_mkroom" }, + { 0, NHTYPE_COMPLEX, "sfo_monst", "sfo_monst" }, + { 0, NHTYPE_COMPLEX, "sfo_mvitals", "sfo_mvitals" }, + { 0, NHTYPE_COMPLEX, "sfo_nhcoord", "sfo_nhcoord" }, + { 0, NHTYPE_COMPLEX, "sfo_nhrect", "sfo_nhrect" }, + { 0, NHTYPE_COMPLEX, "sfo_novel_tracking", "sfo_novel_tracking" }, + { 0, NHTYPE_COMPLEX, "sfo_obj", "sfo_obj" }, + { 0, NHTYPE_COMPLEX, "sfo_obj_split", "sfo_obj_split" }, + { 0, NHTYPE_COMPLEX, "sfo_objclass", "sfo_objclass" }, + { 0, NHTYPE_COMPLEX, "sfo_oextra", "sfo_oextra" }, + { 0, NHTYPE_COMPLEX, "sfo_polearm_info", "sfo_polearm_info" }, + { 0, NHTYPE_COMPLEX, "sfo_prop", "sfo_prop" }, + { 0, NHTYPE_COMPLEX, "sfo_q_score", "sfo_q_score" }, + { 0, NHTYPE_COMPLEX, "sfo_rm", "sfo_rm" }, + { 0, NHTYPE_COMPLEX, "sfo_s_level", "sfo_s_level" }, + { 0, NHTYPE_COMPLEX, "sfo_skills", "sfo_skills" }, + { 0, NHTYPE_COMPLEX, "sfo_spell", "sfo_spell" }, + { 0, NHTYPE_COMPLEX, "sfo_stairway", "sfo_stairway" }, + { 0, NHTYPE_COMPLEX, "sfo_takeoff_info", "sfo_takeoff_info" }, + { 0, NHTYPE_COMPLEX, "sfo_tin_info", "sfo_tin_info" }, + { 0, NHTYPE_COMPLEX, "sfo_trap", "sfo_trap" }, + { 0, NHTYPE_COMPLEX, "sfo_tribute_info", "sfo_tribute_info" }, + { 0, NHTYPE_COMPLEX, "sfo_u_conduct", "sfo_u_conduct" }, + { 0, NHTYPE_COMPLEX, "sfo_u_event", "sfo_u_event" }, + { 0, NHTYPE_COMPLEX, "sfo_u_have", "sfo_u_have" }, + { 0, NHTYPE_COMPLEX, "sfo_u_realtime", "sfo_u_realtime" }, + { 0, NHTYPE_COMPLEX, "sfo_u_roleplay", "sfo_u_roleplay" }, + { 0, NHTYPE_COMPLEX, "sfo_version_info", "sfo_version_info" }, + { 0, NHTYPE_COMPLEX, "sfo_victual_info", "sfo_victual_info" }, + { 0, NHTYPE_COMPLEX, "sfo_vlaunchinfo", "sfo_vlaunchinfo" }, + { 0, NHTYPE_COMPLEX, "sfo_vptrs", "sfo_vptrs" }, + { 0, NHTYPE_COMPLEX, "sfo_warntype_info", "sfo_warntype_info" }, + { 0, NHTYPE_COMPLEX, "sfo_you", "sfo_you" }, + { 0, NHTYPE_SIMPLE, "sfi_any", "sfi_any" }, + { 0, NHTYPE_SIMPLE, "sfi_aligntyp", "Sfi_aligntyp" }, + { 0, NHTYPE_SIMPLE, "sfi_Bitfield", "Sfi_Bitfield" }, + { 0, NHTYPE_SIMPLE, "sfi_boolean", "Sfi_boolean" }, + { 0, NHTYPE_SIMPLE, "sfi_char", "Sfi_char" }, + { 0, NHTYPE_SIMPLE, "sfi_coordxy", "Sfi_Coordxy" }, + { 0, NHTYPE_SIMPLE, "sfi_int", "Sfi_int32" }, + { 0, NHTYPE_SIMPLE, "sfi_long", "Sfi_long" }, + { 0, NHTYPE_SIMPLE, "sfi_schar", "Sfi_schar" }, + { 0, NHTYPE_SIMPLE, "sfi_short", "Sfi_int16" }, + { 0, NHTYPE_SIMPLE, "sfi_size_t", "Sfi_size_t" }, + { 0, NHTYPE_SIMPLE, "sfi_string", "Sfi_string" }, + { 0, NHTYPE_SIMPLE, "sfi_time_t", "Sfi_time_t" }, + { 0, NHTYPE_SIMPLE, "sfi_uchar", "Sfi_uchar" }, + { 0, NHTYPE_SIMPLE, "sfi_unsigned", "Sfi_uint32" }, + { 0, NHTYPE_SIMPLE, "sfi_xint16", "Sfi_int16" }, + { 0, NHTYPE_SIMPLE, "sfi_xint8", "Sfi_xint8" }, + { 0, NHTYPE_SIMPLE, "sfo_aligntyp", "Sfo_aligntyp" }, + { 0, NHTYPE_SIMPLE, "sfo_any", "Sfo_any" }, + { 0, NHTYPE_SIMPLE, "sfo_Bitfield", "Sfo_Bitfield" }, + { 0, NHTYPE_SIMPLE, "sfo_boolean", "Sfo_boolean" }, + { 0, NHTYPE_SIMPLE, "sfo_char", "Sfo_char" }, + { 0, NHTYPE_SIMPLE, "sfo_coordxy", "Sfo_coordxy" }, + { 0, NHTYPE_SIMPLE, "sfo_int", "Sfo_int32" }, + { 0, NHTYPE_SIMPLE, "sfo_long", "sfo_long" }, + { 0, NHTYPE_SIMPLE, "sfo_schar", "Sfo_schar" }, + { 0, NHTYPE_SIMPLE, "sfo_short", "Sfo_short" }, + { 0, NHTYPE_SIMPLE, "sfo_size_t", "Sfo_size_t" }, + { 0, NHTYPE_SIMPLE, "sfo_string", "Sfo_string" }, + { 0, NHTYPE_SIMPLE, "sfo_time_t", "Sfo_time_t" }, + { 0, NHTYPE_SIMPLE, "sfo_uchar", "Sfo_uchar" }, + { 0, NHTYPE_SIMPLE, "sfo_unsigned", "Sfo_uint32" }, + { 0, NHTYPE_SIMPLE, "sfo_xint16", "Sfo_int16" }, + { 0, NHTYPE_SIMPLE, "sfo_xint8", "Sfo_xint8" } +}; + + /*sftags.c*/ + + diff --git a/util/stripbs.c b/util/stripbs.c new file mode 100644 index 000000000..dd1452027 --- /dev/null +++ b/util/stripbs.c @@ -0,0 +1,48 @@ +/* NetHack 5.0 stripbs.c */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * a simple filter to strip character-backspace-character + * from stdin and write the final character to stdout. + */ + +#include +#include +#include +#include + +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +int main(int argc UNUSED, char *argv[] UNUSED) +{ + int stop = 0, trouble = 0; + char buf[2]; + char *cp = &buf[0], *prev = &buf[1]; + + *prev = 0; + while (!stop) { + if ((fread(buf, 1, 1, stdin)) > 0) { + if (*cp == 8) { + *prev = 0; + } else { + if (*prev) + fputc(*prev, stdout); + *prev = *cp; + } + } else { + if (errno != EOF) + trouble = 1; + if (*prev) + fputc(*prev, stdout); + stop = 1; + } + } + fflush(stdout); + fclose(stdout); + return trouble ? EXIT_FAILURE : EXIT_SUCCESS; +} From dc95ddeb3c6388e139ad6808d1388885f44fa5d0 Mon Sep 17 00:00:00 2001 From: Stephen Oman Date: Fri, 12 Jun 2026 15:16:04 +0100 Subject: [PATCH 3/3] Add nh5 makedefs.c and update mdlib.c with NLE mod as it was relocated by NetHack5 --- src/mdlib.c | 4 + util/makedefs.c | 3252 +++++++++++++++++------------------------------ 2 files changed, 1144 insertions(+), 2112 deletions(-) diff --git a/src/mdlib.c b/src/mdlib.c index b7e0810c6..967386843 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -146,6 +146,10 @@ static struct win_information window_opts[] = { { "amii", "Amiga Intuition (text)", TRUE }, { "amiv", "Amiga Intuition (tiles)", TRUE }, #endif +/* NLE: add definition for reinforcement learning graphics */ +#ifdef RL_GRAPHICS + { "rl", "Reinforcement learning 'graphics'", TRUE }, +#endif #if 0 /* remainder have been retired */ #ifdef GNOME_GRAPHICS /* unmaintained/defunct */ diff --git a/util/makedefs.c b/util/makedefs.c index fb5052a68..177fc53df 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1,20 +1,18 @@ -/* NetHack 3.6 makedefs.c $NHDT-Date: 1582403492 2020/02/22 20:31:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.177 $ */ +/* NetHack 5.0 makedefs.c $NHDT-Date: 1702948590 2023/12/19 01:16:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.233 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ -/* Copyright (c) Facebook, Inc. and its affiliates. */ /* NetHack may be freely redistributed. See license for details. */ #define MAKEDEFS_C /* use to conditionally include file sections */ +#define OLD_MAKEDEFS_OPTIONS + #include "config.h" -#ifdef MONITOR_HEAP -#undef free /* makedefs doesn't use the alloc and free in src/alloc.c */ -#endif #include "permonst.h" #include "objclass.h" -#include "monsym.h" +#include "sym.h" #include "artilist.h" #include "dungeon.h" #include "obj.h" @@ -23,29 +21,26 @@ #include "context.h" #include "flag.h" #include "dlb.h" +#include "hacklib.h" -/* version information */ -#ifdef SHORT_FILENAMES -#include "patchlev.h" -#else -#include "patchlevel.h" -#endif - -#include -#ifdef MAC +#ifdef MACOS9 #if defined(__SC__) || defined(__MRC__) /* MPW compilers */ #define MPWTOOL #include #include -#else /* MAC without MPWTOOL */ +#else /* MACOS9 without MPWTOOL */ #define MACsansMPWTOOL #endif -#endif /* MAC */ +#endif /* MACOS9 */ #ifndef MPWTOOL #define SpinCursor(x) #endif +#ifdef MD_USE_TMPFILE_S +#include +#endif + #define Fprintf (void) fprintf #define Fclose (void) fclose #define Unlink (void) unlink @@ -53,90 +48,84 @@ #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */ #endif -#if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN) -static const char SCCS_Id[] UNUSED = "@(#)makedefs.c\t3.6\t2020/03/04"; -#endif - /* names of files to be generated */ +#define ORACLE_FILE "oracles" +#define DATA_FILE "data" +#define RUMOR_FILE "rumors" + +/* These are affiliated with outdated options + but we define them for us in messages */ #define DATE_FILE "date.h" #define MONST_FILE "pm.h" #define ONAME_FILE "onames.h" #ifndef OPTIONS_FILE #define OPTIONS_FILE "options" #endif -#define ORACLE_FILE "oracles" -#define DATA_FILE "data" -#define RUMOR_FILE "rumors" #define DGN_I_FILE "dungeon.def" #define DGN_O_FILE "dungeon.pdf" -#define MON_STR_C "monstr.c" #define QTXT_I_FILE "quest.txt" #define QTXT_O_FILE "quest.dat" -#define VIS_TAB_H "vis_tab.h" -#define VIS_TAB_C "vis_tab.c" #define GITINFO_FILE "gitinfo.txt" + /* locations for those files */ #ifdef AMIGA #define FILE_PREFIX -#define INCLUDE_TEMPLATE "NH:include/t.%s" #define SOURCE_TEMPLATE "NH:src/%s" -#define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "NH:slib/%s" #define DATA_IN_TEMPLATE "NH:dat/%s" +#if defined(OLD_MAKEDEFS_OPTIONS) +#define INCLUDE_TEMPLATE "NH:include/t.%s" +#define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */ +#endif /* OLD_MAKEDEFS_OPTIONS */ #else /* not AMIGA */ -#if defined(MAC) && !defined(__MACH__) +#if defined(MACOS9) && !defined(__MACH__) /* MacOS 9 or earlier */ -#define INCLUDE_TEMPLATE ":include:%s" #define SOURCE_TEMPLATE ":src:%s" -#define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ #if __SC__ || __MRC__ #define DATA_TEMPLATE ":Dungeon:%s" #else #define DATA_TEMPLATE ":lib:%s" #endif /* __SC__ || __MRC__ */ #define DATA_IN_TEMPLATE ":dat:%s" -#else /* neither AMIGA nor MAC */ +#if defined(OLD_MAKEDEFS_OPTIONS) +#define INCLUDE_TEMPLATE ":include:%s" +#define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ +#endif /* OLD_MAKEDEFS_OPTIONS */ +#else /* neither AMIGA nor MACOS9 */ #ifdef OS2 -#define INCLUDE_TEMPLATE "..\\include\\%s" #define SOURCE_TEMPLATE "..\\src\\%s" -#define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "..\\dat\\%s" #define DATA_IN_TEMPLATE "..\\dat\\%s" -#else /* not AMIGA, MAC, or OS2 */ -#define INCLUDE_TEMPLATE "../include/%s" +#if defined(OLD_MAKEDEFS_OPTIONS) +#define INCLUDE_TEMPLATE "..\\include\\%s" +#define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */ +#endif /* OLD_MAKEDEFS_OPTIONS */ +#else /* not AMIGA, MACOS9, or OS2 */ #define SOURCE_TEMPLATE "../src/%s" -#define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */ #define DATA_TEMPLATE "../dat/%s" #define DATA_IN_TEMPLATE "../dat/%s" +#if defined(OLD_MAKEDEFS_OPTIONS) +#define INCLUDE_TEMPLATE "../include/%s" +#define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */ +#endif /* OLD_MAKEDEFS_OPTIONS */ #endif /* else !OS2 */ -#endif /* else !MAC */ +#endif /* else !MACOS9 */ #endif /* else !AMIGA */ static const char - *Dont_Edit_Code = - "/* This source file is generated by 'makedefs'. Do not edit. */\n", *Dont_Edit_Data = "#\tThis data file is generated by 'makedefs'. Do not edit. \n"; -static struct version_info version; +#if defined(OLD_MAKEDEFS_OPTIONS) +static const char + *Reference_file = + "/* This file is generated by 'makedefs' for reference purposes only. */\n" + "/* It is no longer used in the NetHack build. */\n"; +#endif /* OLD_MAKEDEFS_OPTIONS */ -/* definitions used for vision tables */ -#define TEST_WIDTH COLNO -#define TEST_HEIGHT ROWNO -#define BLOCK_WIDTH (TEST_WIDTH + 10) -#define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */ -#define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT) -#define MAX_COL (BLOCK_WIDTH + TEST_WIDTH) -/* Use this as an out-of-bound value in the close table. */ -#define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ -#define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ - -#define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) -#ifdef VISION_TABLES -static char xclear[MAX_ROW][MAX_COL]; -#endif -/*-end of vision defs-*/ +static struct version_info version; +#define FLG_TEMPFILE 0x01 /* flag for temp file */ #define MAXFNAMELEN 600 static char filename[MAXFNAMELEN]; @@ -149,87 +138,91 @@ char *file_prefix = ""; #endif #ifdef MACsansMPWTOOL -int FDECL(main, (void)); +int main(void); #else -int FDECL(main, (int, char **)); -#endif -void FDECL(do_makedefs, (char *)); -void NDECL(do_objs); -void NDECL(do_data); -void NDECL(do_dungeon); -void NDECL(do_date); -void NDECL(do_options); -void NDECL(do_monstr); -void NDECL(do_permonst); -void NDECL(do_questtxt); -void NDECL(do_rumors); -void NDECL(do_oracles); -void NDECL(do_vision); - -extern void NDECL(monst_init); /* monst.c */ -extern void NDECL(objects_init); /* objects.c */ - -static void NDECL(link_sanity_check); -static char *FDECL(name_file, (const char *, const char *)); -static void FDECL(delete_file, (const char *template, const char *)); -static FILE *FDECL(getfp, (const char *, const char *, const char *)); -static void FDECL(do_ext_makedefs, (int, char **)); - -static void NDECL(make_version); -static char *FDECL(version_string, (char *, const char *)); -static char *FDECL(version_id_string, (char *, const char *)); -static char *FDECL(bannerc_string, (char *, const char *)); -static char *FDECL(xcrypt, (const char *)); -static unsigned long FDECL(read_rumors_file, - (const char *, int *, long *, unsigned long)); -static boolean FDECL(get_gitinfo, (char *, char *)); -static void FDECL(do_rnd_access_file, (const char *, const char *)); -static boolean FDECL(d_filter, (char *)); -static boolean FDECL(h_filter, (char *)); -static void NDECL(build_savebones_compat_string); -static void NDECL(windowing_sanity); -static void FDECL(opt_out_words, (char *, int *)); - -static boolean FDECL(qt_comment, (char *)); -static boolean FDECL(qt_control, (char *)); -static int FDECL(get_hdr, (char *)); -static boolean FDECL(new_id, (char *)); -static boolean FDECL(known_msg, (int, int)); -static void FDECL(new_msg, (char *, int, int)); -static char *FDECL(valid_qt_summary, (char *, BOOLEAN_P)); -static void FDECL(do_qt_control, (char *)); -static void FDECL(do_qt_text, (char *)); -static void NDECL(adjust_qt_hdrs); -static void NDECL(put_qt_hdrs); - -#ifdef VISION_TABLES -static void NDECL(H_close_gen); -static void NDECL(H_far_gen); -static void NDECL(C_close_gen); -static void NDECL(C_far_gen); -static int FDECL(clear_path, (int, int, int, int)); +int main(int, char **); #endif -static char *FDECL(fgetline, (FILE*)); -static char *FDECL(tmpdup, (const char *)); -static char *FDECL(limit, (char *, int)); -static char *FDECL(eos, (char *)); -static int FDECL(case_insensitive_comp, (const char *, const char *)); +void do_makedefs(char *); +void do_data(void); +void do_rumors(void); +void do_oracles(void); + +#if defined(OLD_MAKEDEFS_OPTIONS) +void do_date(void); +void do_dungeon(void); +void do_options(void); +void do_objs(void); +void do_permonst(void); +void do_questtxt(void); +#else +static const char *oldfunctionality(char); +#endif /* OLD_MAKEDEFS_OPTIONS */ + +extern void monst_globals_init(void); /* monst.c */ +extern void objects_globals_init(void); /* objects.c */ + +static char *name_file(const char *, const char *); +static FILE *getfp(const char *, const char *, const char *, int); +static void do_ext_makedefs(int, char **); +static char *padline(char *, unsigned); +static unsigned long read_rumors_file(const char *, int *, + long *, unsigned long, unsigned); +static void rafile(int); +static void do_rnd_access_file(const char *, const char *, + const char *, unsigned); +static boolean d_filter(char *); +static boolean h_filter(char *); +static void opt_out_words(char *, int *); +static char *fgetline(FILE *); +/* doesn't do much (counts lines) if MAKEDEFS_FILTER_NONASCII isn't enabled */ +static void filter_nonascii(char *); +static void set_fgetline_context(const char *, boolean, boolean); + +#if defined(OLD_MAKEDEFS_OPTIONS) +static char *tmpdup(const char *); +static char *macronamelimit(char *, int); +static void windowing_sanity(void); +static boolean get_gitinfo(char *, char *); +static boolean use_enum = TRUE; +#endif + +/* for MAKEDEFS_FILTER_NONASCII, but not conditionalized; + extra input for fgetline(); not-needed for files that don't use that */ +struct ascii_filter { + const char *filename; + int linenum, warncnt; + boolean dofilter, tabok; +}; +static struct ascii_filter ascii_ctx; /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; -static boolean use_enum = -#ifdef ENUM_PM - TRUE; -#else - FALSE; -#endif - #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif +unsigned FITSuint_(unsigned long long, const char *, int); + +/* + * Some of the routines in this source file were moved into .../src/mdlib + * to facilitate the use of a cross-compiler generation of some of the + * information for the target environment during the game compile portion + * under the cross-compiler and/or at runtime in some cases. + */ + +#include "../src/mdlib.c" + +ATTRNORETURN static void makedefs_exit(int) NORETURN; + +ATTRNORETURN static void +makedefs_exit(int how) +{ + exit(how); + /*NOTREACHED*/ +} + #ifdef MACsansMPWTOOL int main(void) @@ -253,21 +246,23 @@ main(void) do_ext_makedefs(fakeargc, fakeargv); #else printf("extended makedefs not implemented for Mac OS9\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ #endif } do_makedefs(buf); - exit(EXIT_SUCCESS); + makedefs_exit(EXIT_SUCCESS); + /*NOTREACHED*/ return 0; } -#else /* ! MAC */ +#else /* ! MACOS9 */ + +DISABLE_WARNING_UNREACHABLE_CODE int -main(argc, argv) -int argc; -char *argv[]; +main(int argc, char *argv[]) { if ((argc == 1) || ((argc != 2) @@ -277,7 +272,8 @@ char *argv[]; && !(argv[1][0] == '-' && argv[1][1] == '-'))) { Fprintf(stderr, "Bad arg count (%d).\n", argc - 1); (void) fflush(stderr); - return 1; + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } #ifdef FILE_PREFIX @@ -293,31 +289,21 @@ char *argv[]; } else { do_makedefs(&argv[1][1]); } - exit(EXIT_SUCCESS); + makedefs_exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } - #endif -static void -link_sanity_check() -{ - /* Note: these initializers don't do anything except guarantee that - we're linked properly. - */ - monst_init(); - objects_init(); - -} +RESTORE_WARNINGS void -do_makedefs(options) -char *options; +do_makedefs(char *options) { boolean more_than_one; - link_sanity_check(); + objects_globals_init(); + monst_globals_init(); /* construct the current version number */ make_version(); @@ -328,22 +314,38 @@ char *options; Fprintf(stderr, "makedefs -%c\n", *options); switch (*options) { - case 'o': - case 'O': - do_objs(); - break; case 'd': case 'D': do_data(); break; + case 'h': + case 'H': + do_oracles(); + break; + case 'r': + case 'R': + do_rumors(); + break; + case 's': + case 'S': + rafile('1'); + rafile('2'); + rafile('3'); + break; + case '1': + case '2': + case '3': + rafile(*options); + break; +#if defined(OLD_MAKEDEFS_OPTIONS) + case 'o': + case 'O': + do_objs(); + break; case 'e': case 'E': do_dungeon(); break; - case 'm': - case 'M': - do_monstr(); - break; case 'v': case 'V': do_date(); @@ -357,86 +359,160 @@ char *options; case 'Q': do_questtxt(); break; - case 'r': - case 'R': - do_rumors(); +#else + case 'o': case 'O': case 'e': case 'E': case 'v': case 'V': + case 'p': case 'P': case 'q': case 'Q': + Fprintf(stderr, "Old makedefs option.\n" + "Rebuild makedefs with '-DOLD_MAKEDEFS_OPTIONS'" + " for '%c' (%s) support.\n", + *options, oldfunctionality(*options)); + (void) fflush(stderr); + /*NOTREACHED*/ break; - case 's': - case 'S': +#endif /* OLD_MAKEDEFS_OPTIONS */ + default: + Fprintf(stderr, "Unknown option '%c'.\n", *options); + (void) fflush(stderr); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + options++; + } + if (more_than_one) + Fprintf(stderr, "Completed.\n"); /* feedback */ + return; +} + +#if !defined(OLD_MAKEDEFS_OPTIONS) +static const char * +oldfunctionality(char sought) +{ + static struct ofn_s { + char lcoflet; + char ucoflet; + const char *ofnam; + } ofn[] = { + { 'e', 'E', DGN_O_FILE }, + { 'o', 'O', ONAME_FILE }, + { 'p', 'P', MONST_FILE }, + { 'q', 'Q', QTXT_O_FILE }, + { 'v', 'V', DATE_FILE " & " OPTIONS_FILE }, + }; + int i; + + for (i = 0; i < SIZE(ofn); ++i) { + if (sought == ofn[i].lcoflet || sought == ofn[i].ucoflet) + return ofn[i].ofnam; + } + return "unknown"; +} +#endif /* !OLD_MAKEDEFS_OPTIONS */ + +static void +rafile(int whichone) +{ + switch(whichone) { /* * post-3.6.5: * File must not be empty to avoid divide by 0 * in core's rn2(), so provide a default entry. */ - do_rnd_access_file(EPITAPHFILE, + case '1': + do_rnd_access_file(EPITAPHFILE, "epitaph", /* default epitaph: parody of the default engraving */ - "No matter where I went, here I am."); - do_rnd_access_file(ENGRAVEFILE, + "No matter where I went, here I am.", + MD_PAD_RUMORS); /* '_RUMORS' is correct here */ + break; + case '2': + do_rnd_access_file(ENGRAVEFILE, "engrave", /* default engraving: popularized by "The Adventures of - Buckaroo Bonzai Across the 8th Dimenstion" but predates + Buckaroo Bonzai Across the 8th Dimension" but predates that 1984 movie; some attribute it to Confucius */ - "No matter where you go, there you are."); - do_rnd_access_file(BOGUSMONFILE, - /* default bogusmon: iconic monster that isn't in nethack */ - "grue"); + "No matter where you go, there you are.", + MD_PAD_RUMORS); /* '_RUMORS' used here too */ break; - case 'h': - case 'H': - do_oracles(); - break; - case 'z': - case 'Z': - do_vision(); + case '3': + do_rnd_access_file(BOGUSMONFILE, "bogusmon", + /* default bogusmon: iconic monster that isn't in nethack */ + "grue", MD_PAD_BOGONS); break; - - default: - Fprintf(stderr, "Unknown option '%c'.\n", *options); - (void) fflush(stderr); - exit(EXIT_FAILURE); - } - options++; } - if (more_than_one) - Fprintf(stderr, "Completed.\n"); /* feedback */ } static char namebuf[1000]; +DISABLE_WARNING_FORMAT_NONLITERAL + static char * -name_file(template, tag) -const char *template; -const char *tag; +name_file(const char *template, const char *tag) { Sprintf(namebuf, template, tag); return namebuf; } +#ifdef HAS_NO_MKSTEMP +static void delete_file(const char *template, const char *); + static void -delete_file(template, tag) -const char *template; -const char *tag; +delete_file(const char *template, const char *tag) { char *name = name_file(template, tag); Unlink(name); } +#endif static FILE * -getfp(template, tag, mode) -const char *template; -const char *tag; -const char *mode; +getfp(const char *template, const char *tag, const char *mode, int flg) { char *name = name_file(template, tag); - FILE *rv = fopen(name, mode); + FILE *rv = (FILE *) 0; + boolean istemp = (flg & FLG_TEMPFILE) != 0; +#if !defined(HAS_NO_MKSTEMP) && !defined(MD_USE_TMPFILE_S) + char tmpfbuf[MAXFNAMELEN]; + int tmpfd; +#endif +#ifdef MD_USE_TMPFILE_S + errno_t err; +#endif + +#if defined(MD_USE_TMPFILE_S) + if (istemp) { + err = tmpfile_s(&rv); +#if defined(MSDOS) || defined(WIN32) + if (!err && (!strcmp(mode, WRTMODE) || !strcmp(mode, RDTMODE))) { + (void) _setmode(fileno(rv), O_TEXT); + } +#endif + } else +#else /* MD_USE_TMPFILE_S */ +#ifndef HAS_NO_MKSTEMP + if (istemp) { + (void) snprintf(tmpfbuf, sizeof tmpfbuf, DATA_TEMPLATE, "mdXXXXXX"); + tmpfd = mkstemp(tmpfbuf); + if (tmpfd >= 0) { + rv = fdopen(tmpfd, WRTMODE); /* temp file is always read+write */ + Unlink(tmpfbuf); + } + } else +#endif +#endif /* MD_USE_TMPFILE_S */ + rv = fopen(name, mode); if (!rv) { - Fprintf(stderr, "Can't open '%s'.\n", name); - exit(EXIT_FAILURE); + Fprintf(stderr, "Can't open '%s' (mode=%s).\n", +#if !defined(HAS_NO_MKSTEMP) && !defined(MD_USE_TMPFILE_S) + istemp ? tmpfbuf : +#endif + name, mode); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } return rv; } +RESTORE_WARNING_FORMAT_NONLITERAL + static boolean debug = FALSE; static FILE *inputfp; @@ -449,13 +525,13 @@ struct grep_var { /* struct grep_var grep_vars[] and TODO_* constants in include file: */ #include "mdgrep.h" -static void NDECL(do_grep_showvars); -static struct grep_var *FDECL(grepsearch, (const char *)); -static int FDECL(grep_check_id, (const char *)); -static void FDECL(grep_show_wstack, (const char *)); -static char *FDECL(do_grep_control, (char *)); -static void NDECL(do_grep); -static void FDECL(grep0, (FILE *, FILE *)); +static void do_grep_showvars(void); +static struct grep_var *grepsearch(const char *); +static int grep_check_id(const char *); +static void grep_show_wstack(const char *); +static char *do_grep_control(char *); +static void do_grep(void); +static void grep0(FILE *, FILE *, int); static int grep_trace = 0; @@ -467,7 +543,8 @@ static int grep_trace = 0; argv++, argc--; \ if (argc == 0) { \ Fprintf(stderr, "missing option\n"); \ - exit(EXIT_FAILURE); \ + makedefs_exit(EXIT_FAILURE); \ + /*NOTREACHED*/ \ } static void @@ -475,8 +552,6 @@ do_ext_makedefs(int argc, char **argv) { int todo = 0; - link_sanity_check(); - argc--; argv++; /* skip program name */ @@ -485,7 +560,8 @@ do_ext_makedefs(int argc, char **argv) break; if (argv[0][1] != '-') { Fprintf(stderr, "Can't mix - and -- options.\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } IS_OPTION("svs") { /* short version string for packaging - note no \n */ @@ -496,8 +572,9 @@ do_ext_makedefs(int argc, char **argv) delim[0] = '\0'; if (argv[0]) strcpy(delim, argv[0]); - Fprintf(stdout, "%s", version_string(buf, delim)); - exit(EXIT_SUCCESS); + Fprintf(stdout, "%s", mdlib_version_string(buf, delim)); + makedefs_exit(EXIT_SUCCESS); + /*NOTREACHED*/ } IS_OPTION("debug") { debug = TRUE; @@ -506,7 +583,8 @@ do_ext_makedefs(int argc, char **argv) IS_OPTION("make") { CONSUME; do_makedefs(argv[0]); - exit(EXIT_SUCCESS); + makedefs_exit(EXIT_SUCCESS); + /*NOTREACHED*/ } IS_OPTION("input") { CONSUME; @@ -516,7 +594,8 @@ do_ext_makedefs(int argc, char **argv) inputfp = fopen(argv[0], RDTMODE); if (!inputfp) { Fprintf(stderr, "Can't open '%s'.\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } } CONTINUE; @@ -529,7 +608,8 @@ do_ext_makedefs(int argc, char **argv) outputfp = fopen(argv[0], WRTMODE); if (!outputfp) { Fprintf(stderr, "Can't open '%s'.\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } } CONTINUE; @@ -537,14 +617,16 @@ do_ext_makedefs(int argc, char **argv) IS_OPTION("grep") { if (todo) { Fprintf(stderr, "Can't do grep and something else.\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } todo = TODO_GREP; CONTINUE; } IS_OPTION("grep-showvars") { do_grep_showvars(); - exit(EXIT_SUCCESS); + makedefs_exit(EXIT_SUCCESS); + /*NOTREACHED*/ } IS_OPTION("grep-trace") { grep_trace = 1; @@ -559,7 +641,8 @@ do_ext_makedefs(int argc, char **argv) p->is_defined = 1; } else { Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } CONTINUE; } @@ -572,33 +655,50 @@ do_ext_makedefs(int argc, char **argv) p->is_defined = 0; } else { Fprintf(stderr, "Unknown symbol '%s'\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } CONTINUE; } + IS_OPTION("grep-defined"){ + struct grep_var *p; + + CONSUME; + p = grepsearch(argv[0]); + // NB: Exit status is ready for the shell: + // 0=defined, 1=not defined + makedefs_exit(!(p && p->is_defined)); + } #ifdef notyet IS_OPTION("help") { } #endif Fprintf(stderr, "Unknown option '%s'.\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (argc) { Fprintf(stderr, "unexpected argument '%s'.\n", argv[0]); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } switch (todo) { default: Fprintf(stderr, "Confused about what to do?\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + break; case 0: Fprintf(stderr, "Nothing to do?\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + break; case TODO_GREP: do_grep(); break; } + return; } #undef IS_OPTION @@ -651,7 +751,7 @@ static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) }; static int grep_lineno = 0; static void -do_grep_showvars() +do_grep_showvars(void) { int x; @@ -661,8 +761,7 @@ do_grep_showvars() } static struct grep_var * -grepsearch(name) -const char *name; +grepsearch(const char *name) { /* XXX make into binary search */ int x = 0; @@ -676,8 +775,7 @@ const char *name; } static int -grep_check_id(id) -const char *id; +grep_check_id(const char *id) { struct grep_var *rv; @@ -706,8 +804,7 @@ const char *id; } static void -grep_show_wstack(tag) -const char *tag; +grep_show_wstack(const char *tag) { int x; @@ -722,8 +819,7 @@ const char *tag; } static char * -do_grep_control(buf) -char *buf; +do_grep_control(char *buf) { int isif = 1; char *buf0 = buf; @@ -749,11 +845,13 @@ char *buf; break; case '!': /* if not ID */ isif = 0; - /* FALLTHROUGH */ + FALLTHROUGH; + /* FALLTHRU */ case '?': /* if ID */ if (grep_sp == GREP_STACK_SIZE - 2) { Fprintf(stderr, "stack overflow at line %d.", grep_lineno); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (grep_writing) { isif = grep_check_id(&buf[1]) ? isif : !isif; @@ -806,10 +904,10 @@ char *buf; } #endif -static void grep0(FILE *, FILE *); +static void grep0(FILE *, FILE *, int); static void -do_grep() +do_grep(void) { if (!inputfp) { Fprintf(stderr, "--grep requires --input\n"); @@ -818,17 +916,25 @@ do_grep() Fprintf(stderr, "--grep requires --output\n"); } if (!inputfp || !outputfp) { - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - grep0(inputfp, outputfp); + grep0(inputfp, outputfp, 0); } static void -grep0(inputfp0, outputfp0) -FILE *inputfp0; -FILE *outputfp0; +grep0(FILE *inputfp0, FILE* outputfp0, int flg) { +#ifndef HAS_NO_MKSTEMP + /* if grep0 is passed FLG_TEMPFILE flag, it will + leave the output file open when it returns. + The caller will have to take care of calling + fclose() when it is done with the file */ + boolean istemp = (flg & FLG_TEMPFILE) != 0; +#else + flg; // unused +#endif char buf[16384]; /* looong, just in case */ while (!feof(inputfp0) && !ferror(inputfp0)) { @@ -861,14 +967,21 @@ FILE *outputfp0; } if (ferror(inputfp0)) { Fprintf(stderr, "read error!\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (ferror(outputfp0)) { Fprintf(stderr, "write error!\n"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } fclose(inputfp0); - fclose(outputfp0); +#ifndef HAS_NO_MKSTEMP + if (istemp) + rewind(outputfp0); + else +#endif + fclose(outputfp0); if (grep_sp) { Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp, grep_sp == 1 ? "" : "s"); @@ -877,41 +990,57 @@ FILE *outputfp0; if (grep_errors) { Fprintf(stderr, "%d error%s detected.\n", grep_errors, grep_errors == 1 ? "" : "s"); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } + return; } -/* trivial text encryption routine which can't be broken with `tr' */ static char * -xcrypt(str) -const char *str; -{ /* duplicated in src/hacklib.c */ - static char buf[BUFSZ]; - register const char *p; - register char *q; - register int bitmask; - - for (bitmask = 1, p = str, q = buf; *p; q++) { - *q = *p++; - if (*q & (32 | 64)) - *q ^= bitmask; - if ((bitmask <<= 1) >= 32) - bitmask = 1; - } - *q = '\0'; - return buf; +padline(char *line, unsigned padlength) +{ + /* + * Rumor selection is accomplished by seeking to a random + * position in the file, advancing to newline, and taking + * the next line. Therefore, rumors which follow long-line + * rumors are most likely to be chosen and rumors which + * follow short-line rumors are least likely to be chosen. + * We ameliorate the latter by padding the shortest lines, + * increasing the chance of the random seek landing in them. + * The core's get_rnd_text() handles long lines in a way + * that results in even selection distribution. + * + * Random epitaphs, engravings, and hallucinatory monster + * names are in the same boat. + */ + char *endp; + unsigned len = (unsigned) strlen(line); /* includes newline */ + + if (len <= padlength) { + endp = strchr(line, '\n'); /* fgetline() guarantees a newline even if + * the input file's last line lacks one */ + + /* this is safe provided that padlength+1 is less than the allocation + amount used in fgetline(); currently 144 (BUFSZ/2+16) */ + while (len++ < padlength) { + *endp++ = '_'; + } + *endp++ = '\n'; + *endp = '\0'; + } + return line; } -#define PAD_RUMORS_TO 60 /* common code for do_rumors(). Return 0 on error. */ static unsigned long -read_rumors_file(file_ext, rumor_count, rumor_size, old_rumor_offset) -const char *file_ext; -int *rumor_count; -long *rumor_size; -unsigned long old_rumor_offset; +read_rumors_file( + const char *file_ext, + int *rumor_count, + long *rumor_size, + unsigned long old_rumor_offset, + unsigned padlength) { - char infile[MAXFNAMELEN]; + char infile[MAXFNAMELEN], xbuf[BUFSZ]; char *line; unsigned long rumor_offset; @@ -921,36 +1050,19 @@ unsigned long old_rumor_offset; perror(infile); return 0L; } + set_fgetline_context(infile, TRUE, FALSE); /* copy the rumors */ while ((line = fgetline(ifp)) != 0) { -#ifdef PAD_RUMORS_TO - /* rumor selection is accomplished by seeking to a random - position in the file, advancing to newline, and taking - the next line; therefore, rumors which follow long-line - rumors are most likely to be chosen and rumors which - follow short-line rumors are least likely to be chosen; - we ameliorate the latter by padding the shortest lines, - increasing the chance of the random seek landing in them */ - int len = (int) strlen(line); - - if (len <= PAD_RUMORS_TO) { - char *base = index(line, '\n'); - /* this is only safe because fgetline() overallocates */ - while (len++ < PAD_RUMORS_TO) { - *base++ = '_'; - } - *base++ = '\n'; - *base = '\0'; - } -#endif + (void) padline(line, padlength); /* make shortest lines be longer */ + (*rumor_count)++; #if 0 /*[if we forced binary output, this would be sufficient]*/ *rumor_size += strlen(line); /* includes newline */ #endif - (void) fputs(xcrypt(line), tfp); - free(line); + (void) fputs(xcrypt(line, xbuf), tfp); + free((genericptr_t) line); } /* record the current position; next rumors section will start here */ rumor_offset = (unsigned long) ftell(tfp); @@ -966,17 +1078,22 @@ unsigned long old_rumor_offset; } static void -do_rnd_access_file(fname, deflt_content) -const char *fname; -const char *deflt_content; +do_rnd_access_file( + const char *fname, + const char *basefname, + const char *deflt_content, + unsigned padlength) { - char *line; + char *line, buf[BUFSZ], xbuf[BUFSZ], + greptmp[8 + 1 + 3 + 1]; + Sprintf(greptmp, "grep-%.3s.tmp", basefname); Sprintf(filename, DATA_IN_TEMPLATE, fname); Strcat(filename, ".txt"); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } filename[0] = '\0'; #ifdef FILE_PREFIX @@ -985,33 +1102,48 @@ const char *deflt_content; Sprintf(eos(filename), DATA_TEMPLATE, fname); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } Fprintf(ofp, "%s", Dont_Edit_Data); /* write out the default content entry unconditionally instead of waiting to see whether there are no regular output lines; if it matches a regular entry (bogusmon "grue"), that entry will become more likely to be picked than normal but it's nothing to worry about */ - (void) fputs(xcrypt(deflt_content), ofp); - - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); + Strcpy(buf, deflt_content); + if (!strchr(buf, '\n')) /* lines from the file include trailing newline +*/ + Strcat(buf, "\n"); /* so make sure that the default one does too */ + (void) fputs(xcrypt(padline(buf, padlength), xbuf), ofp); + + tfp = getfp(DATA_TEMPLATE, greptmp, WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, greptmp, RDTMODE, 0); +#endif + set_fgetline_context(NULL, FALSE, FALSE); while ((line = fgetline(ifp)) != 0) { - if (line[0] != '#' && line[0] != '\n') - (void) fputs(xcrypt(line), ofp); + if (line[0] != '#' && line[0] != '\n') { + (void) padline(line, padlength); + (void) fputs(xcrypt(line, xbuf), ofp); + } free((genericptr_t) line); } Fclose(ifp); Fclose(ofp); - delete_file(DATA_TEMPLATE, "grep.tmp"); +#ifdef HAS_NO_MKSTEMP + delete_file(DATA_TEMPLATE, greptmp); +#endif return; } +DISABLE_WARNING_FORMAT_NONLITERAL + void -do_rumors() +do_rumors(void) { char *line; static const char rumors_header[] = @@ -1029,12 +1161,14 @@ do_rumors() Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (!(tfp = fopen(tempfile, WRTMODE))) { perror(tempfile); Fclose(ofp); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } true_rumor_count = false_rumor_count = 0; @@ -1046,47 +1180,52 @@ do_rumors() true_rumor_size, true_rumor_offset, false_rumor_count, false_rumor_size, false_rumor_offset, eof_offset); /* record the current position; true rumors will start here */ - true_rumor_offset = ftell(tfp); + true_rumor_offset = (unsigned long) ftell(tfp); - false_rumor_offset = read_rumors_file( - ".tru", &true_rumor_count, &true_rumor_size, true_rumor_offset); + false_rumor_offset + = (unsigned long) read_rumors_file(".tru", &true_rumor_count, + &true_rumor_size, true_rumor_offset, + MD_PAD_RUMORS); if (!false_rumor_offset) goto rumors_failure; eof_offset = read_rumors_file(".fal", &false_rumor_count, - &false_rumor_size, false_rumor_offset); + &false_rumor_size, false_rumor_offset, + MD_PAD_RUMORS); if (!eof_offset) goto rumors_failure; /* get ready to transfer the contents of temp file to output file */ - line = malloc(BUFSZ + MAXFNAMELEN); + line = (char *) alloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) { perror(line); - free(line); + free((genericptr_t) line); goto rumors_failure; } - free(line); + free((genericptr_t) line); /* output the header record */ Fprintf(ofp, rumors_header, Dont_Edit_Data, true_rumor_count, true_rumor_size, true_rumor_offset, false_rumor_count, false_rumor_size, false_rumor_offset, eof_offset); + + set_fgetline_context(NULL, FALSE, FALSE); /* skip the temp file's dummy header */ if (!(line = fgetline(tfp))) { /* "Don't Edit" */ perror(tempfile); goto rumors_failure; } - free(line); + free((genericptr_t) line); if (!(line = fgetline(tfp))) { /* count,size,offset */ perror(tempfile); goto rumors_failure; } - free(line); + free((genericptr_t) line); /* copy the rest of the temp file into the final output file */ while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); - free(line); + free((genericptr_t) line); } /* all done; delete temp file */ Fclose(tfp); @@ -1094,915 +1233,66 @@ do_rumors() Fclose(ofp); return; -rumors_failure: + rumors_failure: Fclose(ofp); Unlink(filename); /* kill empty or incomplete output file */ Fclose(tfp); Unlink(tempfile); /* and temporary file */ - exit(EXIT_FAILURE); -} - -/* - * Use this to explicitly mask out features during version checks. - * - * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features - * that the port/plaform which wrote the savefile was capable of - * dealing with. Don't reject a savefile just because the port - * reading the savefile doesn't match on all/some of them. - * The actual compression features used to produce the savefile are - * recorded in the savefile_info structure immediately following the - * version_info, and that is what needs to be checked against the - * feature set of the port that is reading the savefile back in. - * That check is done in src/restore.c now. - * - */ -#define IGNORED_FEATURES \ - (0L | (1L << 19) /* SCORE_ON_BOTL */ \ - | (1L << 27) /* ZEROCOMP */ \ - | (1L << 28) /* RLECOMP */ \ - ) - -static void -make_version() -{ - register int i; - - /* - * integer version number - */ - version.incarnation = ((unsigned long) VERSION_MAJOR << 24) - | ((unsigned long) VERSION_MINOR << 16) - | ((unsigned long) PATCHLEVEL << 8) - | ((unsigned long) EDITLEVEL); - /* - * encoded feature list - * Note: if any of these magic numbers are changed or reassigned, - * EDITLEVEL in patchlevel.h should be incremented at the same time. - * The actual values have no special meaning, and the category - * groupings are just for convenience. - */ - version.feature_set = (unsigned long) (0L -/* levels and/or topology (0..4) */ -/* monsters (5..9) */ -#ifdef MAIL - | (1L << 6) -#endif -/* objects (10..14) */ -/* flag bits and/or other global variables (15..26) */ -#ifdef TEXTCOLOR - | (1L << 17) -#endif -#ifdef INSURANCE - | (1L << 18) -#endif -#ifdef SCORE_ON_BOTL - | (1L << 19) -#endif -/* data format (27..31) - * External compression methods such as COMPRESS and ZLIB_COMP - * do not affect the contents and are thus excluded from here */ -#ifdef ZEROCOMP - | (1L << 27) -#endif -#ifdef RLECOMP - | (1L << 28) -#endif - ); - /* - * Value used for object & monster sanity check. - * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0) - */ - for (i = 1; artifact_names[i]; i++) - continue; - version.entity_count = (unsigned long) (i - 1); - for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) - continue; - version.entity_count = (version.entity_count << 12) | (unsigned long) i; - for (i = 0; mons[i].mlet; i++) - continue; - version.entity_count = (version.entity_count << 12) | (unsigned long) i; - /* - * Value used for compiler (word size/field alignment/padding) check. - */ - version.struct_sizes1 = - (((unsigned long) sizeof(struct context_info) << 24) - | ((unsigned long) sizeof(struct obj) << 17) - | ((unsigned long) sizeof(struct monst) << 10) - | ((unsigned long) sizeof(struct you))); - version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10) | -/* free bits in here */ -#ifdef SYSFLAGS - ((unsigned long) sizeof(struct sysflag))); -#else - ((unsigned long) 0L)); -#endif - return; -} - -/* REPRODUCIBLE_BUILD will change this to TRUE */ -static boolean date_via_env = FALSE; - -static char * -version_string(outbuf, delim) -char *outbuf; -const char *delim; -{ - Sprintf(outbuf, "%d%s%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR, delim, - PATCHLEVEL); -#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) - Sprintf(eos(outbuf), "-%d", EDITLEVEL); -#endif - return outbuf; + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } -static char * -version_id_string(outbuf, build_date) -char *outbuf; -const char *build_date; +RESTORE_WARNING_FORMAT_NONLITERAL +void +do_data(void) { - char subbuf[64], versbuf[64]; - char statusbuf[64]; + char infile[60], tempfile[60]; + boolean ok; + long txt_offset; + int entry_cnt, line_cnt; + char *line; -#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) -#if (NH_DEVEL_STATUS == NH_STATUS_BETA) - Strcpy(statusbuf, " Beta"); -#else -#if (NH_DEVEL_STATUS == NH_STATUS_WIP) - Strcpy(statusbuf, " Work-in-progress"); -#else - Strcpy(statusbuf, " post-release"); -#endif + Sprintf(tempfile, DATA_TEMPLATE, "database.tmp"); + filename[0] = '\0'; +#ifdef FILE_PREFIX + Strcat(filename, file_prefix); #endif + Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE); + Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE); +#ifdef SHORT_FILENAMES + Strcat(infile, ".bas"); #else - statusbuf[0] = '\0'; + Strcat(infile, ".base"); #endif + if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */ + perror(infile); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + if (!(ofp = fopen(filename, WRTMODE))) { /* data */ + perror(filename); + Fclose(ifp); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */ + perror(tempfile); + Fclose(ifp); + Fclose(ofp); + Unlink(filename); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } - subbuf[0] = '\0'; -#ifdef PORT_SUB_ID - subbuf[0] = ' '; - Strcpy(&subbuf[1], PORT_SUB_ID); -#endif - - Sprintf(outbuf, "%s NetHack%s Version %s%s - last %s %s.", PORT_ID, - subbuf, version_string(versbuf, "."), statusbuf, - date_via_env ? "revision" : "build", build_date); - return outbuf; -} - -static char * -bannerc_string(outbuf, build_date) -char *outbuf; -const char *build_date; -{ - char subbuf[64], versbuf[64]; - - subbuf[0] = '\0'; -#ifdef PORT_SUB_ID - subbuf[0] = ' '; - Strcpy(&subbuf[1], PORT_SUB_ID); -#endif -#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) -#if (NH_DEVEL_STATUS == NH_STATUS_BETA) - Strcat(subbuf, " Beta"); -#else -#if (NH_DEVEL_STATUS == NH_STATUS_WIP) - Strcat(subbuf, " Work-in-progress"); -#else - Strcat(subbuf, " post-release"); -#endif -#endif -#endif - - Sprintf(outbuf, " Version %s %s%s, %s %s.", - version_string(versbuf, "."), PORT_ID, subbuf, - date_via_env ? "revised" : "built", &build_date[4]); -#if 0 - Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)", - PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR, - &build_date[4]); -#endif - return outbuf; -} - -void -do_date() -{ -#ifdef KR1ED - long clocktim = 0; -#else - time_t clocktim = 0; -#endif - char githash[BUFSZ], gitbranch[BUFSZ]; - char *c, cbuf[60], buf[BUFSZ]; - const char *ul_sfx; - - /* before creating date.h, make sure that xxx_GRAPHICS and - DEFAULT_WINDOW_SYS have been set up in a viable fashion */ - windowing_sanity(); - - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE); - if (!(ofp = fopen(filename, WRTMODE))) { - perror(filename); - exit(EXIT_FAILURE); - } - /* NB: We've moved on from SCCS, but this way this line - * won't get clobbered when downstream projects import - * this file into something more modern. */ - Fprintf(ofp, "%s", Dont_Edit_Code); - - (void) time(&clocktim); -#ifdef REPRODUCIBLE_BUILD - { - /* - * Use date+time of latest source file revision (set up in - * our environment rather than derived by scanning sources) - * instead of current date+time, so that later rebuilds of - * the same sources specifying the same configuration will - * produce the same result. - * - * Changing the configuration should be done by modifying - * config.h or conf.h and setting SOURCE_DATE_EPOCH - * based on whichever changed most recently, not by using - * make CFLAGS='-Dthis -Dthat' - * to make alterations on the fly. - * - * Limited validation is performed to prevent dates in the - * future (beyond a leeway of 24 hours) or distant past. - * - * Assumes the value of time_t is in seconds, which is - * fundamental for Unix and mandated by POSIX. For any ports - * where that isn't true, leaving REPRODUCIBLE_BUILD disabled - * is probably preferrable to hacking this code.... - */ - static struct tm nh360; /* static init should yield UTC timezone */ - unsigned long sd_num, sd_earliest, sd_latest; - const char *sd_str = getenv("SOURCE_DATE_EPOCH"); - - if (sd_str) { - sd_num = strtoul(sd_str, (char **) 0, 10); - /* - * Note: this does not need to be updated for future - * releases. It serves as a sanity check for potentially - * mis-set environment, not a hard baseline for when the - * current version could have first been built. - */ - /* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */ - nh360.tm_mday = 7; - nh360.tm_mon = 12 - 1; - nh360.tm_year = 2015 - 1900; - sd_earliest = (unsigned long) mktime(&nh360); - /* 'youngest' date we'll accept: 24 hours in the future */ - sd_latest = (unsigned long) clocktim + 24L * 60L * 60L; - - if (sd_num >= sd_earliest && sd_num <= sd_latest) { - /* use SOURCE_DATE_EPOCH value */ - clocktim = (time_t) sd_num; - date_via_env = TRUE; - } else { - Fprintf(stderr, "? Invalid value for SOURCE_DATE_EPOCH (%lu)", - sd_num); - if (sd_num > 0L && sd_num < sd_earliest) - Fprintf(stderr, ", older than %lu", sd_earliest); - else if (sd_num > sd_latest) - Fprintf(stderr, ", newer than %lu", sd_latest); - Fprintf(stderr, ".\n"); - Fprintf(stderr, ": Reverting to current date+time (%lu).\n", - (unsigned long) clocktim); - (void) fflush(stderr); - } - } else { - /* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */ - Fprintf(stderr, "? No value for SOURCE_DATE_EPOCH.\n"); - Fprintf(stderr, ": Using current date+time (%lu).\n", - (unsigned long) clocktim); - (void) fflush(stderr); - } - Strcpy(cbuf, asctime(gmtime(&clocktim))); - } -#else - /* ordinary build: use current date+time */ - Strcpy(cbuf, ctime(&clocktim)); -#endif - - if ((c = index(cbuf, '\n')) != 0) - *c = '\0'; /* strip off the '\n' */ -#ifdef NHSTDC - ul_sfx = "UL"; -#else - ul_sfx = "L"; -#endif - if (date_via_env) - Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n", - (unsigned long) clocktim, ul_sfx); - Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf); - if (date_via_env) - Fprintf(ofp, "#define BUILD_TIME SOURCE_DATE_EPOCH\n"); - else - Fprintf(ofp, "#define BUILD_TIME (%lu%s)\n", - (unsigned long) clocktim, ul_sfx); - Fprintf(ofp, "\n"); - Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation, - ul_sfx); - Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set, - ul_sfx); -#ifdef IGNORED_FEATURES - Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n", - (unsigned long) IGNORED_FEATURES, ul_sfx); -#endif - Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, - ul_sfx); - Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1, - ul_sfx); - Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2, - ul_sfx); - Fprintf(ofp, "\n"); - Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", version_string(buf, ".")); - Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n", - version_id_string(buf, cbuf)); - Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n", - bannerc_string(buf, cbuf)); - Fprintf(ofp, "\n"); - if (get_gitinfo(githash, gitbranch)) { - Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash); - Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch); - } -#ifdef AMIGA - { - struct tm *tm = localtime((time_t *) &clocktim); - - Fprintf(ofp, "#define AMIGA_VERSION_STRING "); - Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n", - VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, - tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900); - } -#endif - Fclose(ofp); - return; -} - -static boolean -get_gitinfo(githash, gitbranch) -char *githash, *gitbranch; -{ - FILE *gifp; - size_t len; - char infile[MAXFNAMELEN]; - char *line, *strval, *opt, *c, *end; - boolean havebranch = FALSE, havehash = FALSE; - - if (!githash || !gitbranch) return FALSE; - - Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE); - if (!(gifp = fopen(infile, RDTMODE))) { - /* perror(infile); */ - return FALSE; - } - - /* read the gitinfo file */ - while ((line = fgetline(gifp)) != 0) { - strval = index(line, '='); - if (strval && strlen(strval) < (BUFSZ-1)) { - opt = line; - *strval++ = '\0'; - /* strip off the '\n' */ - if ((c = index(strval, '\n')) != 0) - *c = '\0'; - if ((c = index(opt, '\n')) != 0) - *c = '\0'; - /* strip leading and trailing white space */ - while (*strval == ' ' || *strval == '\t') - strval++; - end = eos(strval); - while (--end >= strval && (*end == ' ' || *end == '\t')) - *end = '\0'; - while (*opt == ' ' || *opt == '\t') - opt++; - end = eos(opt); - while (--end >= opt && (*end == ' ' || *end == '\t')) - *end = '\0'; - - len = strlen(opt); - if ((len >= strlen("gitbranch")) && !case_insensitive_comp(opt, "gitbranch")) { - Strcpy(gitbranch, strval); - havebranch = TRUE; - } - if ((len >= strlen("githash")) && !case_insensitive_comp(opt, "githash")) { - Strcpy(githash, strval); - havehash = TRUE; - } - } - free(line); - } - Fclose(gifp); - if (havebranch && havehash) - return TRUE; - return FALSE; -} - -static int -case_insensitive_comp(s1, s2) -const char *s1; -const char *s2; -{ - uchar u1, u2; - - for (;; s1++, s2++) { - u1 = (uchar) *s1; - if (isupper(u1)) - u1 = tolower(u1); - u2 = (uchar) *s2; - if (isupper(u2)) - u2 = tolower(u2); - if (u1 == '\0' || u1 != u2) - break; - } - return u1 - u2; -} - -static char save_bones_compat_buf[BUFSZ]; - -static void -build_savebones_compat_string() -{ -#ifdef VERSION_COMPATIBILITY - unsigned long uver = VERSION_COMPATIBILITY; -#endif - Strcpy(save_bones_compat_buf, - "save and bones files accepted from version"); -#ifdef VERSION_COMPATIBILITY - Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d", - ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16), - ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR, - PATCHLEVEL); -#else - Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR, - VERSION_MINOR, PATCHLEVEL); -#endif -} - -static const char *build_opts[] = { -#ifdef AMIGA_WBENCH - "Amiga WorkBench support", -#endif -#ifdef ANSI_DEFAULT - "ANSI default terminal", -#endif -#ifdef TEXTCOLOR - "color", -#endif -#ifdef TTY_GRAPHICS -#ifdef TTY_TILES_ESCCODES - "console escape codes for tile hinting", -#endif -#endif -#ifdef COM_COMPL - "command line completion", -#endif -#ifdef LIFE - "Conway's Game of Life", -#endif -#ifdef COMPRESS - "data file compression", -#endif -#ifdef ZLIB_COMP - "ZLIB data file compression", -#endif -#ifdef DLB -#ifndef VERSION_IN_DLB_FILENAME - "data librarian", -#else - "data librarian with a version-dependent name", -#endif -#endif -#ifdef DUMPLOG - "end-of-game dumplogs", -#endif -#ifdef HOLD_LOCKFILE_OPEN - "exclusive lock on level 0 file", -#endif -#if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) - "external program as a message handler", -#endif -#ifdef MFLOPPY - "floppy drive support", -#endif -#ifdef INSURANCE - "insurance files for recovering from crashes", -#endif -#ifdef LOGFILE - "log file", -#endif -#ifdef XLOGFILE - "extended log file", -#endif -#ifdef PANICLOG - "errors and warnings log file", -#endif -#ifdef MAIL - "mail daemon", -#endif -#ifdef GNUDOS - "MSDOS protected mode", -#endif -#ifdef NEWS - "news file", -#endif -#ifdef OVERLAY -#ifdef MOVERLAY - "MOVE overlays", -#else -#ifdef VROOMM - "VROOMM overlays", -#else - "overlays", -#endif -#endif -#endif - /* pattern matching method will be substituted by nethack at run time */ - "pattern matching via :PATMATCH:", -#ifdef USE_ISAAC64 - "pseudo random numbers generated by ISAAC64", -#ifdef DEV_RANDOM -#ifdef NHSTDC - /* include which specific one */ - "strong PRNG seed available from " DEV_RANDOM, -#else - "strong PRNG seed available from DEV_RANDOM", -#endif -#else -#ifdef WIN32 - "strong PRNG seed available from CNG BCryptGenRandom()", -#endif -#endif /* DEV_RANDOM */ -#else /* ISAAC64 */ -#ifdef RANDOM - "pseudo random numbers generated by random()", -#else - "pseudo random numbers generated by C rand()", -#endif -#endif -#ifdef SELECTSAVED - "restore saved games via menu", -#endif -#ifdef SCORE_ON_BOTL - "score on status line", -#endif -#ifdef CLIPPING - "screen clipping", -#endif -#ifdef NO_TERMS -#ifdef MAC - "screen control via mactty", -#endif -#ifdef SCREEN_BIOS - "screen control via BIOS", -#endif -#ifdef SCREEN_DJGPPFAST - "screen control via DJGPP fast", -#endif -#ifdef SCREEN_VGA - "screen control via VGA graphics", -#endif -#ifdef WIN32CON - "screen control via WIN32 console I/O", -#endif -#endif -#ifdef SHELL - "shell command", -#endif - "traditional status display", -#ifdef STATUS_HILITES - "status via windowport with highlighting", -#else - "status via windowport without highlighting", -#endif -#ifdef SUSPEND - "suspend command", -#endif -#ifdef TTY_GRAPHICS -#ifdef TERMINFO - "terminal info library", -#else -#if defined(TERMLIB) || (!defined(MICRO) && !defined(WIN32)) - "terminal capability library", -#endif -#endif -#endif /*TTY_GRAPHICS*/ -/*#ifdef X11_GRAPHICS*/ -#ifdef USE_XPM - "tiles file in XPM format", -#endif -/*#endif*/ -/*#if (defined(QT_GRAPHICS) || defined(X11_GRAPHICS)*/ -#ifdef GRAPHIC_TOMBSTONE - "graphical RIP screen", -#endif -/*#endif*/ -#ifdef TIMED_DELAY - "timed wait for display effects", -#endif -#ifdef USER_SOUNDS - "user sounds", -#endif -#ifdef PREFIXES_IN_USE - "variable playground", -#endif -#ifdef VISION_TABLES - "vision tables", -#endif -#ifdef ZEROCOMP - "zero-compressed save files", -#endif -#ifdef RLECOMP - "run-length compression of map in save files", -#endif -#ifdef SYSCF - "system configuration at run-time", -#endif - save_bones_compat_buf, - "and basic NetHack features" -}; - -struct win_info { - const char *id, /* DEFAULT_WINDOW_SYS string */ - *name; /* description, often same as id */ -}; -static struct win_info window_opts[] = { -#ifdef TTY_GRAPHICS - { "tty", - /* testing 'USE_TILES' here would bring confusion because it could - apply to another interface such as X11, so check MSDOS explicitly - instead; even checking TTY_TILES_ESCCODES would probably be - confusing to most users (and it will already be listed separately - in the compiled options section so users aware of it can find it) */ -#ifdef MSDOS - "traditional text with optional 'tiles' graphics" -#else - /* assume that one or more of IBMgraphics, DECgraphics, or MACgraphics - can be enabled; we can't tell from here whether that is accurate */ - "traditional text with optional line-drawing" -#endif - }, -#endif -#ifdef CURSES_GRAPHICS - { "curses", "terminal-based graphics" }, -#endif -#ifdef X11_GRAPHICS - { "X11", "X11" }, -#endif -#ifdef QT_GRAPHICS /* too vague; there are multiple incompatible versions */ - { "Qt", "Qt" }, -#endif -#ifdef GNOME_GRAPHICS /* unmaintained/defunct */ - { "Gnome", "Gnome" }, -#endif -#ifdef MAC /* defunct OS 9 interface */ - { "mac", "Mac" }, -#endif -#ifdef AMIGA_INTUITION /* unmaintained/defunct */ - { "amii", "Amiga Intuition" }, -#endif -#ifdef GEM_GRAPHICS /* defunct Atari interface */ - { "Gem", "Gem" }, -#endif -#ifdef MSWIN_GRAPHICS /* win32 */ - { "mswin", "mswin" }, -#endif -#ifdef BEOS_GRAPHICS /* unmaintained/defunct */ - { "BeOS", "BeOS InterfaceKit" }, -#endif -#ifdef RL_GRAPHICS - { "rl", "Reinforcement learning 'graphics'" }, -#endif - { 0, 0 } -}; - -static void -windowing_sanity() -{ -#ifndef DEFAULT_WINDOW_SYS - /* pre-standard compilers didn't support #error; wait til run-time */ - Fprintf(stderr, - "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n"); - exit(EXIT_FAILURE); -/*NOTREACHED*/ - -/* put in a dummy value so that do_options() will compile and makedefs - will build, otherwise the message above won't ever get delivered */ -#define DEFAULT_WINDOW_SYS "" -#else /*DEFAULT_WINDOW_SYS*/ - - if (!window_opts[0].id) { - Fprintf(stderr, "Configuration error: no windowing systems " - "(TTY_GRAPHICS, &c) enabled.\n"); - exit(EXIT_FAILURE); - } - - { - int i; - - for (i = 0; window_opts[i].id; ++i) - if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS)) - break; - if (!window_opts[i].id) { /* went through whole list without a match */ - Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n", - DEFAULT_WINDOW_SYS); - Fprintf(stderr, - " does not match any enabled windowing system (%s%s).\n", - window_opts[0].id, window_opts[1].id ? ", &c" : ""); - exit(EXIT_FAILURE); - } - } -#endif /*DEFAULT_WINDOW_SYS*/ -} - -static const char opt_indent[] = " "; - -static void -opt_out_words(str, length_p) -char *str; /* input, but modified during processing */ -int *length_p; /* in/out */ -{ - char *word; - - while (*str) { - word = index(str, ' '); -#if 0 - /* treat " (" as unbreakable space */ - if (word && *(word + 1) == '(') - word = index(word + 1, ' '); -#endif - if (word) - *word = '\0'; - if (*length_p + (int) strlen(str) > COLNO - 5) - Fprintf(ofp, "\n%s", opt_indent), - *length_p = (int) strlen(opt_indent); - else - Fprintf(ofp, " "), (*length_p)++; - Fprintf(ofp, "%s", str), *length_p += (int) strlen(str); - str += strlen(str) + (word ? 1 : 0); - } -} - -void -do_options() -{ - char buf[BUFSZ]; - int i, length, winsyscnt; - - windowing_sanity(); - - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE); - if (!(ofp = fopen(filename, WRTMODE))) { - perror(filename); - exit(EXIT_FAILURE); - } - - build_savebones_compat_string(); - Fprintf(ofp, "\n%sNetHack version %d.%d.%d%s\n", - opt_indent, - VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, -#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) -#if (NH_DEVEL_STATUS == NH_STATUS_BETA) - " [beta]" -#else -#if (NH_DEVEL_STATUS == NH_STATUS_WIP) - " [work-in-progress]" -#else - " [post-release]" -#endif -#endif -#else - "" -#endif - ); - - Fprintf(ofp, "\nOptions compiled into this edition:\n"); - length = COLNO + 1; /* force 1st item onto new line */ - for (i = 0; i < SIZE(build_opts); i++) { - opt_out_words(strcat(strcpy(buf, build_opts[i]), - (i < SIZE(build_opts) - 1) ? "," : "."), - &length); - } - Fprintf(ofp, "\n"); /* terminate last line of words */ - - winsyscnt = SIZE(window_opts) - 1; - Fprintf(ofp, "\nSupported windowing system%s:\n", - (winsyscnt > 1) ? "s" : ""); - length = COLNO + 1; /* force 1st item onto new line */ - for (i = 0; i < winsyscnt; i++) { - Sprintf(buf, "\"%s\"", window_opts[i].id); - if (strcmp(window_opts[i].name, window_opts[i].id)) - Sprintf(eos(buf), " (%s)", window_opts[i].name); - /* - * 1 : foo. - * 2 : foo and bar (note no period; comes from 'with default' below) - * 3+: for, bar, and quux - */ - opt_out_words(strcat(buf, (winsyscnt == 1) ? "." /* no 'default' */ - : (winsyscnt == 2 && i == 0) ? " and" - : (i == winsyscnt - 2) ? ", and" - : ","), - &length); - } - if (winsyscnt > 1) { - Sprintf(buf, "with a default of \"%s\".", DEFAULT_WINDOW_SYS); - opt_out_words(buf, &length); - } - Fprintf(ofp, "\n"); /* terminate last line of words */ - - /* end with a blank line */ - Fprintf(ofp, "\n"); - Fclose(ofp); - return; -} - -/* routine to decide whether to discard something from data.base */ -static boolean -d_filter(line) -char *line; -{ - if (*line == '#') - return TRUE; /* ignore comment lines */ - return FALSE; -} - -/* - * - New format (v3.1) of 'data' file which allows much faster lookups [pr] -"do not edit" first record is a comment line -01234567 hexadecimal formatted offset to text area -name-a first name of interest -123,4 offset to name's text, and number of lines for it -name-b next name of interest -name-c multiple names which share same description also -456,7 share a single offset,count line -. sentinel to mark end of names -789,0 dummy record containing offset, count of EOF -text-a 4 lines of descriptive text for name-a -text-a at file position 0x01234567L + 123L -text-a -text-a -text-b/text-c 7 lines of text for names-b and -c -text-b/text-c at fseek(0x01234567L + 456L) -... - * - */ - -void -do_data() -{ - char infile[60], tempfile[60]; - boolean ok; - long txt_offset; - int entry_cnt, line_cnt; - char *line; - - Sprintf(tempfile, DATA_TEMPLATE, "database.tmp"); - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE); - Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE); -#ifdef SHORT_FILENAMES - Strcat(infile, ".bas"); -#else - Strcat(infile, ".base"); -#endif - if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */ - perror(infile); - exit(EXIT_FAILURE); - } - if (!(ofp = fopen(filename, WRTMODE))) { /* data */ - perror(filename); - Fclose(ifp); - exit(EXIT_FAILURE); - } - if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */ - perror(tempfile); - Fclose(ifp); - Fclose(ofp); - Unlink(filename); - exit(EXIT_FAILURE); - } - - /* output a dummy header record; we'll rewind and overwrite it later */ - Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L); + /* output a dummy header record; we'll rewind and overwrite it later */ + Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L); entry_cnt = line_cnt = 0; + set_fgetline_context(infile, TRUE, TRUE); /* read through the input file and split it into two sections */ while ((line = fgetline(ifp)) != 0) { if (d_filter(line)) { - free(line); + free((genericptr_t) line); continue; } if (*line > ' ') { /* got an entry name */ @@ -2020,7 +1310,7 @@ do_data() (void) fputs(line, tfp); line_cnt++; /* update line counter */ } - free(line); + free((genericptr_t) line); } /* output an end marker and then record the current position */ if (line_cnt) @@ -2031,14 +1321,19 @@ do_data() /* reprocess the scratch file; 1st format an error msg, just in case */ line = malloc(BUFSZ + MAXFNAMELEN); + if (!line) { + fprintf(stderr, "makedefs malloc() failure\n"); + exit(EXIT_FAILURE); + } Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; - free(line); + free((genericptr_t) line); + set_fgetline_context(NULL, FALSE, TRUE); /* copy all lines of text from the scratch file into the output file */ while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); - free(line); + free((genericptr_t) line); } /* finished with scratch file */ @@ -2046,7 +1341,7 @@ do_data() Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ - line = malloc(BUFSZ + MAXFNAMELEN); + line = (char *) alloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { @@ -2055,15 +1350,16 @@ do_data() (unsigned long) txt_offset) >= 0); } if (!ok) { - dead_data: + dead_data: perror(line); /* report the problem */ - free(line); + free((genericptr_t) line); /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - free(line); + free((genericptr_t) line); /* all done */ Fclose(ofp); @@ -2073,8 +1369,7 @@ do_data() /* routine to decide whether to discard something from oracles.txt */ static boolean -h_filter(line) -char *line; +h_filter(char *line) { static boolean skip = FALSE; char *tag; @@ -2084,23 +1379,35 @@ char *line; if (*line == '#') return TRUE; /* ignore comment lines */ - tag = malloc(strlen(line)); + tag = (char *) alloc((unsigned) strlen(line)); /* don't need +1 here */ if (sscanf(line, "----- %s", tag) == 1) { skip = FALSE; } else if (skip && !strncmp(line, "-----", 5)) skip = FALSE; - free(tag); + free((genericptr_t) tag); return skip; } +/* routine to decide whether to discard something from data.base */ +static boolean +d_filter(char *line) +{ + if (*line == '#') + return TRUE; /* ignore comment lines */ + return FALSE; +} + static const char *special_oracle[] = { "\"...it is rather disconcerting to be confronted with the", - "following theorem from [Baker, Gill, and Solovay, 1975].", "", + "following theorem from [Baker, Gill, and Solovay, 1975].", + "", "Theorem 7.18 There exist recursive languages A and B such that", - " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "", + " (1) P(A) == NP(A), and", + " (2) P(B) != NP(B)", + "", "This provides impressive evidence that the techniques that are", - "currently available will not suffice for proving that P != NP or " - " ", + ("currently available will not suffice for proving that P != NP or" + " "), "that P == NP.\" [Garey and Johnson, p. 185.]" }; @@ -2113,14 +1420,14 @@ static const char *special_oracle[] = { */ void -do_oracles() +do_oracles(void) { - char infile[60], tempfile[60]; + char infile[60], tempfile[60], xbuf[BUFSZ]; boolean in_oracle, ok; long fpos; unsigned long txt_offset, offset; int oracle_cnt; - register int i; + int i; char *line; Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp"); @@ -2133,19 +1440,22 @@ do_oracles() Strcat(infile, ".txt"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Fclose(ifp); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } /* output a dummy header record; we'll rewind and overwrite it later */ @@ -2156,7 +1466,7 @@ do_oracles() offset = (unsigned long) ftell(tfp); Fprintf(ofp, "%05lx\n", offset); /* start pos of special oracle */ for (i = 0; i < SIZE(special_oracle); i++) { - (void) fputs(xcrypt(special_oracle[i]), tfp); + (void) fputs(xcrypt(special_oracle[i], xbuf), tfp); (void) fputc('\n', tfp); } SpinCursor(3); @@ -2167,16 +1477,17 @@ do_oracles() Fprintf(ofp, "%05lx\n", offset); /* start pos of first oracle */ in_oracle = FALSE; + set_fgetline_context(infile, TRUE, FALSE); while ((line = fgetline(ifp)) != 0) { SpinCursor(3); if (h_filter(line)) { - free(line); + free((genericptr_t) line); continue; } if (!strncmp(line, "-----", 5)) { if (!in_oracle) { - free(line); + free((genericptr_t) line); continue; } in_oracle = FALSE; @@ -2186,9 +1497,9 @@ do_oracles() Fprintf(ofp, "%05lx\n", offset); /* start pos of this oracle */ } else { in_oracle = TRUE; - (void) fputs(xcrypt(line), tfp); + (void) fputs(xcrypt(line, xbuf), tfp); } - free(line); + free((genericptr_t) line); } if (in_oracle) { /* need to terminate last oracle */ @@ -2203,15 +1514,16 @@ do_oracles() Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ - line = malloc(BUFSZ + MAXFNAMELEN); + line = (char *) alloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; - free(line); + free((genericptr_t) line); /* copy all lines of text from the scratch file into the output file */ + set_fgetline_context(tempfile, FALSE, FALSE); while ((line = fgetline(tfp)) != 0) { (void) fputs(line, ofp); - free(line); + free((genericptr_t) line); } /* finished with scratch file */ @@ -2219,7 +1531,7 @@ do_oracles() Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ - line = malloc(BUFSZ + MAXFNAMELEN); + line = (char *) alloc(BUFSZ + MAXFNAMELEN); Sprintf(line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { @@ -2239,7 +1551,7 @@ do_oracles() break; if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break; -#ifdef MAC +#ifdef MACOS9 #ifdef __MWERKS__ /* MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL @@ -2258,15 +1570,16 @@ do_oracles() } } if (!ok) { - dead_data: + dead_data: perror(line); /* report the problem */ - free(line); + free((genericptr_t) line); /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - free(line); + free((genericptr_t) line); /* all done */ Fclose(ofp); @@ -2274,520 +1587,622 @@ do_oracles() return; } -void -do_dungeon() +/* Read one line from input, up to and including the next newline + * character. Returns a pointer to the heap-allocated string, or a + * null pointer if no characters were read. + * 5.0: redone to use nethack's alloc() rather than libc's malloc() + * and realloc(). + */ +static char * +fgetline(FILE *fd) { - char *line; + static const int inc = (BUFSZ / 2) + 16; /* fgets() wants signed int */ + unsigned len = (unsigned) inc, newlen; /* alloc() wants unsigned int */ + char *c = (char *) alloc(len), *cprime, *ret; - Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE); - if (!(ifp = fopen(filename, RDTMODE))) { - perror(filename); - exit(EXIT_FAILURE); + *c = '\0'; + for (;;) { + ret = fgets(c + len - inc, inc, fd); + if (!ret) { + /* don't just assume ret==Null indicates an error; last line + might lack terminating newline; if previous fgets() read it, + instead of returning we would have expanded the buffer and + tried for more, then got Null due to end of file having + already been reached */ + if (feof(fd) && *c && strlen(c) < len) { + Strcat(c, "\n"); /* append missing newline */ + } else { + free((genericptr_t) c), c = NULL; + } + break; /* either with or without added newline, we're done */ + } else if (strchr(c, '\n')) { + /* normal case: we have a full line */ + break; + } + /* didn't fit in c[0..len-1]; expand buffer and read some more + [this was much simpler (and possibly slightly more efficient) + with realloc() but less safe because return values from malloc() + and realloc() were not being checked for Null, and efficiency is + a red herring because growing the buffer will be extremely rare] */ + newlen = len + (unsigned) inc; + cprime = (char *) alloc(newlen); + (void) memcpy(cprime, c, len); + free((genericptr_t) c); + c = cprime; + *(c + len) = '\0'; + len = newlen; + } + + filter_nonascii(c); + return c; +} + +static void +filter_nonascii(char *line) +{ +#ifdef MAKEDEFS_FILTER_NONASCII + char warnbuf[BUFSZ]; + unsigned char *p; + int warned = 0, prevreason = -1, reason; +#endif + + if (!line) /* end of file; uses 'line' for !MAKEDEFS_FILTER_NONASCII */ + return; + ascii_ctx.linenum += 1; + if (!ascii_ctx.dofilter) + return; + +#ifdef MAKEDEFS_FILTER_NONASCII + for (p = (unsigned char *) line; *p; ++p) { + if (*p == '\n') + break; + if (*p == '\t' && ascii_ctx.tabok) + continue; + reason = (*p > 126) ? 3 : (*p == '\t') ? 2 : (*p < ' '); + if (reason != 0) { + if (!warned) + ascii_ctx.warncnt += 1; /* number of lines warned about */ + if (++warned <= 3) { /* show up to 3 warnings for this line */ + if (warned == 1) { + /*assert(ascii_ctx.filename != NULL);*/ + Sprintf(warnbuf, "? %s:", ascii_ctx.filename); + } else { + Strcpy(warnbuf, ","); + } + Sprintf(eos(warnbuf), " %d.%ld", ascii_ctx.linenum, + (long) ((char *) p - line)); /* column */ + if (reason != prevreason) { + Strcat(warnbuf, (reason == 1) ? " non-printable" + : (reason == 3) ? " non-ascii" + : " "); /* (reason == 2) */ + prevreason = reason; + } + Fprintf(stderr, "%s '%03o'", warnbuf, *p); + } else if (warned == 3 + 1) { /* when more than 3 */ + Fprintf(stderr, ", ..."); /* show an indicator */ + } + *p = '#'; + } } + if (warned > 0) + Fprintf(stderr, "\n"); +#endif + return; +} + +static void +set_fgetline_context( + const char *current_filename, + boolean do_filtering, + boolean tabs_are_ok) /* moot for !do_filtering */ +{ + static const char dummyname[] = "[makedefs input]"; + +#ifndef MAKEDEFS_FILTER_NONASCII + do_filtering = FALSE; +#endif + if (!current_filename) + current_filename = dummyname; + /* change from relative-to-dat to be relative-to-top, iff that's easy */ + if (!strncmp(current_filename, "../", 3)) + current_filename += 3; + + ascii_ctx.filename = current_filename; + ascii_ctx.linenum = ascii_ctx.warncnt = 0; + ascii_ctx.tabok = tabs_are_ok; + ascii_ctx.dofilter = do_filtering; +} + +#if defined(OLD_MAKEDEFS_OPTIONS) +void +do_date(void) +{ +#ifdef KR1ED + long clocktim = 0; +#else + time_t clocktim = 0; +#endif + char githash[BUFSZ], gitbranch[BUFSZ]; + char *c, cbuf[60], buf[BUFSZ]; + const char *ul_sfx; +#if defined(CROSSCOMPILE) && !defined(CROSSCOMPILE_TARGET) + const char *xpref = "HOST_"; +#else + const char *xpref = (const char *) 0; +#endif /* CROSSCOMPILE && !CROSSCOMPILE_TARGET */ + + /* before creating date.h, make sure that xxx_GRAPHICS and + DEFAULT_WINDOW_SYS have been set up in a viable fashion */ + windowing_sanity(); + filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif - Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE); + Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + /* NB: We've moved on from SCCS, but this way this line + * won't get clobbered when downstream projects import + * this file into something more modern. */ + Fprintf(ofp, "%s", Reference_file); + + (void) time(&clocktim); +#ifdef REPRODUCIBLE_BUILD + { + /* + * Use date+time of latest source file revision (set up in + * our environment rather than derived by scanning sources) + * instead of current date+time, so that later rebuilds of + * the same sources specifying the same configuration will + * produce the same result. + * + * Changing the configuration should be done by modifying + * config.h or conf.h and setting SOURCE_DATE_EPOCH + * based on whichever changed most recently, not by using + * make CFLAGS='-Dthis -Dthat' + * to make alterations on the fly. + * + * Limited validation is performed to prevent dates in the + * future (beyond a leeway of 24 hours) or distant past. + * + * Assumes the value of time_t is in seconds, which is + * fundamental for Unix and mandated by POSIX. For any ports + * where that isn't true, leaving REPRODUCIBLE_BUILD disabled + * is probably preferrable to hacking this code.... + */ + static struct tm nh360; /* static init should yield UTC timezone */ + unsigned long sd_num, sd_earliest, sd_latest; + const char *sd_str = getenv("SOURCE_DATE_EPOCH"); + + if (sd_str) { + sd_num = strtoul(sd_str, (char **) 0, 10); + /* + * Note: this does not need to be updated for future + * releases. It serves as a sanity check for potentially + * mis-set environment, not a hard baseline for when the + * current version could have first been built. + */ + /* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */ + nh360.tm_mday = 7; + nh360.tm_mon = 12 - 1; + nh360.tm_year = 2015 - 1900; + sd_earliest = (unsigned long) mktime(&nh360); + /* 'youngest' date we'll accept: 24 hours in the future */ + sd_latest = (unsigned long) clocktim + 24L * 60L * 60L; + + if (sd_num >= sd_earliest && sd_num <= sd_latest) { + /* use SOURCE_DATE_EPOCH value */ + clocktim = (time_t) sd_num; + date_via_env = TRUE; + } else { + Fprintf(stderr, "? Invalid value for SOURCE_DATE_EPOCH (%lu)", + sd_num); + if (sd_num > 0L && sd_num < sd_earliest) + Fprintf(stderr, ", older than %lu", sd_earliest); + else if (sd_num > sd_latest) + Fprintf(stderr, ", newer than %lu", sd_latest); + Fprintf(stderr, ".\n"); + Fprintf(stderr, ": Reverting to current date+time (%lu).\n", + (unsigned long) clocktim); + (void) fflush(stderr); + } + } else { + /* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */ + Fprintf(stderr, "? No value for SOURCE_DATE_EPOCH.\n"); + Fprintf(stderr, ": Using current date+time (%lu).\n", + (unsigned long) clocktim); + (void) fflush(stderr); + } +#if !defined(NOSTRFTIME) + if (!strftime(cbuf, sizeof cbuf, "%c", gmtime(&clocktim))) + cbuf[0] = '\0'; +#else + Strcpy(cbuf, asctime(gmtime(&clocktim))); +#endif /* NOSTRFTIME */ + } +#else + /* ordinary build: use current date+time */ +#if !defined(NOSTRFTIME) + if (!strftime(cbuf, sizeof cbuf, "%c", localtime(&clocktim))) + cbuf[0] = '\0'; +#else + Strcpy(cbuf, ctime(&clocktim)); +#endif /* NOSTRFTIME */ +#endif /* REPRODUCIBLE_BUILD */ + + if ((c = strchr(cbuf, '\n')) != 0) + *c = '\0'; /* strip off the '\n' */ +#ifdef NHSTDC + ul_sfx = "UL"; +#else + ul_sfx = "L"; +#endif + +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) + Fprintf(ofp, + "\n#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET)\n"); +#endif /* CROSSCOMPILE || !CROSSCOMPILE_TARGET */ + if (date_via_env) + Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n", + (unsigned long) clocktim, ul_sfx); + Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf); + if (date_via_env) + Fprintf(ofp, "#define BUILD_TIME SOURCE_DATE_EPOCH\n"); + else + Fprintf(ofp, "#define BUILD_TIME (%lu%s)\n", + (unsigned long) clocktim, ul_sfx); + Fprintf(ofp, "\n"); + Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation, + ul_sfx); + Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set, + ul_sfx); + { + unsigned long ignored_features = md_ignored_features(); + + Fprintf(ofp, "#define IGNORED_FEATURES 0x%08lx%s\n", + ignored_features, ul_sfx); + } + Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, + ul_sfx); + Fprintf(ofp, "\n"); + Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", + mdlib_version_string(buf, ".")); + Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n", + version_id_string(buf, sizeof buf, cbuf)); + Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n", + bannerc_string(buf, sizeof buf, cbuf)); + if (get_gitinfo(githash, gitbranch)) { + Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash); + Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch); } - Fprintf(ofp, "%s", Dont_Edit_Data); - - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); - - while ((line = fgetline(ifp)) != 0) { - SpinCursor(3); + if (xpref && get_gitinfo(githash, gitbranch)) { + Fprintf(ofp, "#else /* !CROSSCOMPILE || !CROSSCOMPILE_TARGET */\n"); + Fprintf(ofp, "#define NETHACK_%sGIT_SHA \"%s\"\n", + xpref, githash); + Fprintf(ofp, "#define NETHACK_%sGIT_BRANCH \"%s\"\n", + xpref, gitbranch); + } +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) + Fprintf(ofp, "#endif /* !CROSSCOMPILE || !CROSSCOMPILE_TARGET */\n"); +#endif + Fprintf(ofp, "\n"); +#ifdef AMIGA + { + struct tm *tm = localtime((time_t *) &clocktim); - if (line[0] == '#') { - free(line); - continue; /* discard comments */ - } - (void) fputs(line, ofp); - free(line); + Fprintf(ofp, "#define AMIGA_VERSION_STRING "); + Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n", + VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, + tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900); } - Fclose(ifp); +#endif Fclose(ofp); - - delete_file(DATA_TEMPLATE, "grep.tmp"); return; } -void -do_monstr() +static boolean +get_gitinfo(char *githash, char *gitbranch) { - /* Don't break anything for ports that haven't been updated. */ - printf("DEPRECATION WARNINGS:\n"); - printf("'makedefs -m' is deprecated. Remove all references\n"); - printf(" to it from the build process.\n"); - printf("'monstr.c' is deprecated. Remove all references to\n"); - printf(" it from the build process.\n"); - printf("monstr[] is deprecated. Replace monstr[x] with\n"); - printf(" mons[x].difficulty\n"); - printf("monstr_init() is deprecated. Remove all references to it.\n"); + FILE *gifp; + size_t len; + char infile[MAXFNAMELEN]; + char *line, *strval, *opt, *c, *end; + boolean havebranch = FALSE, havehash = FALSE; - /* - * create the source file, "monstr.c" - */ - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C); - if (!(ofp = fopen(filename, WRTMODE))) { - perror(filename); - exit(EXIT_FAILURE); + if (!githash || !gitbranch) return FALSE; + + Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE); + if (!(gifp = fopen(infile, RDTMODE))) { + /* perror(infile); */ + return FALSE; } - Fprintf(ofp, "%s", Dont_Edit_Code); - Fprintf(ofp, "#include \"config.h\"\n"); - Fprintf(ofp, "\nconst int monstrXXX[] = {\n"); - Fprintf(ofp, "0};\n"); - Fprintf(ofp, "/*\n"); - Fprintf(ofp, "DEPRECATION WARNINGS:\n"); - Fprintf(ofp, "'makedefs -m' is deprecated. Remove all references\n"); - Fprintf(ofp, " to it from the build process.\n"); - Fprintf(ofp, "'monstr.c' is deprecated. Remove all references to\n"); - Fprintf(ofp, " it from the build process.\n"); - Fprintf(ofp, "monstr[] is deprecated. Replace monstr[x] with\n"); - Fprintf(ofp, " mons[x].difficulty\n"); - Fprintf(ofp, "monstr_init() is deprecated. Remove all references to it.\n"); - Fprintf(ofp, "*/\n"); - - Fprintf(ofp, "\nvoid NDECL(monstr_init);\n"); - Fprintf(ofp, "\nvoid\n"); - Fprintf(ofp, "monstr_init()\n"); - Fprintf(ofp, "{\n"); - Fprintf(ofp, " return;\n"); - Fprintf(ofp, "}\n"); - Fprintf(ofp, "\n/*monstr.c*/\n"); + set_fgetline_context(infile, TRUE, TRUE); - Fclose(ofp); - return; + /* read the gitinfo file */ + while ((line = fgetline(gifp)) != 0) { + strval = strchr(line, '='); + if (strval && strlen(strval) < (BUFSZ-1)) { + opt = line; + *strval++ = '\0'; + /* strip off the '\n' */ + if ((c = strchr(strval, '\n')) != 0) + *c = '\0'; + if ((c = strchr(opt, '\n')) != 0) + *c = '\0'; + /* strip leading and trailing white space */ + while (*strval == ' ' || *strval == '\t') + strval++; + end = eos(strval); + while (--end >= strval && (*end == ' ' || *end == '\t')) + *end = '\0'; + while (*opt == ' ' || *opt == '\t') + opt++; + end = eos(opt); + while (--end >= opt && (*end == ' ' || *end == '\t')) + *end = '\0'; + + len = strlen(opt); + if ((len >= strlen("gitbranch")) + && !case_insensitive_comp(opt, "gitbranch")) { + Strcpy(gitbranch, strval); + havebranch = TRUE; + } + if ((len >= strlen("githash")) + && !case_insensitive_comp(opt, "githash")) { + Strcpy(githash, strval); + havehash = TRUE; + } + } + free((genericptr_t) line); + } + Fclose(gifp); + if (havebranch && havehash) + return TRUE; + return FALSE; } void -do_permonst() +do_options(void) { - int i; - char *c, *nam; + const char *optline; + int infocontext = 0; + windowing_sanity(); filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif - Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE); + Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - exit(EXIT_FAILURE); - } - Fprintf(ofp, "%s", Dont_Edit_Code); - Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n"); - - if (use_enum) { - Fprintf(ofp, "\nenum monnums {"); -#if 0 - /* need #define ENUM_PM for the full NetHack build to include these */ - Fprintf(ofp, "\n NON_PM = -1,"); - Fprintf(ofp, "\n LOW_PM = 0,"); -#endif - } - for (i = 0; mons[i].mlet; i++) { - SpinCursor(3); - if (use_enum) - Fprintf(ofp, "\n PM_"); - else - Fprintf(ofp, "\n#define\tPM_"); - if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4)) - Fprintf(ofp, "HUMAN_"); - for (nam = c = tmpdup(mons[i].mname); *c; c++) - if (*c >= 'a' && *c <= 'z') - *c -= (char) ('a' - 'A'); - else if (*c < 'A' || *c > 'Z') - *c = '_'; - if (use_enum) - Fprintf(ofp, "%s = %d,", nam, i); - else - Fprintf(ofp, "%s\t%d", nam, i); - } - if (use_enum) { - Fprintf(ofp, "\n\n NUMMONS = %d", i); - Fprintf(ofp, "\n};\n"); - } else { - Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - Fprintf(ofp, "\n#endif /* PM_H */\n"); + while ((optline = do_runtime_info(&infocontext)) != 0) + Fprintf(ofp, "%s\n", optline); Fclose(ofp); return; } -/* Start of Quest text file processing. */ -#include "qtext.h" - -static struct qthdr qt_hdr; -static struct msghdr msg_hdr[N_HDR]; -static struct qtmsg *curr_msg; - -static int qt_line; - -static boolean in_msg; -#define NO_MSG 1 /* strlen of a null line returned by fgets() */ - -static boolean -qt_comment(s) -char *s; -{ - if (s[0] == '#') - return TRUE; - return (boolean) (!in_msg && strlen(s) == NO_MSG); -} - -static boolean -qt_control(s) -char *s; -{ - return (boolean) (s[0] == '%' && (s[1] == 'C' || s[1] == 'E')); -} - -static int -get_hdr(code) -char *code; -{ - int i; - - for (i = 0; i < qt_hdr.n_hdr; i++) - if (!strncmp(code, qt_hdr.id[i], LEN_HDR)) - return ++i; - - return 0; -} - -static boolean -new_id(code) -char *code; -{ - if (qt_hdr.n_hdr >= N_HDR) { - Fprintf(stderr, OUT_OF_HEADERS, qt_line); - return FALSE; - } - - strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR); - msg_hdr[qt_hdr.n_hdr].n_msg = 0; - qt_hdr.offset[qt_hdr.n_hdr++] = 0L; - return TRUE; -} - -static boolean -known_msg(num, id) -int num, id; -{ - int i; - - for (i = 0; i < msg_hdr[num].n_msg; i++) - if (msg_hdr[num].qt_msg[i].msgnum == id) - return TRUE; - - return FALSE; -} - static void -new_msg(s, num, id) -char *s; -int num, id; -{ - struct qtmsg *qt_msg; - - if (msg_hdr[num].n_msg >= N_MSG) { - Fprintf(stderr, OUT_OF_MESSAGES, qt_line); - } else { - qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]); - qt_msg->msgnum = id; - qt_msg->delivery = s[2]; - qt_msg->offset = qt_msg->size = qt_msg->summary_size = 0L; - - curr_msg = qt_msg; - } -} - -/* check %E record for "[summary text]" that nethack can stuff into the - message history buffer when delivering text via window instead of pline */ -static char * -valid_qt_summary(s, parsing) -char *s; /* end record: "%E" optionally followed by " [summary]" */ -boolean parsing; /* curr_msg is valid iff this is True */ +windowing_sanity(void) { - static char summary[BUFSZ]; - char *p; +#ifndef DEFAULT_WINDOW_SYS + /* pre-standard compilers didn't support #error; wait til run-time */ + Fprintf(stderr, + "Configuration error: DEFAULT_WINDOW_SYS is not defined.\n"); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ - if (*s != '%' || *(s + 1) != 'E') - return (char *) 0; - if ((p = index(s, '[')) == 0) - return (char *) 0; - /* note: opening '[' and closing ']' will be retained in the output; - anything after ']' will be discarded by putting a newline there */ - Strcpy(summary, p); +/* put in a dummy value so that do_options() will compile and makedefs + will build, otherwise the message above won't ever get delivered */ +#define DEFAULT_WINDOW_SYS "" +#else /*DEFAULT_WINDOW_SYS*/ - /* have an opening bracket; summary[] holds it and all text that follows - */ - p = eos(summary); - /* find closing bracket */ - while (p > summary && *(p - 1) != ']') - --p; - - if (p == summary) { - /* we backed up all the way to the start without finding a bracket */ - if (parsing) /* malformed summary */ - Fprintf(stderr, MAL_SUM, qt_line); - } else if (p == summary + 1) { - ; /* ignore empty [] */ - } else { /* got something */ - /* p points one spot past ']', usually to '\n'; - we need to include the \n as part of the size */ - if (parsing) { - /* during the writing pass we won't be able to recheck - delivery, so any useless summary for a pline mode - message has to be carried along to the output file */ - if (curr_msg->delivery == 'p') - Fprintf(stderr, DUMB_SUM, qt_line); - /* +1 is for terminating newline */ - curr_msg->summary_size = (long) (p - summary) + 1L; - } else { - /* caller is writing rather than just parsing; - force newline after the closing bracket */ - Strcpy(p, "\n"); - } - return summary; + if (!window_opts[0].id) { + Fprintf(stderr, "Configuration error: no windowing systems " + "(TTY_GRAPHICS, &c) enabled.\n"); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - return (char *) 0; -} - -static void -do_qt_control(s) -char *s; -{ - char code[BUFSZ]; - int num, id = 0; - if (!index(s, '\n')) - Fprintf(stderr, CTRL_TRUNC, qt_line); + { + int i; - switch (s[1]) { - case 'C': - if (in_msg) { - Fprintf(stderr, CREC_IN_MSG, qt_line); - break; - } else { - in_msg = TRUE; - if (sscanf(&s[4], "%s %5d", code, &id) != 2) { - Fprintf(stderr, UNREC_CREC, qt_line); - break; - } - num = get_hdr(code); - if (!num && !new_id(code)) + for (i = 0; window_opts[i].id; ++i) + if (!strcmp(window_opts[i].id, DEFAULT_WINDOW_SYS)) break; - num = get_hdr(code) - 1; - if (known_msg(num, id)) - Fprintf(stderr, DUP_MSG, qt_line); - else - new_msg(s, num, id); - } - break; - - case 'E': - if (!in_msg) { - Fprintf(stderr, END_NOT_IN_MSG, qt_line); - } else { - /* sets curr_msg->summary_size if applicable */ - (void) valid_qt_summary(s, TRUE); - in_msg = FALSE; + if (!window_opts[i].id) { /* went through whole list without a match */ + Fprintf(stderr, "Configuration error: DEFAULT_WINDOW_SYS (%s)\n", + DEFAULT_WINDOW_SYS); + Fprintf(stderr, + " does not match any enabled windowing system (%s%s).\n", + window_opts[0].id, window_opts[1].id ? ", &c" : ""); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - break; - - default: - Fprintf(stderr, UNREC_CREC, qt_line); - break; - } -} - -static void -do_qt_text(s) -char *s; -{ - if (!in_msg) { - Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line); - } else if (!index(s, '\n')) { - Fprintf(stderr, TEXT_TRUNC, qt_line); - } - - curr_msg->size += strlen(s); - return; -} - -static void -adjust_qt_hdrs() -{ - int i, j; - long count = 0L, hdr_offset = sizeof(int) - + (sizeof(char) * LEN_HDR + sizeof(long)) - * qt_hdr.n_hdr; - - for (i = 0; i < qt_hdr.n_hdr; i++) { - qt_hdr.offset[i] = hdr_offset; - hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg; } - - for (i = 0; i < qt_hdr.n_hdr; i++) - for (j = 0; j < msg_hdr[i].n_msg; j++) { - msg_hdr[i].qt_msg[j].offset = hdr_offset + count; - count += - msg_hdr[i].qt_msg[j].size + msg_hdr[i].qt_msg[j].summary_size; - } +#endif /*DEFAULT_WINDOW_SYS*/ return; } -static void -put_qt_hdrs() -{ - int i; - - /* - * The main header record. - */ - if (debug) - Fprintf(stderr, "%ld: header info.\n", ftell(ofp)); - (void) fwrite((genericptr_t) & (qt_hdr.n_hdr), sizeof(int), 1, ofp); - (void) fwrite((genericptr_t) & (qt_hdr.id[0][0]), sizeof(char) * LEN_HDR, - qt_hdr.n_hdr, ofp); - (void) fwrite((genericptr_t) & (qt_hdr.offset[0]), sizeof(long), - qt_hdr.n_hdr, ofp); - if (debug) { - for (i = 0; i < qt_hdr.n_hdr; i++) - Fprintf(stderr, "%s @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]); - Fprintf(stderr, "\n"); - } - - /* - * The individual class headers. - */ - for (i = 0; i < qt_hdr.n_hdr; i++) { - if (debug) - Fprintf(stderr, "%ld: %s header info.\n", ftell(ofp), - qt_hdr.id[i]); - (void) fwrite((genericptr_t) & (msg_hdr[i].n_msg), sizeof(int), 1, - ofp); - (void) fwrite((genericptr_t) & (msg_hdr[i].qt_msg[0]), - sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp); - if (debug) { - int j; - - for (j = 0; j < msg_hdr[i].n_msg; j++) { - Fprintf(stderr, "msg %d @ %ld (%ld)", - msg_hdr[i].qt_msg[j].msgnum, - msg_hdr[i].qt_msg[j].offset, - msg_hdr[i].qt_msg[j].size); - if (msg_hdr[i].qt_msg[j].summary_size) - Fprintf(stderr, " [%ld]", - msg_hdr[i].qt_msg[j].summary_size); - Fprintf(stderr, "\n"); - } - } - } -} +/* + * + New format (v3.1) of 'data' file which allows much faster lookups [pr] +"do not edit" first record is a comment line +01234567 hexadecimal formatted offset to text area +name-a first name of interest +123,4 offset to name's text, and number of lines for it +name-b next name of interest +name-c multiple names which share same description also +456,7 share a single offset,count line +. sentinel to mark end of names +789,0 dummy record containing offset, count of EOF +text-a 4 lines of descriptive text for name-a +text-a at file position 0x01234567L + 123L +text-a +text-a +text-b/text-c 7 lines of text for names-b and -c +text-b/text-c at fseek(0x01234567L + 456L) +... + * + */ void -do_questtxt() +do_dungeon(void) { - char *line; + char *line, greptmp[8 + 1 + 3 + 1]; - Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE); + Sprintf(greptmp, "grep-%.3s.tmp", "dun"); + Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - filename[0] = '\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif - Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE); - if (!(ofp = fopen(filename, WRBMODE))) { + Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE); + if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - Fclose(ifp); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } + Fprintf(ofp, "%s", Dont_Edit_Data); - qt_hdr.n_hdr = 0; - qt_line = 0; - in_msg = FALSE; - + tfp = getfp(DATA_TEMPLATE, greptmp, WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, greptmp, RDTMODE, 0); +#endif + set_fgetline_context(NULL, FALSE, TRUE); while ((line = fgetline(ifp)) != 0) { SpinCursor(3); - qt_line++; - if (qt_control(line)) - do_qt_control(line); - else if (qt_comment(line)) { - free(line); - continue; - } else - do_qt_text(line); - free(line); - } - - (void) rewind(ifp); - in_msg = FALSE; - adjust_qt_hdrs(); - put_qt_hdrs(); - while ((line = fgetline(ifp)) != 0) { - if (qt_control(line)) { - char *summary_p = 0; - - in_msg = (line[1] == 'C'); - if (!in_msg) - summary_p = valid_qt_summary(line, FALSE); - /* don't write anything unless we've got a summary */ - if (!summary_p) { - free(line); - continue; - } - /* we have summary text; replace raw %E record with it */ - Strcpy(line, summary_p); /* (guaranteed to fit) */ - } else if (qt_comment(line)) { - free(line); - continue; + if (line[0] == '#') { + free((genericptr_t) line); + continue; /* discard comments */ } - if (debug) - Fprintf(stderr, "%ld: %s", ftell(stdout), line); - (void) fputs(xcrypt(line), ofp); - free(line); + (void) fputs(line, ofp); + free((genericptr_t) line); } Fclose(ifp); Fclose(ofp); + +#ifdef HAS_NO_MKSTEMP + delete_file(DATA_TEMPLATE, greptmp); +#endif + return; +} + +/* obsolete */ +void +do_permonst(void) +{ + int i; + char *c, *nam; + + filename[0] = '\0'; +#ifdef FILE_PREFIX + Strcat(filename, file_prefix); +#endif + Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE); + if (!(ofp = fopen(filename, WRTMODE))) { + perror(filename); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ + } + Fprintf(ofp, "%s", Reference_file); + Fprintf(ofp, "#ifndef PM_H\n#define PM_H\n"); + + if (use_enum) { + Fprintf(ofp, "\nenum monnums {"); +#if 0 + /* need #define ENUM_PM for the full NetHack build to include these */ + Fprintf(ofp, "\n NON_PM = -1,"); + Fprintf(ofp, "\n LOW_PM = 0,"); +#endif + } + for (i = 0; mons[i].mlet; i++) { + SpinCursor(3); + if (use_enum) + Fprintf(ofp, "\n PM_"); + else + Fprintf(ofp, "\n#define\tPM_"); + if (mons[i].mlet == S_HUMAN + && !strncmp(mons[i].pmnames[NEUTRAL], "were", 4)) + Fprintf(ofp, "HUMAN_"); + for (nam = c = tmpdup(mons[i].pmnames[NEUTRAL]); *c; c++) + if (*c >= 'a' && *c <= 'z') + *c -= (char) ('a' - 'A'); + else if (*c < 'A' || *c > 'Z') + *c = '_'; + if (use_enum) + Fprintf(ofp, "%s = %d,", nam, i); + else + Fprintf(ofp, "%s\t%d", nam, i); + } + if (use_enum) { + Fprintf(ofp, "\n\n NUMMONS = %d", i); + Fprintf(ofp, "\n};\n"); + } else { + Fprintf(ofp, "\n\n#define\tNUMMONS\t%d\n", i); + } + Fprintf(ofp, "\n#endif /* PM_H */\n"); + Fclose(ofp); return; } -static char temp[32]; +/* Start of Quest text file processing. */ + +void +do_questtxt(void) +{ + printf("DEPRECATION WARNINGS:\n"); + printf("'makedefs -q' is no longer required. Remove all references\n"); + printf(" to it from the build process.\n"); + printf("'dat/quest.txt' is no longer part of the source tree.\n"); + + return; +} -static char *limit(name, pref) /* limit a name to 30 characters length */ -char *name; -int pref; +/* limit a name to 30 characters (26 if "xyz_" prefix precedes it) */ +static char * +macronamelimit(char *name, int pref) { - (void) strncpy(temp, name, pref ? 26 : 30); - temp[pref ? 26 : 30] = 0; - return temp; + static char macronametemp[32]; + unsigned len = pref ? 26 : 30; + +#if 0 /* avoid potential warning about strncpy() not guaranteeing '\0' */ + (void) strncpy(macronametemp, name, len); + macronametemp[len] = '\0'; +#else /* strncat() does guarantee terminating '\0' */ + macronametemp[0] = '\0'; + (void) strncat(macronametemp, name, len); +#endif + return macronametemp; } +/* obsolete */ void -do_objs() +do_objs(void) { - int i, sum = 0; + int i /*, sum = 0 */; char *c, *objnam; int nspell = 0; int prefix = 0; char class = '\0'; boolean sumerr = FALSE; + int n_glass_gems = 0; + int start_glass_gems = 0; filename[0] = '\0'; #ifdef FILE_PREFIX @@ -2796,27 +2211,31 @@ do_objs() Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); - exit(EXIT_FAILURE); + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - Fprintf(ofp, "%s", Dont_Edit_Code); + Fprintf(ofp, "%s", Reference_file); Fprintf(ofp, "#ifndef ONAMES_H\n#define ONAMES_H\n\n"); for (i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) { SpinCursor(3); - objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */ + objects[i].oc_name_idx = objects[i].oc_descr_idx = (short) i; if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue; - /* make sure probabilities add up to 1000 */ + /* done with current class? */ if (objects[i].oc_class != class) { +#if 0 /* [class total oc_prob of 1000 is no longer enforced] */ + /* make sure probabilities add up to 1000 */ if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } +#endif /*0*/ class = objects[i].oc_class; - sum = 0; + /* sum = 0; */ } for (c = objnam; *c; c++) @@ -2861,26 +2280,53 @@ do_objs() if (objects[i].oc_material == GLASS) { Fprintf(ofp, "/* #define\t%s\t%d */\n", objnam, i); prefix = -1; + if (!n_glass_gems) + start_glass_gems = i; + if (i != n_glass_gems + start_glass_gems) { + Fprintf(stderr, "glass gems not sequential\n"); + (void) fflush(stderr); + sumerr = TRUE; + } + n_glass_gems++; break; } + FALLTHROUGH; + /*FALLTHRU*/ + case VENOM_CLASS: + /* fall-through from gem class is ok; objects[] used to have + { "{acid,blinding} venom", "splash of venom" } + but those have been changed to + { "splash of {acid,blinding} venom", "splash of venom" } + so strip the extra "splash of " off to keep same macros */ + if (!strncmp(objnam, "SPLASH_OF_", 10)) + objnam += 10; + FALLTHROUGH; /*FALLTHRU*/ default: Fprintf(ofp, "#define\t"); + break; } if (prefix >= 0) - Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i); + Fprintf(ofp, "%s\t%d\n", macronamelimit(objnam, prefix), i); prefix = 0; - sum += objects[i].oc_prob; + /* sum += objects[i].oc_prob; */ + + if (sumerr) + break; } +#if 0 /* [class total oc_prob of 1000 is no longer enforced] */ /* check last set of probabilities */ - if (sum && sum != 1000) { + if (!sumerr && sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } +#endif /*0*/ + Fprintf(ofp, "\n"); + Fprintf(ofp, "#define\tNUM_GLASS_GEMS\t%d\n", n_glass_gems); Fprintf(ofp, "#define\tLAST_GEM\t(JADE)\n"); Fprintf(ofp, "#define\tMAXSPELL\t%d\n", nspell + 1); Fprintf(ofp, "#define\tNUM_OBJECTS\t%d\n", i); @@ -2901,48 +2347,21 @@ do_objs() /* fudge _platinum_ YENDORIAN EXPRESS CARD */ if (!strncmp(objnam, "PLATINUM_", 9)) objnam += 9; - Fprintf(ofp, "#define\tART_%s\t%d\n", limit(objnam, 1), i); + Fprintf(ofp, "#define\tART_%s\t%d\n", macronamelimit(objnam, 1), i); } Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i - 1); Fprintf(ofp, "\n#endif /* ONAMES_H */\n"); Fclose(ofp); - if (sumerr) - exit(EXIT_FAILURE); - return; -} - -/* Read one line from input, up to and including the next newline - * character. Returns a pointer to the heap-allocated string, or a - * null pointer if no characters were read. - */ -static char * -fgetline(fd) -FILE *fd; -{ - static const int inc = 256; - int len = inc; - char *c = malloc(len), *ret; - - for (;;) { - ret = fgets(c + len - inc, inc, fd); - if (!ret) { - free(c); - c = NULL; - break; - } else if (index(c, '\n')) { - /* normal case: we have a full line */ - break; - } - len += inc; - c = realloc(c, len); + if (sumerr) { + makedefs_exit(EXIT_FAILURE); + /*NOTREACHED*/ } - return c; + return; } static char * -tmpdup(str) -const char *str; +tmpdup(const char *str) { static char buf[128]; @@ -2951,400 +2370,9 @@ const char *str; (void) strncpy(buf, str, 127); return buf; } +#endif /* OLD_MAKEDEFS_OPTIONS */ -static char * -eos(str) -char *str; -{ - while (*str) - str++; - return str; -} - -/* - * macro used to control vision algorithms: - * VISION_TABLES => generate tables - */ - -void -do_vision() -{ -#ifdef VISION_TABLES - int i, j; - - /* Everything is clear. xclear may be malloc'ed. - * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH) - */ - for (i = 0; i < MAX_ROW; i++) - for (j = 0; j < MAX_COL; j++) - if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH) - xclear[i][j] = '\000'; - else - xclear[i][j] = '\001'; -#endif /* VISION_TABLES */ - - SpinCursor(3); - - /* - * create the include file, "vis_tab.h" - */ - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H); - if (!(ofp = fopen(filename, WRTMODE))) { - perror(filename); - exit(EXIT_FAILURE); - } - Fprintf(ofp, "%s", Dont_Edit_Code); - Fprintf(ofp, "#ifdef VISION_TABLES\n"); -#ifdef VISION_TABLES - H_close_gen(); - H_far_gen(); -#endif /* VISION_TABLES */ - Fprintf(ofp, "\n#endif /* VISION_TABLES */\n"); - Fclose(ofp); - - SpinCursor(3); - - /* - * create the source file, "vis_tab.c" - */ - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), SOURCE_TEMPLATE, VIS_TAB_C); - if (!(ofp = fopen(filename, WRTMODE))) { - perror(filename); - /* creating vis_tab.c failed; remove the vis_tab.h we just made */ - filename[0] = '\0'; -#ifdef FILE_PREFIX - Strcat(filename, file_prefix); -#endif - Sprintf(eos(filename), INCLUDE_TEMPLATE, VIS_TAB_H); - Unlink(filename); - exit(EXIT_FAILURE); - } - Fprintf(ofp, "%s", Dont_Edit_Code); - Fprintf(ofp, "#include \"config.h\"\n"); - Fprintf(ofp, "#ifdef VISION_TABLES\n"); - Fprintf(ofp, "#include \"vis_tab.h\"\n"); - - SpinCursor(3); - -#ifdef VISION_TABLES - C_close_gen(); - C_far_gen(); - Fprintf(ofp, "\nvoid vis_tab_init() { return; }\n"); -#endif /* VISION_TABLES */ - - SpinCursor(3); - - Fprintf(ofp, "\n#endif /* VISION_TABLES */\n"); - Fprintf(ofp, "\n/*vis_tab.c*/\n"); - - Fclose(ofp); - return; -} - -#ifdef VISION_TABLES - -/*-------------- vision tables --------------*\ - * - * Generate the close and far tables. This is done by setting up a - * fake dungeon and moving our source to different positions relative - * to a block and finding the first/last visible position. The fake - * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT - * by BLOCK_WIDTH) is blocked. Then we move the source around relative - * to the corner of the block. For each new position of the source - * we check positions on rows "kittycorner" from the source. We check - * positions until they are either in sight or out of sight (depends on - * which table we are generating). The picture below shows the setup - * for the generation of the close table. The generation of the far - * table would switch the quadrants of the '@' and the "Check rows - * here". - * - * - * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,, - * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - * ............................... - * ............................... - * .........@..................... - * ............................... - * - * Table generation figure (close_table). The 'X's are blocked points. - * The 'B' is a special blocked point. The '@' is the source. The ','s - * are the target area. The '.' are just open areas. - * - * - * Example usage of close_table[][][]. - * - * The table is as follows: - * - * dy = |row of '@' - row of 'B'| - 1 - * dx = |col of '@' - col of 'B'| - * - * The first indices are the deltas from the source '@' and the block 'B'. - * You must check for the value inside the abs value bars being zero. If - * so then the block is on the same row and you don't need to do a table - * lookup. The last value: - * - * dcy = |row of block - row to be checked| - * - * Is the value of the first visible spot on the check row from the - * block column. So - * - * first visible col = close_table[dy][dx][dcy] + col of 'B' - * -\*-------------- vision tables --------------*/ - -static void -H_close_gen() -{ - Fprintf(ofp, "\n/* Close */\n"); - Fprintf(ofp, - "#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n", - TEST_HEIGHT - 1); - Fprintf(ofp, - "#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n", - TEST_WIDTH); - Fprintf(ofp, - "#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n", - TEST_HEIGHT); - Fprintf(ofp, "typedef struct {\n"); - Fprintf(ofp, - " unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n"); - Fprintf(ofp, "} close2d;\n"); - Fprintf(ofp, "extern close2d close_table[CLOSE_MAX_SB_DY];\n"); - return; -} - -static void -H_far_gen() -{ - Fprintf(ofp, "\n/* Far */\n"); - Fprintf(ofp, "#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n", - TEST_HEIGHT); - Fprintf(ofp, - "#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n", - TEST_WIDTH - 1); - Fprintf(ofp, - "#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n", - TEST_HEIGHT - 1); - Fprintf(ofp, "typedef struct {\n"); - Fprintf(ofp, " unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n"); - Fprintf(ofp, "} far2d;\n"); - Fprintf(ofp, "extern far2d far_table[FAR_MAX_SB_DY];\n"); - return; -} - -static void -C_close_gen() -{ - int i, dx, dy; - int src_row, src_col; /* source */ - int block_row, block_col; /* block */ - int this_row; - int no_more; - const char *delim; - - block_row = BLOCK_HEIGHT - 1; - block_col = BLOCK_WIDTH - 1; - - Fprintf(ofp, "\n#ifndef FAR_TABLE_ONLY\n"); - Fprintf(ofp, "\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n"); -#ifndef no_vision_progress - Fprintf(stderr, "\nclose:"); -#endif - - for (dy = 1; dy < TEST_HEIGHT; dy++) { - src_row = block_row + dy; - Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy); -#ifndef no_vision_progress - Fprintf(stderr, " %2d", dy), (void) fflush(stderr); -#endif - for (dx = 0; dx < TEST_WIDTH; dx++) { - src_col = block_col - dx; - Fprintf(ofp, " /*%2d*/ {", dx); - - no_more = 0; - for (this_row = 0; this_row < TEST_HEIGHT; this_row++) { - delim = (this_row < TEST_HEIGHT - 1) ? "," : ""; - if (no_more) { - Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim); - continue; - } - SpinCursor(3); - - /* Find the first column that we can see. */ - for (i = block_col + 1; i < MAX_COL; i++) { - if (clear_path(src_row, src_col, block_row - this_row, i)) - break; - } - - if (i == MAX_COL) - no_more = 1; - Fprintf(ofp, "%2d%s", i - block_col, delim); - } - Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); - } - Fprintf(ofp, " }},\n"); - } - - Fprintf(ofp, "}; /* close_table[] */\n"); /* closing brace for table */ - Fprintf(ofp, "#endif /* !FAR_TABLE_ONLY */\n"); -#ifndef no_vision_progress - Fprintf(stderr, "\n"); -#endif - return; -} - -static void -C_far_gen() -{ - int i, dx, dy; - int src_row, src_col; /* source */ - int block_row, block_col; /* block */ - int this_row; - const char *delim; - - block_row = BLOCK_HEIGHT - 1; - block_col = BLOCK_WIDTH - 1; - - Fprintf(ofp, "\n#ifndef CLOSE_TABLE_ONLY\n"); - Fprintf(ofp, "\nfar2d far_table[FAR_MAX_SB_DY] = {\n"); -#ifndef no_vision_progress - Fprintf(stderr, "\n_far_:"); -#endif - - for (dy = 0; dy < TEST_HEIGHT; dy++) { - src_row = block_row - dy; - Fprintf(ofp, "/* DY = %2d */\n {{\n", dy); -#ifndef no_vision_progress - Fprintf(stderr, " %2d", dy), (void) fflush(stderr); -#endif - for (dx = 1; dx < TEST_WIDTH; dx++) { - src_col = block_col + dx; - Fprintf(ofp, " /*%2d(-1)*/ {", dx); - - for (this_row = block_row + 1; this_row < block_row + TEST_HEIGHT; - this_row++) { - delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : ""; - - SpinCursor(3); - /* Find first col that we can see. */ - for (i = 0; i <= block_col; i++) { - if (clear_path(src_row, src_col, this_row, i)) - break; - } - - if (block_col - i < 0) - Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim); - else - Fprintf(ofp, "%2d%s", block_col - i, delim); - } - Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); - } - Fprintf(ofp, " }},\n"); - } - - Fprintf(ofp, "}; /* far_table[] */\n"); /* closing brace for table */ - Fprintf(ofp, "#endif /* !CLOSE_TABLE_ONLY */\n"); -#ifndef no_vision_progress - Fprintf(stderr, "\n"); -#endif - return; -} - -/* - * "Draw" a line from the hero to the given location. Stop if we hit a - * wall. - * - * Generalized integer Bresenham's algorithm (fast line drawing) for - * all quadrants. From _Procedural Elements for Computer Graphics_, by - * David F. Rogers. McGraw-Hill, 1985. - * - * I have tried a little bit of optimization by pulling compares out of - * the inner loops. - * - * NOTE: This had better *not* be called from a position on the - * same row as the hero. - */ -static int -clear_path(you_row, you_col, y2, x2) -int you_row, you_col, y2, x2; -{ - int dx, dy, s1, s2; - register int i, error, x, y, dxs, dys; - - x = you_col; - y = you_row; - dx = abs(x2 - you_col); - dy = abs(y2 - you_row); - s1 = sign(x2 - you_col); - s2 = sign(y2 - you_row); - - if (s1 == 0) { /* same column */ - if (s2 == 1) { /* below (larger y2 value) */ - for (i = you_row + 1; i < y2; i++) - if (!xclear[i][you_col]) - return 0; - } else { /* above (smaller y2 value) */ - for (i = y2 + 1; i < you_row; i++) - if (!xclear[i][you_col]) - return 0; - } - return 1; - } - - /* - * Lines at 0 and 90 degrees have been weeded out. - */ - if (dy > dx) { - error = dx; - dx = dy; - dy = error; /* swap the values */ - dxs = dx << 1; /* save the shifted values */ - dys = dy << 1; - error = dys - dx; /* NOTE: error is used as a temporary above */ - - for (i = 0; i < dx; i++) { - if (!xclear[y][x]) - return 0; /* plot point */ - - while (error >= 0) { - x += s1; - error -= dxs; - } - y += s2; - error += dys; - } - } else { - dxs = dx << 1; /* save the shifted values */ - dys = dy << 1; - error = dys - dx; - - for (i = 0; i < dx; i++) { - if (!xclear[y][x]) - return 0; /* plot point */ - - while (error >= 0) { - y += s2; - error -= dxs; - } - x += s1; - error += dys; - } - } - return 1; -} -#endif /* VISION_TABLES */ - +/* the STRICT_REF_DEF checking is way out of date... */ #ifdef STRICT_REF_DEF NEARDATA struct flag flags; #ifdef ATTRIB_H