OSDN Git Service

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