1 /*	SCCS Id: @(#)lev_main.c	3.4	2002/03/27	*/
2 /*	Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /*
6  * This file contains the main function for the parser
7  * and some useful functions needed by yacc
8  */
9 #define SPEC_LEV	/* for MPW */
10 /* although, why don't we move those special defines here.. and in dgn_main? */
11 
12 #include <stdarg.h>
13 
14 #include "hack.h"
15 #include "date.h"
16 #include "sp_lev.h"
17 #ifdef STRICT_REF_DEF
18 #include "tcap.h"
19 #endif
20 
21 #ifdef MAC
22 # if defined(__SC__) || defined(__MRC__)
23 #  define MPWTOOL
24 #  define PREFIX ":dungeon:"	/* place output files here */
25 #  include <CursorCtl.h>
26 # else
27 #  if !defined(__MACH__)
28 #   define PREFIX ":lib:"	/* place output files here */
29 #  endif
30 # endif
31 #endif
32 
33 #ifdef WIN_CE
34 #define PREFIX "\\nethack\\dat\\"
35 #endif
36 
37 #ifndef MPWTOOL
38 # define SpinCursor(x)
39 #endif
40 
41 #if defined(AMIGA) && defined(DLB)
42 # define PREFIX "NH:slib/"
43 #endif
44 
45 #ifndef O_WRONLY
46 #include <fcntl.h>
47 #endif
48 #ifndef O_CREAT	/* some older BSD systems do not define O_CREAT in <fcntl.h> */
49 #include <sys/file.h>
50 #endif
51 #ifndef O_BINARY	/* used for micros, no-op for others */
52 # define O_BINARY 0
53 #endif
54 
55 #if defined(MICRO) || defined(WIN32)
56 # define OMASK FCMASK
57 #else
58 # define OMASK 0644
59 #endif
60 
61 #define ERR		(-1)
62 
63 #define NewTab(type, size)	(type **) alloc(sizeof(type *) * size)
64 #define Free(ptr)		if(ptr) free((genericptr_t) (ptr))
65 #define Write(fd, item, size)	if (write(fd, (genericptr_t)(item), size) != size) return FALSE;
66 
67 #if defined(__BORLANDC__) && !defined(_WIN32)
68 extern unsigned _stklen = STKSIZ;
69 #endif
70 #define MAX_ERRORS	25
71 
72 extern int  NDECL (yyparse);
73 extern void FDECL (init_yyin, (FILE *));
74 extern void FDECL (init_yyout, (FILE *));
75 
76 int  FDECL (main, (int, char **));
77 void FDECL (yyerror, (const char *));
78 void FDECL (yywarning, (const char *));
79 int  NDECL (yywrap);
80 int FDECL(get_floor_type, (CHAR_P));
81 int FDECL(get_room_type, (char *));
82 int FDECL(get_trap_type, (char *));
83 int FDECL(get_monster_id, (char *,CHAR_P));
84 int FDECL(get_object_id, (char *,CHAR_P));
85 boolean FDECL(check_monster_char, (CHAR_P));
86 boolean FDECL(check_object_char, (CHAR_P));
87 char FDECL(what_map_char, (CHAR_P));
88 void FDECL(scan_map, (char *, sp_lev *));
89 boolean FDECL(check_subrooms, (sp_lev *));
90 boolean FDECL(write_level_file, (char *,sp_lev *));
91 
92 struct lc_funcdefs *FDECL(funcdef_new,(long,char *));
93 void FDECL(funcdef_free_all,(struct lc_funcdefs *));
94 struct lc_funcdefs *FDECL(funcdef_defined,(struct lc_funcdefs *,char *, int));
95 
96 struct lc_vardefs *FDECL(vardef_new,(long,char *));
97 void FDECL(vardef_free_all,(struct lc_vardefs *));
98 struct lc_vardefs *FDECL(vardef_defined,(struct lc_vardefs *,char *, int));
99 
100 void FDECL(splev_add_from, (sp_lev *, sp_lev *));
101 
102 extern void NDECL(monst_init);
103 extern void NDECL(objects_init);
104 extern void NDECL(decl_init);
105 
106 void FDECL(add_opcode, (sp_lev *, int, genericptr_t));
107 
108 static boolean FDECL(write_common_data, (int,sp_lev *));
109 static boolean FDECL(write_maze, (int,sp_lev *));
110 static void NDECL(init_obj_classes);
111 
112 void VDECL(lc_error, (const char *, ...));
113 void VDECL(add_opvars, (sp_lev *, const char *, ...));
114 
115 static const struct {
116     long functype;
117     long objtyp;
118     const char *methodname;
119     long retval;
120 } core_methods[] = {
121     {COREFUNC_COORD_X, SPOVAR_COORD, "x", SPOVAR_INT}, /* $coord.x */
122     {COREFUNC_COORD_Y, SPOVAR_COORD, "y", SPOVAR_INT}, /* $coord.y */
123     {COREFUNC_ARRAY_LEN, SPOVAR_INT|SPOVAR_ARRAY, "length", SPOVAR_INT},
124     {COREFUNC_ARRAY_LEN, SPOVAR_STRING|SPOVAR_ARRAY, "length", SPOVAR_INT},
125     {COREFUNC_ARRAY_LEN, SPOVAR_COORD|SPOVAR_ARRAY, "length", SPOVAR_INT},
126     {COREFUNC_ARRAY_LEN, SPOVAR_REGION|SPOVAR_ARRAY, "length", SPOVAR_INT},
127     {COREFUNC_ARRAY_LEN, SPOVAR_MAPCHAR|SPOVAR_ARRAY, "length", SPOVAR_INT},
128     {COREFUNC_ARRAY_LEN, SPOVAR_MONST|SPOVAR_ARRAY, "length", SPOVAR_INT},
129     {COREFUNC_ARRAY_LEN, SPOVAR_OBJ|SPOVAR_ARRAY, "length", SPOVAR_INT},
130     {COREFUNC_ARRAY_LEN, SPOVAR_SEL|SPOVAR_ARRAY, "length", SPOVAR_INT},
131     {0, 0, NULL, 0}
132 };
133 
134 long
method_defined(char * methname,long o,long * ftyp)135 method_defined(char *methname, long o, long *ftyp)
136 {
137     int i;
138     for (i = 0; core_methods[i].methodname; i++)
139 	if (core_methods[i].objtyp == o && !strcmp(core_methods[i].methodname, methname)) {
140 	    *ftyp = core_methods[i].functype;
141 	    return core_methods[i].retval;
142 	}
143     return 0;
144 }
145 
146 
147 static const struct {
148     int functype;
149     const char *name;
150     const char *params;
151     char retval;
152 } core_vars[] = {
153     {COREFUNC_DISCORDIAN_HOLIDAY,	"time.discordian_holiday", "", 'i'},
154     {COREFUNC_PIRATEDAY,		"time.pirateday", "", 'i'},
155     {COREFUNC_APRILFOOLSDAY,		"time.aprilfoolsday", "", 'i'},
156     {COREFUNC_PIDAY,			"time.piday", "", 'i'},
157     {COREFUNC_TOWELDAY,			"time.towelday", "", 'i'},
158     {COREFUNC_MIDNIGHT,			"time.midnight", "", 'i'},
159     {COREFUNC_NIGHT,			"time.night", "", 'i'},
160     {COREFUNC_FRIDAY_13TH,		"time.friday_13th", "", 'i'},
161     {COREFUNC_POM,			"time.phase_of_the_moon", "", 'i'},
162     {COREFUNC_YYYYMMDD,			"time.yyyymmdd", "", 'i'},
163     {COREFUNC_LEVEL_DIFFICULTY,		"level.difficulty", "", 'i'},
164     {COREFUNC_LEVEL_DEPTH,		"level.depth", "", 'i'},
165     {COREFUNC_SOBJ_AT,			"level.obj_at", "Oc", 'i'},
166     {COREFUNC_MON_AT,			"level.mon_at", "Mc", 'i'},
167     {COREFUNC_PLNAME,			"hero.name", "", 's'},
168     {COREFUNC_ROLE,			"hero.role", "", 's'},
169     {COREFUNC_RACE,			"hero.race", "", 's'},
170     {COREFUNC_CARRYING,			"hero.carrying", "O", 'i'},
171     {COREFUNC_TOSTRING,			"string", "i", 's'},
172     {COREFUNC_TOSTRING,			"str", "i", 's'},
173     {COREFUNC_TOINT,			"integer", "s", 'i'},
174     {COREFUNC_TOINT,			"int", "s", 'i'},
175     {COREFUNC_TOCOORD,			"coord", "ii", 'c'},
176     {COREFUNC_TOREGION,			"region", "iiii", 'r'},
177     {COREFUNC_RN2,			"rnd", "i", 'i'},
178     {COREFUNC_ROOM_WID, 		"room.width", "", 'i'},
179     {COREFUNC_ROOM_HEI, 		"room.height", "", 'i'},
180     {COREFUNC_ROOM_X,			"room.x", "", 'i'},
181     {COREFUNC_ROOM_Y,			"room.y", "", 'i'},
182     {0, NULL, NULL, 0}
183 };
184 
185 static struct {
186 	const char *name;
187 	int type;
188 } trap_types[] = {
189 	{ "arrow",	ARROW_TRAP },
190 	{ "dart",	DART_TRAP },
191 	{ "falling rock", ROCKTRAP },
192 	{ "board",	SQKY_BOARD },
193 	{ "bear",	BEAR_TRAP },
194 	{ "land mine",	LANDMINE },
195 	{ "rolling boulder",	ROLLING_BOULDER_TRAP },
196 	{ "sleep gas",	SLP_GAS_TRAP },
197 	{ "rust",	RUST_TRAP },
198 	{ "fire",	FIRE_TRAP },
199 	{ "pit",	PIT },
200 	{ "spiked pit",	SPIKED_PIT },
201 	{ "hole",	HOLE },
202 	{ "trap door",	TRAPDOOR },
203 	{ "teleport",	TELEP_TRAP },
204 	{ "level teleport", LEVEL_TELEP },
205 	{ "magic portal",   MAGIC_PORTAL },
206 	{ "web",	WEB },
207 	{ "statue",	STATUE_TRAP },
208 	{ "magic",	MAGIC_TRAP },
209 	{ "anti magic",	ANTI_MAGIC },
210 	{ "polymorph",	POLY_TRAP },
211 	{ "cold", ICE_TRAP},
212 	{ 0, 0 }
213 };
214 
215 static struct {
216 	const char *name;
217 	int type;
218 } room_types[] = {
219 	/* for historical reasons, room types are not contiguous numbers */
220 	/* (type 1 is skipped) */
221 	{ "ordinary",	 OROOM },
222 	{ "rndvault",	 RNDVAULT },
223 	{ "throne",	 COURT },
224 	{ "swamp",	 SWAMP },
225 	{ "vault",	 VAULT },
226 	{ "beehive",	 BEEHIVE },
227 	{ "morgue",	 MORGUE },
228 	{ "barracks",	 BARRACKS },
229 	{ "zoo",	 ZOO },
230 	{ "delphi",	 DELPHI },
231 	{ "temple",	 TEMPLE },
232 	{ "lemurepit",   LEMUREPIT },
233 	{ "anthole",	 ANTHOLE },
234 	{ "cocknest",	 COCKNEST },
235 	{ "garden",	 GARDEN },
236 	{ "leprehall",	 LEPREHALL },
237 	{ "shop",	 SHOPBASE },
238 	{ "armor shop",	 ARMORSHOP },
239 	{ "scroll shop", SCROLLSHOP },
240 	{ "potion shop", POTIONSHOP },
241 	{ "weapon shop", WEAPONSHOP },
242 	{ "food shop",	 FOODSHOP },
243 	{ "ring shop",	 RINGSHOP },
244 	{ "wand shop",	 WANDSHOP },
245 	{ "tool shop",	 TOOLSHOP },
246 	{ "book shop",	 BOOKSHOP },
247 	{ "tin shop",	 TINSHOP },
248 	{ "music shop",	 INSTRUMENTSHOP },
249 	{ "candle shop", CANDLESHOP },
250 	{ "pet shop",	 PETSHOP },	/* Stephen White */
251 #ifdef BLACKMARKET
252 	{ "black market", BLACKSHOP },
253 	{ "black market foyer", BLACKFOYER },
254 #endif /* BLACKMARKET */
255 	{ 0, 0 }
256 };
257 
258 const char *fname = "(stdin)";
259 int fatal_error = 0;
260 int got_errors = 0;
261 int be_verbose = 0;
262 int decompile = 0;
263 int is_rnd_vault = 0;
264 int rnd_vault_freq = 1;
265 int fname_counter = 1;
266 
267 #ifdef FLEX23_BUG
268 /* Flex 2.3 bug work around; not needed for 2.3.6 or later */
269 int yy_more_len = 0;
270 #endif
271 
272 extern unsigned int max_x_map, max_y_map;
273 
274 extern int line_number, colon_line_number;
275 extern int token_start_pos;
276 extern char curr_token[512];
277 
278 struct lc_vardefs *variable_definitions = NULL;
279 struct lc_funcdefs *function_definitions = NULL;
280 
281 extern int allow_break_statements;
282 extern struct lc_breakdef *break_list;
283 
284 int
main(argc,argv)285 main(argc, argv)
286 int argc;
287 char **argv;
288 {
289 	FILE *fin;
290 	int i;
291 	boolean errors_encountered = FALSE;
292 #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
293 	static char *mac_argv[] = {	"lev_comp",	/* dummy argv[0] */
294 				":dat:Arch.des",
295 				":dat:Barb.des",
296 				":dat:Caveman.des",
297 				":dat:Healer.des",
298 				":dat:Knight.des",
299 				":dat:Monk.des",
300 				":dat:Priest.des",
301 				":dat:Ranger.des",
302 				":dat:Rogue.des",
303 				":dat:Samurai.des",
304 				":dat:Tourist.des",
305 				":dat:Valkyrie.des",
306 				":dat:Wizard.des",
307 				":dat:bigroom.des",
308 				":dat:castle.des",
309 				":dat:endgame.des",
310 				":dat:gehennom.des",
311 				":dat:knox.des",
312 				":dat:medusa.des",
313 				":dat:mines.des",
314 				":dat:oracle.des",
315 				":dat:sheol.des",
316 				":dat:sokoban.des",
317 				":dat:tower.des",
318 				":dat:yendor.des"
319 				};
320 
321 	argc = SIZE(mac_argv);
322 	argv = mac_argv;
323 #endif
324 	/* Note:  these initializers don't do anything except guarantee that
325 		we're linked properly.
326 	*/
327 	monst_init();
328 	objects_init();
329 	decl_init();
330 	/* this one does something... */
331 	init_obj_classes();
332 
333 	init_yyout(stdout);
334 	if (argc == 1) {		/* Read standard input */
335 	    init_yyin(stdin);
336 	    (void) yyparse();
337 	    if (fatal_error > 0 || got_errors > 0) {
338 		    errors_encountered = TRUE;
339 	    }
340 	} else {			/* Otherwise every argument is a filename */
341 	    for(i=1; i<argc; i++) {
342 		    fname = argv[i];
343 		    if(!strcmp(fname, "-v")) {
344 			be_verbose++;
345 			continue;
346 		    }
347 		    if(!strcmp(fname, "-d")) {
348 			decompile = 1;
349 			continue;
350 		    }
351 		    fin = freopen(fname, "r", stdin);
352 		    if (!fin) {
353 			(void) fprintf(stderr,"Can't open \"%s\" for input.\n",
354 						fname);
355 			perror(fname);
356 			errors_encountered = TRUE;
357 		    } else {
358 			fname_counter = 1;
359 			init_yyin(fin);
360 			(void) yyparse();
361 			line_number = 1;
362 			if (fatal_error > 0 || got_errors > 0) {
363 				errors_encountered = TRUE;
364 				fatal_error = 0;
365 			}
366 		    }
367 		    (void) fclose(fin);
368 		    funcdef_free_all(function_definitions);
369 	    }
370 	}
371 	exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
372 	/*NOTREACHED*/
373 	return 0;
374 }
375 
376 /*
377  * Each time the parser detects an error, it uses this function.
378  * Here we take count of the errors. To continue farther than
379  * MAX_ERRORS wouldn't be reasonable.
380  */
381 void
yyerror(s)382 yyerror(s)
383 const char *s;
384 {
385 	char *e = ((char *)s + strlen(s) - 1);
386 	(void) fprintf(stderr, "%s: line %d, pos %d : %s",
387 		       fname, line_number,
388 		       token_start_pos-strlen(curr_token), s);
389 	if (*e != '.' && *e != '!')
390 	    (void) fprintf(stderr, " at \"%s\"", curr_token);
391 	(void) fprintf(stderr, "\n");
392 
393 	if (++fatal_error > MAX_ERRORS) {
394 		(void) fprintf(stderr,"Too many errors, good bye!\n");
395 		exit(EXIT_FAILURE);
396 	}
397 }
398 
399 
400 void
lc_error(const char * fmt,...)401 lc_error(const char *fmt, ...)
402 {
403     char buf[512];
404     va_list argp;
405 
406     va_start(argp, fmt);
407     (void) vsnprintf(buf, 511, fmt, argp);
408     va_end(argp);
409 
410     yyerror(buf);
411 }
412 
413 
414 /*
415  * Just display a warning (that is : a non fatal error)
416  */
417 void
yywarning(s)418 yywarning(s)
419 const char *s;
420 {
421 	(void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
422 				fname, line_number, s);
423 }
424 
425 void
lc_warning(const char * fmt,...)426 lc_warning(const char *fmt, ...)
427 {
428     char buf[512];
429     va_list argp;
430 
431     va_start(argp, fmt);
432     (void) vsnprintf(buf, 511, fmt, argp);
433     va_end(argp);
434 
435     yywarning(buf);
436 }
437 
438 char *
decode_parm_chr(chr)439 decode_parm_chr(chr)
440 char chr;
441 {
442     static char buf[32];
443     switch (chr) {
444     default: sprintf(buf, "unknown"); break;
445     case 'i': sprintf(buf, "int"); break;
446     case 'r': sprintf(buf, "region"); break;
447     case 's': sprintf(buf, "str"); break;
448     case 'O': sprintf(buf, "obj"); break;
449     case 'c': sprintf(buf, "coord"); break;
450     case ' ': sprintf(buf, "nothing"); break;
451     case 'm': sprintf(buf, "mapchar"); break;
452     case 'M': sprintf(buf, "monster"); break;
453     }
454     return buf;
455 }
456 
457 char *
decode_parm_str(str)458 decode_parm_str(str)
459 char *str;
460 {
461     static char tmpbuf[1024];
462     char *p = str;
463     tmpbuf[0] = '\0';
464     if (str) {
465 	for ( ; *p; p++) {
466 	    Strcat(tmpbuf, decode_parm_chr(*p));
467 	    if (*(p + 1)) Strcat(tmpbuf, ", ");
468 	}
469     }
470     return tmpbuf;
471 }
472 
473 int
is_core_func(char * str)474 is_core_func(char *str)
475 {
476     int i;
477     for (i = 0; core_vars[i].name; i++)
478 	if (!strcmp(core_vars[i].name, str))
479 	    return core_vars[i].functype;
480     return 0;
481 }
482 
483 int
core_func_idx(char * str)484 core_func_idx(char *str)
485 {
486     int i;
487     for (i = 0; core_vars[i].name; i++)
488 	if (!strcmp(core_vars[i].name, str))
489 	    return i;
490     return -1;
491 }
492 
493 char
core_func_retval(int idx)494 core_func_retval(int idx)
495 {
496     return core_vars[idx].retval;
497 }
498 
499 const char *
core_func_params(int idx)500 core_func_params(int idx)
501 {
502     return core_vars[idx].params;
503 }
504 
505 const char *
core_func_name(int idx)506 core_func_name(int idx)
507 {
508     return core_vars[idx].name;
509 }
510 
511 int
handle_corefunc(splev,funcname,parmlist,retc)512 handle_corefunc(splev, funcname, parmlist, retc)
513 sp_lev *splev;
514 char *funcname;
515 char *parmlist;
516 char retc;
517 {
518     int f = is_core_func(funcname);
519     int i;
520     char *p, *dp;
521     if (!f) {
522 	lc_error("Unknown core function '%s'", funcname);
523 	return 0;
524     }
525     i = core_func_idx(funcname);
526     p = (char *)core_func_params(i);
527     if (strcmp(parmlist, p)) {
528 	if (!strcmp(p, "")) {
529 	    lc_error("Core function '%s' takes no parameters.", funcname);
530 	} else {
531 	    dp = strdup(decode_parm_str(p));
532 	    lc_error("Core function '%s' requires '%s' parameter%s, got '%s' instead.",
533 		     funcname, dp,
534 		     (strlen(p) > 1 ? "s" : ""),
535 		     decode_parm_str(parmlist));
536 	    free(dp);
537 	}
538 	return 0;
539     }
540     if (core_func_retval(i) != retc) {
541 	lc_error("Core function '%s' does not return '%s' value.", funcname, decode_parm_chr(retc));
542 	return 0;
543     }
544     add_opvars(splev, "io", f, SPO_COREFUNC);
545     return 1;
546 }
547 
548 struct opvar *
set_opvar_int(ov,val)549 set_opvar_int(ov, val)
550 struct opvar *ov;
551 long  val;
552 {
553     if (ov) {
554         ov->spovartyp = SPOVAR_INT;
555         ov->vardata.l = val;
556     }
557     return ov;
558 }
559 
560 struct opvar *
set_opvar_coord(ov,val)561 set_opvar_coord(ov, val)
562 struct opvar *ov;
563 long  val;
564 {
565     if (ov) {
566         ov->spovartyp = SPOVAR_COORD;
567         ov->vardata.l = val;
568     }
569     return ov;
570 }
571 
572 struct opvar *
set_opvar_region(ov,val)573 set_opvar_region(ov, val)
574 struct opvar *ov;
575 long  val;
576 {
577     if (ov) {
578         ov->spovartyp = SPOVAR_REGION;
579         ov->vardata.l = val;
580     }
581     return ov;
582 }
583 
584 struct opvar *
set_opvar_mapchar(ov,val)585 set_opvar_mapchar(ov, val)
586 struct opvar *ov;
587 long  val;
588 {
589     if (ov) {
590         ov->spovartyp = SPOVAR_MAPCHAR;
591         ov->vardata.l = val;
592     }
593     return ov;
594 }
595 
596 struct opvar *
set_opvar_monst(ov,val)597 set_opvar_monst(ov, val)
598 struct opvar *ov;
599 long  val;
600 {
601     if (ov) {
602         ov->spovartyp = SPOVAR_MONST;
603         ov->vardata.l = val;
604     }
605     return ov;
606 }
607 
608 struct opvar *
set_opvar_obj(ov,val)609 set_opvar_obj(ov, val)
610 struct opvar *ov;
611 long  val;
612 {
613     if (ov) {
614         ov->spovartyp = SPOVAR_OBJ;
615         ov->vardata.l = val;
616     }
617     return ov;
618 }
619 
620 struct opvar *
set_opvar_str(ov,val)621 set_opvar_str(ov, val)
622 struct opvar *ov;
623 char *val;
624 {
625     if (ov) {
626         ov->spovartyp = SPOVAR_STRING;
627 	ov->vardata.str = (val) ? strdup(val) : NULL;
628     }
629     return ov;
630 }
631 
632 struct opvar *
set_opvar_var(ov,val)633 set_opvar_var(ov, val)
634 struct opvar *ov;
635 char *val;
636 {
637     if (ov) {
638         ov->spovartyp = SPOVAR_VARIABLE;
639 	ov->vardata.str = (val) ? strdup(val) : NULL;
640     }
641     return ov;
642 }
643 
644 #define New(type)		\
645 	(type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type))
646 
647 void
add_opvars(sp_lev * sp,const char * fmt,...)648 add_opvars(sp_lev *sp, const char *fmt, ...)
649 {
650     const char *p;
651     va_list argp;
652 
653     va_start(argp, fmt);
654 
655     for(p = fmt; *p != '\0'; p++) {
656 	switch(*p) {
657 	case ' ': break;
658 	case 'i':
659 	    {
660 		struct opvar *ov = New(struct opvar);
661 		set_opvar_int(ov, va_arg(argp, long));
662 		add_opcode(sp, SPO_PUSH, ov);
663 		break;
664 	    }
665 	case 'c':
666 	    {
667 		struct opvar *ov = New(struct opvar);
668 		set_opvar_coord(ov, va_arg(argp, long));
669 		add_opcode(sp, SPO_PUSH, ov);
670 		break;
671 	    }
672 	case 'r':
673 	    {
674 		struct opvar *ov = New(struct opvar);
675 		set_opvar_region(ov, va_arg(argp, long));
676 		add_opcode(sp, SPO_PUSH, ov);
677 		break;
678 	    }
679 	case 'm':
680 	    {
681 		struct opvar *ov = New(struct opvar);
682 		set_opvar_mapchar(ov, va_arg(argp, long));
683 		add_opcode(sp, SPO_PUSH, ov);
684 		break;
685 	    }
686 	case 'M':
687 	    {
688 		struct opvar *ov = New(struct opvar);
689 		set_opvar_monst(ov, va_arg(argp, long));
690 		add_opcode(sp, SPO_PUSH, ov);
691 		break;
692 	    }
693 	case 'O':
694 	    {
695 		struct opvar *ov = New(struct opvar);
696 		set_opvar_obj(ov, va_arg(argp, long));
697 		add_opcode(sp, SPO_PUSH, ov);
698 		break;
699 	    }
700 	case 's':
701 	    {
702 		struct opvar *ov = New(struct opvar);
703 		set_opvar_str(ov, va_arg(argp, char *));
704 		add_opcode(sp, SPO_PUSH, ov);
705 		break;
706 	    }
707 	case 'v':
708 	    {
709 		struct opvar *ov = New(struct opvar);
710 		set_opvar_var(ov, va_arg(argp, char *));
711 		add_opcode(sp, SPO_PUSH, ov);
712 		break;
713 	    }
714 	case 'o':
715 	    {
716 		long i = va_arg(argp, int);
717 		if (i < 0 || i >= MAX_SP_OPCODES)
718 		    fprintf(stderr, "add_opvars: unknown opcode '%i'.\n", i);
719 		add_opcode(sp, i, NULL);
720 		break;
721 	    }
722 	default:
723 	    fprintf(stderr, "add_opvars: illegal format character '%c'.\n", *p);
724 	    break;
725 	}
726     }
727 
728     va_end(argp);
729 }
730 
731 void
break_stmt_start()732 break_stmt_start()
733 {
734     allow_break_statements++;
735 }
736 
737 void
break_stmt_end(splev)738 break_stmt_end(splev)
739      sp_lev *splev;
740 {
741     struct lc_breakdef *tmp = break_list;
742     struct lc_breakdef *prv = NULL;
743     while (tmp) {
744 	if (tmp->break_depth == allow_break_statements) {
745 	    struct lc_breakdef *nxt = tmp->next;
746 	    set_opvar_int(tmp->breakpoint, splev->n_opcodes - tmp->breakpoint->vardata.l-1);
747 	    tmp->next = NULL;
748 	    Free(tmp);
749 	    if (!prv) break_list = NULL;
750 	    else prv->next = nxt;
751 	    tmp = nxt;
752 	} else {
753 	    prv = tmp;
754 	    tmp = tmp->next;
755 	}
756     }
757     allow_break_statements--;
758 }
759 
760 void
break_stmt_new(splev,i)761 break_stmt_new(splev,i)
762      sp_lev *splev;
763      long i;
764 {
765     struct lc_breakdef *tmp = New(struct lc_breakdef);
766     tmp->breakpoint = New(struct opvar);
767     tmp->break_depth = allow_break_statements;
768     tmp->next = break_list;
769     break_list = tmp;
770     set_opvar_int(tmp->breakpoint, i);
771     add_opcode(splev, SPO_PUSH, tmp->breakpoint);
772     add_opcode(splev, SPO_JMP, NULL);
773 }
774 
775 struct lc_funcdefs *
funcdef_new(addr,name)776 funcdef_new(addr, name)
777      long addr;
778      char *name;
779 {
780     struct lc_funcdefs *f = New(struct lc_funcdefs);
781     if (!f) {
782 	lc_error("Could not alloc function definition for '%s'.", name);
783 	return NULL;
784     }
785     f->next = NULL;
786     f->addr = addr;
787     f->name = strdup(name);
788     f->n_called = 0;
789     f->n_params = 0;
790     f->params = NULL;
791     f->code.opcodes = NULL;
792     f->code.n_opcodes = 0;
793     return f;
794 }
795 
796 void
funcdef_free_all(fchain)797 funcdef_free_all(fchain)
798      struct lc_funcdefs *fchain;
799 {
800     struct lc_funcdefs *tmp = fchain;
801     struct lc_funcdefs *nxt;
802     struct lc_funcdefs_parm *tmpparam;
803     while (tmp) {
804 	nxt = tmp->next;
805 	Free(tmp->name);
806 	while (tmp->params) {
807 	    tmpparam = tmp->params->next;
808 	    Free(tmp->params->name);
809 	    tmp->params = tmpparam;
810 	}
811 	/* FIXME: free tmp->code */
812 	Free(tmp);
813 	tmp = nxt;
814     }
815 }
816 
817 
818 char *
funcdef_paramtypes(f)819 funcdef_paramtypes(f)
820      struct lc_funcdefs *f;
821 {
822     int i = 0;
823     struct lc_funcdefs_parm *fp = f->params;
824     char *tmp = (char *)alloc((f->n_params) + 1);
825     if (!tmp) return NULL;
826     while (fp) {
827 	tmp[i++] = fp->parmtype;
828 	fp = fp->next;
829     }
830     tmp[i] = '\0';
831     return tmp;
832 }
833 
834 struct lc_funcdefs *
funcdef_defined(f,name,casesense)835 funcdef_defined(f, name, casesense)
836      struct lc_funcdefs *f;
837      char *name;
838      int casesense;
839 {
840     while (f) {
841 	if (casesense) {
842 	    if (!strcmp(name, f->name)) return f;
843 	} else {
844 	    if (!strcasecmp(name, f->name)) return f;
845 	}
846 	f = f->next;
847     }
848     return NULL;
849 }
850 
851 
852 struct lc_vardefs *
vardef_new(typ,name)853 vardef_new(typ, name)
854      long typ;
855      char *name;
856 {
857     struct lc_vardefs *f = New(struct lc_vardefs);
858     if (!f) {
859 	lc_error("Could not alloc variable definition for '%s'.", name);
860 	return NULL;
861     }
862     f->next = NULL;
863     f->var_type = typ;
864     f->name = strdup(name);
865     f->n_used = 0;
866     return f;
867 }
868 
869 void
vardef_free_all(fchain)870 vardef_free_all(fchain)
871      struct lc_vardefs *fchain;
872 {
873     struct lc_vardefs *tmp = fchain;
874     struct lc_vardefs *nxt;
875     while (tmp) {
876 	if (be_verbose && (tmp->n_used == 0))
877 	    lc_warning("Unused variable '%s'", tmp->name);
878 	nxt = tmp->next;
879 	Free(tmp->name);
880 	Free(tmp);
881 	tmp = nxt;
882     }
883 }
884 
885 struct lc_vardefs *
vardef_defined(f,name,casesense)886 vardef_defined(f, name, casesense)
887      struct lc_vardefs *f;
888      char *name;
889      int casesense;
890 {
891     while (f) {
892 	if (casesense) {
893 	    if (!strcmp(name, f->name)) return f;
894 	} else {
895 	    if (!strcasecmp(name, f->name)) return f;
896 	}
897 	f = f->next;
898     }
899     return NULL;
900 }
901 
902 const char *
spovar2str(spovar)903 spovar2str(spovar)
904      long spovar;
905 {
906     static int togl = 0;
907     static char buf[2][128];
908     char *n = NULL;
909     int is_array = (spovar & SPOVAR_ARRAY);
910     spovar &= ~SPOVAR_ARRAY;
911 
912     switch (spovar) {
913     default:		  lc_error("spovar2str(%li)", spovar); break;
914     case SPOVAR_INT:	  n = "integer"; break;
915     case SPOVAR_STRING:   n = "string"; break;
916     case SPOVAR_VARIABLE: n = "variable"; break;
917     case SPOVAR_COORD:	  n = "coordinate"; break;
918     case SPOVAR_REGION:	  n = "region"; break;
919     case SPOVAR_MAPCHAR:  n = "mapchar"; break;
920     case SPOVAR_MONST:	  n = "monster"; break;
921     case SPOVAR_OBJ:	  n = "object"; break;
922     }
923 
924     togl = ((togl + 1) % 2);
925 
926     snprintf(buf[togl], 127, "%s%s", n, (is_array ? " array" : ""));
927     return buf[togl];
928 }
929 
930 void
vardef_used(vd,varname)931 vardef_used(vd, varname)
932      struct lc_vardefs *vd;
933      char *varname;
934 {
935     struct lc_vardefs *tmp;
936     if ((tmp = vardef_defined(vd, varname, 1))) tmp->n_used++;
937 }
938 
939 void
check_vardef_type(vd,varname,vartype)940 check_vardef_type(vd, varname, vartype)
941      struct lc_vardefs *vd;
942      char *varname;
943      long vartype;
944 {
945     struct lc_vardefs *tmp;
946     if ((tmp = vardef_defined(vd, varname, 1))) {
947 	if (tmp->var_type != vartype)
948 	    lc_error("Trying to use variable '%s' as %s, when it is %s.",
949 		     varname, spovar2str(vartype), spovar2str(tmp->var_type));
950     } else lc_error("Variable '%s' not defined.", varname);
951 }
952 
953 struct lc_vardefs *
add_vardef_type(vd,varname,vartype)954 add_vardef_type(vd, varname, vartype)
955      struct lc_vardefs *vd;
956      char *varname;
957      long vartype;
958 {
959     struct lc_vardefs *tmp;
960     if ((tmp = vardef_defined(vd, varname, 1))) {
961 	if (tmp->var_type != vartype)
962 	    lc_error("Trying to redefine variable '%s' as %s, when it is %s.",
963 		     varname, spovar2str(vartype), spovar2str(tmp->var_type));
964     } else {
965 	tmp = vardef_new(vartype, varname);
966 	tmp->next = vd;
967 	return tmp;
968     }
969     return vd;
970 }
971 
972 int
reverse_jmp_opcode(opcode)973 reverse_jmp_opcode(opcode)
974      int opcode;
975 {
976     switch (opcode) {
977     case SPO_JE:  return SPO_JNE;
978     case SPO_JNE: return SPO_JE;
979     case SPO_JL:  return SPO_JGE;
980     case SPO_JG:  return SPO_JLE;
981     case SPO_JLE: return SPO_JG;
982     case SPO_JGE: return SPO_JL;
983     default: lc_error("Cannot reverse comparison jmp opcode %i.", opcode); return SPO_NULL;
984     }
985 }
986 
987 /* basically copied from src/sp_lev.c */
988 struct opvar *
opvar_clone(ov)989 opvar_clone(ov)
990      struct opvar *ov;
991 {
992     if (ov) {
993 	struct opvar *tmpov = (struct opvar *)alloc(sizeof(struct opvar));
994 	if (!tmpov) panic("could not alloc opvar struct");
995 	switch (ov->spovartyp) {
996 	case SPOVAR_COORD:
997 	case SPOVAR_REGION:
998 	case SPOVAR_MAPCHAR:
999 	case SPOVAR_MONST:
1000 	case SPOVAR_OBJ:
1001 	case SPOVAR_INT:
1002 	    {
1003 		tmpov->spovartyp = ov->spovartyp;
1004 		tmpov->vardata.l = ov->vardata.l;
1005 	    }
1006 	    break;
1007 	case SPOVAR_VARIABLE:
1008 	case SPOVAR_STRING:
1009 	    {
1010 		int len = strlen(ov->vardata.str);
1011 		tmpov->spovartyp = ov->spovartyp;
1012 		tmpov->vardata.str = (char *)alloc(len+1);
1013 		(void)memcpy((genericptr_t)tmpov->vardata.str,
1014 			     (genericptr_t)ov->vardata.str, len);
1015 		tmpov->vardata.str[len] = '\0';
1016 	    }
1017 	    break;
1018 	default:
1019 	    {
1020 		lc_error("Unknown opvar_clone value type (%i)!", ov->spovartyp);
1021 	    }
1022 	}
1023 	return tmpov;
1024     }
1025     return NULL;
1026 }
1027 
1028 
1029 void
splev_add_from(splev,from_splev)1030 splev_add_from(splev, from_splev)
1031      sp_lev *splev;
1032      sp_lev *from_splev;
1033 {
1034     int i;
1035     if (splev && from_splev)
1036 	for (i = 0; i < from_splev->n_opcodes; i++)
1037 	    add_opcode(splev, from_splev->opcodes[i].opcode, opvar_clone(from_splev->opcodes[i].opdat));
1038 }
1039 
1040 
1041 /*
1042  * Find the type of floor, knowing its char representation.
1043  */
1044 int
get_floor_type(c)1045 get_floor_type(c)
1046 char c;
1047 {
1048 	int val;
1049 
1050 	SpinCursor(3);
1051 	val = what_map_char(c);
1052 	if(val == INVALID_TYPE) {
1053 	    val = ERR;
1054 	    lc_warning("Invalid fill character '%c' in MAZE declaration", c);
1055 	}
1056 	return val;
1057 }
1058 
1059 /*
1060  * Find the type of a room in the table, knowing its name.
1061  */
1062 int
get_room_type(s)1063 get_room_type(s)
1064 char *s;
1065 {
1066 	register int i;
1067 
1068 	SpinCursor(3);
1069 	for(i=0; room_types[i].name; i++)
1070 	    if (!strcmp(s, room_types[i].name))
1071 		return ((int) room_types[i].type);
1072 	return ERR;
1073 }
1074 
1075 /*
1076  * Find the type of a trap in the table, knowing its name.
1077  */
1078 int
get_trap_type(s)1079 get_trap_type(s)
1080 char *s;
1081 {
1082 	register int i;
1083 
1084 	SpinCursor(3);
1085 	for (i=0; trap_types[i].name; i++)
1086 	    if(!strcmp(s,trap_types[i].name))
1087 		return trap_types[i].type;
1088 	return ERR;
1089 }
1090 
1091 /*
1092  * Find the index of a monster in the table, knowing its name.
1093  */
1094 int
get_monster_id(s,c)1095 get_monster_id(s, c)
1096 char *s;
1097 char c;
1098 {
1099 	register int i, class;
1100 
1101 	SpinCursor(3);
1102 	class = c ? def_char_to_monclass(c) : 0;
1103 	if (class == MAXMCLASSES) return ERR;
1104 
1105 	for (i = LOW_PM; i < NUMMONS; i++)
1106 	    if (!class || class == mons[i].mlet)
1107 		if (!strcmp(s, mons[i].mname)) return i;
1108 	/* didn't find it; lets try case insensitive search */
1109 	for (i = LOW_PM; i < NUMMONS; i++)
1110 	    if (!class || class == mons[i].mlet)
1111 		if (!strcasecmp(s, mons[i].mname)) {
1112 		    if (be_verbose)
1113 			lc_warning("Monster type \"%s\" matches \"%s\".", s, mons[i].mname);
1114 		    return i;
1115 		}
1116 	return ERR;
1117 }
1118 
1119 /*
1120  * Find the index of an object in the table, knowing its name.
1121  */
1122 int
get_object_id(s,c)1123 get_object_id(s, c)
1124 char *s;
1125 char c;		/* class */
1126 {
1127 	int i, class;
1128 	const char *objname;
1129 
1130 	SpinCursor(3);
1131 	class = (c > 0) ? def_char_to_objclass(c) : 0;
1132 	if (class == MAXOCLASSES) return ERR;
1133 
1134 	for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
1135 	    if (class && objects[i].oc_class != class) break;
1136 	    objname = obj_descr[i].oc_name;
1137 	    if (objname && !strcmp(s, objname))
1138 		return i;
1139 	}
1140 
1141 	for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
1142 	    if (class && objects[i].oc_class != class) break;
1143 	    objname = obj_descr[i].oc_name;
1144 	    if (objname && !strcasecmp(s, objname)) {
1145 		if (be_verbose)
1146 		    lc_warning("Object type \"%s\" matches \"%s\".", s, objname);
1147 		return i;
1148 	    }
1149 	}
1150 
1151 	return ERR;
1152 }
1153 
1154 static void
init_obj_classes()1155 init_obj_classes()
1156 {
1157 	int i, class, prev_class;
1158 
1159 	prev_class = -1;
1160 	for (i = 0; i < NUM_OBJECTS; i++) {
1161 	    class = objects[i].oc_class;
1162 	    if (class != prev_class) {
1163 		bases[class] = i;
1164 		prev_class = class;
1165 	    }
1166 	}
1167 }
1168 
1169 /*
1170  * Is the character 'c' a valid monster class ?
1171  */
1172 boolean
check_monster_char(c)1173 check_monster_char(c)
1174 char c;
1175 {
1176 	return (def_char_to_monclass(c) != MAXMCLASSES);
1177 }
1178 
1179 /*
1180  * Is the character 'c' a valid object class ?
1181  */
1182 boolean
check_object_char(c)1183 check_object_char(c)
1184 char c;
1185 {
1186 	return (def_char_to_objclass(c) != MAXOCLASSES);
1187 }
1188 
1189 /*
1190  * Convert .des map letter into floor type.
1191  */
1192 char
what_map_char(c)1193 what_map_char(c)
1194 char c;
1195 {
1196 	SpinCursor(3);
1197 	switch(c) {
1198 		  case ' '  : return(STONE);
1199 		  case '#'  : return(CORR);
1200 		  case '.'  : return(ROOM);
1201 		  case '-'  : return(HWALL);
1202 		  case '|'  : return(VWALL);
1203 		  case '+'  : return(DOOR);
1204 		  case 'A'  : return(AIR);
1205 		  case 'B'  : return(CROSSWALL); /* hack: boundary location */
1206 		  case 'C'  : return(CLOUD);
1207 		  case 'S'  : return(SDOOR);
1208 		  case 'H'  : return(SCORR);
1209 		  case '{'  : return(FOUNTAIN);
1210 		  case '\\' : return(THRONE);
1211 		  case 'K'  :
1212 #ifdef SINKS
1213 		      return(SINK);
1214 #else
1215 		      lc_warning("Sinks ('K') are not allowed in this version!  Ignoring...");
1216 		      return(ROOM);
1217 #endif
1218 		  case '}'  : return(MOAT);
1219 		  case 'P'  : return(POOL);
1220 		  case 'L'  : return(LAVAPOOL);
1221 		  case 'I'  : return(ICE);
1222 		  case 'W'  : return(WATER);
1223 		  case 'T'  : return(TREE);
1224 		  case 't'  : return(DEADTREE);
1225 		  case 'F'  : return(IRONBARS);	/* Fe = iron */
1226 		  case 'M'  : return(BOG);	/* muddy swamp */
1227 		  case 'x'  : return(MAX_TYPE);	/* 'see-through' */
1228 		  case 'Y'  : return(CRYSTALICEWALL);
1229 		  case 'U'  : return(ICEWALL);
1230 	    }
1231 	return(INVALID_TYPE);
1232 }
1233 
1234 void
add_opcode(sp,opc,dat)1235 add_opcode(sp, opc, dat)
1236 sp_lev *sp;
1237 int opc;
1238 genericptr_t dat;
1239 {
1240    long nop = sp->n_opcodes;
1241    _opcode *tmp;
1242 
1243    if ((opc < 0) || (opc >= MAX_SP_OPCODES))
1244        lc_error("Unknown opcode '%i'", opc);
1245 
1246    tmp = (_opcode *)alloc(sizeof(_opcode)*(nop+1));
1247    if (sp->opcodes && nop) {
1248        (void) memcpy(tmp, sp->opcodes, sizeof(_opcode)*nop);
1249        free(sp->opcodes);
1250    } else if (!tmp)
1251        lc_error("Could not alloc opcode space");
1252 
1253    sp->opcodes = tmp;
1254 
1255    sp->opcodes[nop].opcode = opc;
1256    sp->opcodes[nop].opdat = dat;
1257 
1258    sp->n_opcodes++;
1259 }
1260 
1261 /*
1262  * Yep! LEX gives us the map in a raw mode.
1263  * Just analyze it here.
1264  */
1265 void
scan_map(map,sp)1266 scan_map(map, sp)
1267 char *map;
1268 sp_lev *sp;
1269 {
1270 	register int i, len;
1271 	register char *s1, *s2;
1272 	long max_len = 0;
1273 	long max_hig = 0;
1274 	char *tmpmap[ROWNO];
1275 	int dx,dy;
1276 	char *mbuf;
1277 
1278 	/* First, strip out digits 0-9 (line numbering) */
1279 	for (s1 = s2 = map; *s1; s1++)
1280 	    if (*s1 < '0' || *s1 > '9')
1281 		*s2++ = *s1;
1282 	*s2 = '\0';
1283 
1284 	/* Second, find the max width of the map */
1285 	s1 = map;
1286 	while (s1 && *s1) {
1287 		s2 = index(s1, '\n');
1288 		if (s2) {
1289 			len = (int) (s2 - s1);
1290 			s1 = s2 + 1;
1291 		} else {
1292 			len = (int) strlen(s1);
1293 			s1 = (char *) 0;
1294 		}
1295 		if (len > max_len) max_len = len;
1296 	}
1297 
1298 	/* Then parse it now */
1299 	while (map && *map) {
1300 		tmpmap[max_hig] = (char *) alloc(max_len);
1301 		s1 = index(map, '\n');
1302 		if (s1) {
1303 			len = (int) (s1 - map);
1304 			s1++;
1305 		} else {
1306 			len = (int) strlen(map);
1307 			s1 = map + len;
1308 		}
1309 		for(i=0; i<len; i++)
1310 		  if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
1311 		      lc_warning("Invalid character '%c' @ (%d, %d) - replacing with stone", map[i], max_hig, i);
1312 		      tmpmap[max_hig][i] = STONE;
1313 		    }
1314 		while(i < max_len)
1315 		    tmpmap[max_hig][i++] = STONE;
1316 		map = s1;
1317 		max_hig++;
1318 	}
1319 
1320 	/* Memorize boundaries */
1321 
1322 	max_x_map = max_len - 1;
1323 	max_y_map = max_hig - 1;
1324 
1325 
1326 	if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
1327 	    lc_error("Map too large at (%d x %d), max is (%d x %d)", max_len, max_hig, MAP_X_LIM, MAP_Y_LIM);
1328 	}
1329 
1330 	mbuf = (char *) alloc(((max_hig-1) * max_len) + (max_len-1) + 2);
1331 	for (dy = 0; dy < max_hig; dy++)
1332 	    for (dx = 0; dx < max_len; dx++)
1333 		mbuf[(dy * max_len) + dx] = (tmpmap[dy][dx] + 1);
1334 
1335 	mbuf[((max_hig-1) * max_len) + (max_len-1) + 1] = '\0';
1336 
1337 	add_opvars(sp, "siio", mbuf, max_hig, max_len, SPO_MAP);
1338 
1339 	for (dy = 0; dy < max_hig; dy++)
1340 	    Free(tmpmap[dy]);
1341 	Free(mbuf);
1342 }
1343 
1344 
1345 /*
1346  * Output some info common to all special levels.
1347  */
1348 static boolean
write_common_data(fd,lvl)1349 write_common_data(fd, lvl)
1350 int fd;
1351 sp_lev *lvl;
1352 {
1353 	static struct version_info version_data = {
1354 			VERSION_NUMBER, VERSION_FEATURES,
1355 			VERSION_SANITY1, VERSION_SANITY2
1356 	};
1357 
1358 	Write(fd, &version_data, sizeof version_data);
1359 	/*Write(fd, &lvl->init_lev, sizeof(lev_init));*/
1360 	return TRUE;
1361 }
1362 
1363 
1364 /*
1365  * Here we write the sp_lev structure in the specified file (fd).
1366  * Also, we have to free the memory allocated via alloc().
1367  */
1368 static boolean
write_maze(fd,maze)1369 write_maze(fd, maze)
1370 int fd;
1371 sp_lev *maze;
1372 {
1373         int i;
1374 
1375         if (!write_common_data(fd, maze))
1376             return FALSE;
1377 
1378 	Write(fd, &(maze->n_opcodes), sizeof(maze->n_opcodes));
1379 
1380         for (i = 0; i < maze->n_opcodes; i++) {
1381 	   _opcode tmpo = maze->opcodes[i];
1382 
1383 	   Write(fd, &(tmpo.opcode), sizeof(tmpo.opcode));
1384 
1385 	   if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES)
1386 	       panic("write_maze: unknown opcode (%i).", tmpo.opcode);
1387 
1388 	   if (tmpo.opcode == SPO_PUSH) {
1389 	       genericptr_t opdat = tmpo.opdat;
1390 	       if (opdat) {
1391 		   struct opvar *ov = (struct opvar *)opdat;
1392 		   int size;
1393 		   Write(fd, &(ov->spovartyp), sizeof(ov->spovartyp));
1394 		   switch (ov->spovartyp) {
1395 		   case SPOVAR_NULL: break;
1396 		   case SPOVAR_COORD:
1397 		   case SPOVAR_REGION:
1398 		   case SPOVAR_MAPCHAR:
1399 		   case SPOVAR_MONST:
1400 		   case SPOVAR_OBJ:
1401 		   case SPOVAR_INT:
1402 		       Write(fd, &(ov->vardata.l), sizeof(ov->vardata.l));
1403 		       break;
1404 		   case SPOVAR_VARIABLE:
1405 		   case SPOVAR_STRING:
1406 		       if (ov->vardata.str)
1407 			   size = strlen(ov->vardata.str);
1408 		       else size = 0;
1409 		       Write(fd, &size, sizeof(size));
1410 		       if (size) {
1411 			   Write(fd, ov->vardata.str, size);
1412 			   Free(ov->vardata.str);
1413 		       }
1414 		       break;
1415 		   default: panic("write_maze: unknown data type (%i).", ov->spovartyp);
1416 		   }
1417 	       } else panic("write_maze: PUSH with no data.");
1418 	   } else {
1419 	       /* sanity check */
1420 	       genericptr_t opdat = tmpo.opdat;
1421 	       if (opdat)
1422 		   panic("write_maze: opcode (%i) has data.", tmpo.opcode);
1423 	   }
1424 
1425 	   Free(tmpo.opdat);
1426 
1427 	}
1428         /* clear the struct for next user */
1429 	Free(maze->opcodes);
1430 	maze->opcodes = NULL;
1431         /*(void) memset((genericptr_t) &maze->init_lev, 0, sizeof maze->init_lev);*/
1432 
1433 	return TRUE;
1434 }
1435 
1436 
1437 static boolean
decompile_maze(fd,maze)1438 decompile_maze(fd, maze)
1439 int fd;
1440 sp_lev *maze;
1441 {
1442         int i;
1443 	char debuf[128];
1444 	const char *opcodestr[MAX_SP_OPCODES] = {
1445 	    "null",
1446 	    "message",
1447 	    "monster",
1448 	    "object",
1449 	    "engraving",
1450 	    "room",
1451 	    "subroom",
1452 	    "door",
1453 	    "stair",
1454 	    "ladder",
1455 	    "altar",
1456 	    "fountain",
1457 	    "sink",
1458 	    "pool",
1459 	    "trap",
1460 	    "gold",
1461 	    "corridor",
1462 	    "levregion",
1463 	    "drawbridge",
1464 	    "mazewalk",
1465 	    "non_diggable",
1466 	    "non_passwall",
1467 	    "wallify",
1468 	    "map",
1469 	    "room_door",
1470 	    "region",
1471 	    "cmp",
1472 	    "jmp",
1473 	    "jl",
1474 	    "jle",
1475 	    "jg",
1476 	    "jge",
1477 	    "je",
1478 	    "jne",
1479 	    "spill",
1480 	    "terrain",
1481 	    "replaceterrain",
1482 	    "exit",
1483 	    "endroom",
1484 	    "pop_container",
1485 	    "push",
1486 	    "pop",
1487 	    "rn2",
1488 	    "dec",
1489 	    "inc",
1490 	    "add",
1491 	    "sub",
1492 	    "mul",
1493 	    "div",
1494 	    "mod",
1495 	    "sign",
1496 	    "copy",
1497 	    "mon_generation",
1498 	    "end_moninvent",
1499 	    "grave",
1500 	    "frame_push",
1501 	    "frame_pop",
1502 	    "call",
1503 	    "return",
1504 	    "init_map",
1505 	    "flags",
1506 	    "sounds",
1507 	    "wallwalk",
1508 	    "var_init",
1509 	    "shuffle_array",
1510 	    "dice",
1511 	    "corefunc",
1512 	    "selection_add",
1513 	    "selection_point",
1514 	    "selection_rect",
1515 	    "selection_fillrect",
1516 	    "selection_line",
1517 	    "selection_rndline",
1518 	    "selection_grow",
1519 	    "selection_flood",
1520 	    "selection_rndcoord",
1521 	    "selection_ellipse",
1522 	    "selection_filter",
1523 	    "selection_gradient",
1524 	    "selection_complement",
1525 	};
1526 
1527 	/* don't bother with the header stuff */
1528 
1529         for (i=0;i<maze->n_opcodes;i++) {
1530 	   _opcode tmpo = maze->opcodes[i];
1531 
1532 	   if (tmpo.opcode < SPO_NULL || tmpo.opcode >= MAX_SP_OPCODES)
1533 	       panic("decompile_maze: unknown opcode (%i).", tmpo.opcode);
1534 
1535 	   if (tmpo.opcode == SPO_PUSH) {
1536 	       genericptr_t opdat = tmpo.opdat;
1537 	       if (opdat) {
1538 		   struct opvar *ov = (struct opvar *)opdat;
1539 		   int size;
1540 		   switch (ov->spovartyp) {
1541 		   case SPOVAR_NULL: break;
1542 		   case SPOVAR_COORD:
1543 		       snprintf(debuf, 127, "%li:\t%s\tcoord:(%i,%i)\n", i, opcodestr[tmpo.opcode],
1544 				(ov->vardata.l & 0xff), ((ov->vardata.l >> 16) & 0xff));
1545 			   Write(fd, debuf, strlen(debuf));
1546 			   break;
1547 		   case SPOVAR_REGION:
1548 		       snprintf(debuf, 127, "%li:\t%s\tregion:(%i,%i,%i,%i)\n", i, opcodestr[tmpo.opcode],
1549 				(ov->vardata.l & 0xff), ((ov->vardata.l >> 8) & 0xff),
1550 				((ov->vardata.l >> 16) & 0xff), ((ov->vardata.l >> 24) & 0xff));
1551 			   Write(fd, debuf, strlen(debuf));
1552 			   break;
1553 		   case SPOVAR_OBJ:
1554 		       snprintf(debuf, 127, "%li:\t%s\tobj:(id=%i,class=\'%c\')\n",
1555 				i, opcodestr[tmpo.opcode],
1556 				SP_OBJ_TYP(ov->vardata.l), SP_OBJ_CLASS(ov->vardata.l));
1557 		       Write(fd, debuf, strlen(debuf));
1558 		       break;
1559 		   case SPOVAR_MONST:
1560 		       snprintf(debuf, 127, "%li:\t%s\tmonster:(pm=%i, class='%c')\n", i, opcodestr[tmpo.opcode],
1561 				SP_MONST_PM(ov->vardata.l), SP_MONST_CLASS(ov->vardata.l));
1562 		       Write(fd, debuf, strlen(debuf));
1563 		       break;
1564 		   case SPOVAR_MAPCHAR:
1565 		       snprintf(debuf, 127, "%li:\t%s\tmapchar:(%li,%i)\n", i, opcodestr[tmpo.opcode],
1566 				(int)SP_MAPCHAR_TYP(ov->vardata.l), (schar)SP_MAPCHAR_LIT(ov->vardata.l));
1567 		       Write(fd, debuf, strlen(debuf));
1568 		       break;
1569 		   case SPOVAR_INT:
1570 		       if (ov->vardata.l >= ' ' && ov->vardata.l <= '~')
1571 			   snprintf(debuf, 127, "%li:\t%s\tint:%li\t# '%c'\n", i, opcodestr[tmpo.opcode], ov->vardata.l, (char)ov->vardata.l);
1572 		       else
1573 			   snprintf(debuf, 127, "%li:\t%s\tint:%li\n", i, opcodestr[tmpo.opcode], ov->vardata.l);
1574 		       Write(fd, debuf, strlen(debuf));
1575 		       break;
1576 		   case SPOVAR_VARIABLE:
1577 		   case SPOVAR_STRING:
1578 		       if (ov->vardata.str)
1579 			   size = strlen(ov->vardata.str);
1580 		       else size = 0;
1581 		       if (size) {
1582 			   int x;
1583 			   int ok = (size > 127) ? 0 : 1;
1584 			   if (ok)
1585 			       for (x = 0; x < size; x++)
1586 				   if (ov->vardata.str[x] < ' ' || ov->vardata.str[x] > '~') {
1587 				       ok = 0;
1588 				       break;
1589 				   }
1590 			   if (ok) {
1591 			       if (ov->spovartyp == SPOVAR_VARIABLE)
1592 				   snprintf(debuf, 127, "%li:\t%s\tvar:$%s\n", i, opcodestr[tmpo.opcode], ov->vardata.str);
1593 			       else
1594 				   snprintf(debuf, 127, "%li:\t%s\tstr:\"%s\"\n", i, opcodestr[tmpo.opcode], ov->vardata.str);
1595 			       Write(fd, debuf, strlen(debuf));
1596 			   } else {
1597 			       snprintf(debuf, 127, "%li:\t%s\tstr:", i, opcodestr[tmpo.opcode]);
1598 			       Write(fd, debuf, strlen(debuf));
1599 			       for (x = 0; x < size; x++) {
1600 				   snprintf(debuf, 127, "%02x ", ov->vardata.str[x]);
1601 				   Write(fd, debuf, strlen(debuf));
1602 			       }
1603 			       snprintf(debuf, 127, "\n");
1604 			       Write(fd, debuf, strlen(debuf));
1605 			   }
1606 		       }
1607 		       break;
1608 		   default: panic("decompile_maze: unknown data type (%i).", ov->spovartyp);
1609 		   }
1610 	       } else panic("decompile_maze: PUSH with no data.");
1611 	   } else {
1612 	       /* sanity check */
1613 	       genericptr_t opdat = tmpo.opdat;
1614 	       if (opdat)
1615 		   panic("decompile_maze: opcode (%i) has data.", tmpo.opcode);
1616 	       snprintf(debuf, 127, "%li:\t%s\n", i, opcodestr[tmpo.opcode]);
1617 	       Write(fd, debuf, strlen(debuf));
1618 	   }
1619 
1620 	}
1621 	return TRUE;
1622 }
1623 
1624 char *
mangle_fname(fname)1625 mangle_fname(fname)
1626      char *fname;
1627 {
1628     static char buf[256];
1629     char *p = strchr(fname, '%');
1630 
1631     if (p) {
1632 	char buf2[256];
1633 	p++;
1634 	while (*p && (*p >= '0') && (*p <= '9')) p++;
1635 	if (*p != 'i') panic("Illegal counter variable '%%%c' in filename.", *p);
1636 	if (strchr(p, '%')) panic("Only one counter variable (%%i) in filename allowed.");
1637 	sprintf(buf2, "%s", fname);
1638 	sprintf(buf, buf2, fname_counter);
1639 	fname_counter++;
1640     } else {
1641 	sprintf(buf, "%s", fname);
1642     }
1643     return buf;
1644 }
1645 
1646 
1647 /*
1648  * Open and write special level file.
1649  * Return TRUE on success, FALSE on failure.
1650  */
1651 boolean
write_level_file(filename,lvl)1652 write_level_file(filename, lvl)
1653 char *filename;
1654 sp_lev *lvl;
1655 {
1656 	int fout;
1657 	char lbuf[60];
1658 	char * mangled = mangle_fname(filename);
1659 
1660 	if (decompile) {
1661 	    lbuf[0] = '\0';
1662 #ifdef PREFIX
1663 	    Strcat(lbuf, PREFIX);
1664 #endif
1665 	    Strcat(lbuf, mangled);
1666 	    Strcat(lbuf, "_lev.txt");
1667 	    fout = open(lbuf, O_TRUNC|O_WRONLY|O_CREAT, OMASK);
1668 	    if (fout < 0) return FALSE;
1669 	    decompile_maze(fout, lvl);
1670 	    (void) close(fout);
1671 	}
1672 
1673 	lbuf[0] = '\0';
1674 #ifdef PREFIX
1675 	Strcat(lbuf, PREFIX);
1676 #endif
1677 	Strcat(lbuf, mangled);
1678 	Strcat(lbuf, LEV_EXT);
1679 
1680 	fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
1681 	if (fout < 0) return FALSE;
1682 
1683         if (!lvl) panic("write_level_file");
1684 
1685 	if (be_verbose)
1686 	    fprintf(stdout, "File: '%s', opcodes: %li\n", lbuf, lvl->n_opcodes);
1687 
1688         if (!write_maze(fout, lvl))
1689           return FALSE;
1690 
1691 	(void) close(fout);
1692 
1693 	if (is_rnd_vault) {
1694 	    char debuf[256];
1695 	    lbuf[0] = '\0';
1696 #ifdef PREFIX
1697 	    Strcat(lbuf, PREFIX);
1698 #endif
1699 	    Strcat(lbuf, "vaults.dat");
1700 	    fout = open(lbuf, O_WRONLY|O_APPEND|O_CREAT, OMASK);
1701 	    snprintf(debuf, 255, "%i %s\n", rnd_vault_freq, mangled);
1702 	    Write(fout, debuf, strlen(debuf));
1703 	    (void) close(fout);
1704 	}
1705 
1706 	return TRUE;
1707 }
1708 
1709 #ifdef STRICT_REF_DEF
1710 /*
1711  * Any globals declared in hack.h and descendents which aren't defined
1712  * in the modules linked into lev_comp should be defined here.  These
1713  * definitions can be dummies:  their sizes shouldn't matter as long as
1714  * as their types are correct; actual values are irrelevant.
1715  */
1716 #define ARBITRARY_SIZE 1
1717 /* attrib.c */
1718 struct attribs attrmax, attrmin;
1719 /* files.c */
1720 const char *configfile;
1721 char lock[ARBITRARY_SIZE];
1722 char SAVEF[ARBITRARY_SIZE];
1723 # ifdef MICRO
1724 char SAVEP[ARBITRARY_SIZE];
1725 # endif
1726 /* termcap.c */
1727 struct tc_lcl_data tc_lcl_data;
1728 # ifdef TEXTCOLOR
1729 #  ifdef TOS
1730 const char *hilites[CLR_MAX];
1731 #  else
1732 char NEARDATA *hilites[CLR_MAX];
1733 #  endif
1734 # endif
1735 /* trap.c */
1736 const char *traps[TRAPNUM];
1737 /* window.c */
1738 struct window_procs windowprocs;
1739 /* xxxtty.c */
1740 # ifdef DEFINE_OSPEED
1741 short ospeed;
1742 # endif
1743 #endif	/* STRICT_REF_DEF */
1744 
1745 /*lev_main.c*/
1746