root/trunk/src/files.c

Revision 983, 57.1 kB (checked in by takkaria, 2 months ago)

Remove yet more debugging guff. (Rowan Beentje)

  • Property svn:eol-style set to native
Line 
1 /*
2  * File: files.c
3  * Purpose: Various file-related activities, poorly organised
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 #include "angband.h"
19 #include "tvalsval.h"
20 #include "ui-menu.h"
21 #include "cmds.h"
22 #include "option.h"
23
24 #define MAX_PANEL 12
25
26
27 #if 0
28
29 /*
30  * Use this (perhaps) for Angband 2.8.4
31  *
32  * Extract "tokens" from a buffer
33  *
34  * This function uses "whitespace" as delimiters, and treats any amount of
35  * whitespace as a single delimiter.  We will never return any empty tokens.
36  * When given an empty buffer, or a buffer containing only "whitespace", we
37  * will return no tokens.  We will never extract more than "num" tokens.
38  *
39  * By running a token through the "text_to_ascii()" function, you can allow
40  * that token to include (encoded) whitespace, using "\s" to encode spaces.
41  *
42  * We save pointers to the tokens in "tokens", and return the number found.
43  */
44 static s16b tokenize_whitespace(char *buf, s16b num, char **tokens)
45 {
46         int k = 0;
47
48         char *s = buf;
49
50
51         /* Process */
52         while (k < num)
53         {
54                 char *t;
55
56                 /* Skip leading whitespace */
57                 for ( ; *s && isspace((unsigned char)*s); ++s) /* loop */;
58
59                 /* All done */
60                 if (!*s) break;
61
62                 /* Find next whitespace, if any */
63                 for (t = s; *t && !isspace((unsigned char)*t); ++t) /* loop */;
64
65                 /* Nuke and advance (if necessary) */
66                 if (*t) *t++ = '\0';
67
68                 /* Save the token */
69                 tokens[k++] = s;
70
71                 /* Advance */
72                 s = t;
73         }
74
75         /* Count */
76         return (k);
77 }
78
79 #endif
80
81
82 /*
83  * Extract the first few "tokens" from a buffer
84  *
85  * This function uses "colon" and "slash" as the delimeter characters.
86  *
87  * We never extract more than "num" tokens.  The "last" token may include
88  * "delimeter" characters, allowing the buffer to include a "string" token.
89  *
90  * We save pointers to the tokens in "tokens", and return the number found.
91  *
92  * Hack -- Attempt to handle the 'c' character formalism
93  *
94  * Hack -- An empty buffer, or a final delimeter, yields an "empty" token.
95  *
96  * Hack -- We will always extract at least one token
97  */
98 s16b tokenize(char *buf, s16b num, char **tokens)
99 {
100         int i = 0;
101
102         char *s = buf;
103
104
105         /* Process */
106         while (i < num - 1)
107         {
108                 char *t;
109
110                 /* Scan the string */
111                 for (t = s; *t; t++)
112                 {
113                         /* Allow pseudo-escaping */
114                         if (*t == '\\') t++;
115
116                         /* Found a delimiter */
117                         else if (*t == ':') break;
118                 }
119
120                 /* Nothing left */
121                 if (!*t) break;
122
123                 /* Nuke and advance */
124                 *t++ = '\0';
125
126                 /* Save the token */
127                 tokens[i++] = s;
128
129                 /* Advance */
130                 s = t;
131         }
132
133         /* Save the token */
134         tokens[i++] = s;
135
136         /* Number found */
137         return (i);
138 }
139
140
141
142 /*
143  * Parse a sub-file of the "extra info" (format shown below)
144  *
145  * Each "action" line has an "action symbol" in the first column,
146  * followed by a colon, followed by some command specific info,
147  * usually in the form of "tokens" separated by colons or slashes.
148  *
149  * Blank lines, lines starting with white space, and lines starting
150  * with pound signs ("#") are ignored (as comments).
151  *
152  * Note the use of "tokenize()" to allow the use of both colons and
153  * slashes as delimeters, while still allowing final tokens which
154  * may contain any characters including "delimiters".
155  *
156  * Note the use of "strtol()" to allow all "integers" to be encoded
157  * in decimal, hexidecimal, or octal form.
158  *
159  * Note that "monster zero" is used for the "player" attr/char, "object
160  * zero" will be used for the "stack" attr/char, and "feature zero" is
161  * used for the "nothing" attr/char.
162  *
163  * Specify the attr/char values for "monsters" by race index.
164  *   R:<num>:<a>/<c>
165  *
166  * Specify the attr/char values for "objects" by kind index.
167  *   K:<num>:<a>/<c>
168  *
169  * Specify the attr/char values for "features" by feature index.
170  *   F:<num>:<a>/<c>
171  *
172  * Specify the attr/char values for "special" things.
173  *   S:<num>:<a>/<c>
174  *
175  * Specify the attribute values for inventory "objects" by kind tval.
176  *   E:<tv>:<a>
177  *
178  * Define a macro action, given an encoded macro action.
179  *   A:<str>
180  *
181  * Create a macro, given an encoded macro trigger.
182  *   P:<str>
183  *
184  * Create a keymap, given an encoded keymap trigger.
185  *   C:<num>:<str>
186  *
187  * Turn an option off, given its name.
188  *   X:<str>
189  *
190  * Turn an option on, given its name.
191  *   Y:<str>
192  *
193  * Turn a window flag on or off, given a window, flag, and value.
194  *   W:<win>:<flag>:<value>
195  *
196  * Specify visual information, given an index, and some data.
197  *   V:<num>:<kv>:<rv>:<gv>:<bv>
198  *
199  * Specify colors for message-types.
200  *   M:<type>:<attr>
201  *
202  * Specify the attr/char values for "flavors" by flavors index.
203  *   L:<num>:<a>/<c>
204  */
205 errr process_pref_file_command(char *buf)
206 {
207         long i, n1, n2, sq;
208
209         char *zz[16];
210
211
212         /* Skip "empty" lines */
213         if (!buf[0]) return (0);
214
215         /* Skip "blank" lines */
216         if (isspace((unsigned char)buf[0])) return (0);
217
218         /* Skip comments */
219         if (buf[0] == '#') return (0);
220
221
222         /* Paranoia */
223         /* if (strlen(buf) >= 1024) return (1); */
224
225
226         /* Require "?:*" format */
227         if (buf[1] != ':') return (1);
228
229
230         /* Process "R:<num>:<a>/<c>" -- attr/char for monster races */
231         if (buf[0] == 'R')
232         {
233                 if (tokenize(buf+2, 3, zz) == 3)
234                 {
235                         monster_race *r_ptr;
236                         i = strtol(zz[0], NULL, 0);
237                         n1 = strtol(zz[1], NULL, 0);
238                         n2 = strtol(zz[2], NULL, 0);
239                         if ((i < 0) || (i >= (long)z_info->r_max)) return (1);
240                         r_ptr = &r_info[i];
241                         if (n1) r_ptr->x_attr = (byte)n1;
242                         if (n2) r_ptr->x_char = (char)n2;
243                         return (0);
244                 }
245         }
246
247         /* Process "B:<k_idx>:inscription */
248         else if (buf[0] == 'B')
249         {
250                 if (2 == tokenize(buf + 2, 2, zz))
251                 {
252                         add_autoinscription(strtol(zz[0], NULL, 0), zz[1]);
253                         return (0);
254                 }
255         }
256
257         /* Process "Q:<idx>:<tval>:<sval>:<y|n>"  -- squelch bits   */
258         /* and     "Q:<idx>:<val>"                -- squelch levels */
259         /* and     "Q:<val>"                      -- auto_destroy   */
260         else if (buf[0] == 'Q')
261         {
262                 i = tokenize(buf+2, 4, zz);
263                 if (i == 2)
264                 {
265                         n1 = strtol(zz[0], NULL, 0);
266                         n2 = strtol(zz[1], NULL, 0);
267                         squelch_level[n1] = n2;
268                         return(0);
269                 }
270                 else if (i == 4)
271                 {
272                         i = strtol(zz[0], NULL, 0);
273                         n1 = strtol(zz[1], NULL, 0);
274                         n2 = strtol(zz[2], NULL, 0);
275                         sq = strtol(zz[3], NULL, 0);
276                         if ((k_info[i].tval == n1) && (k_info[i].sval == n2))
277                         {
278                                 k_info[i].squelch = sq;
279                                 return(0);
280                         }
281                         else
282                         {
283                                 for (i = 1; i < z_info->k_max; i++)
284                                 {
285                                         if ((k_info[i].tval == n1) && (k_info[i].sval == n2))
286                                         {
287                                                 k_info[i].squelch = sq;
288                                                 return(0);
289                                         }
290                                 }
291                         }
292                 }
293         }
294
295         /* Process "K:<tval>:<sval>:<a>/<c>"  -- attr/char for object kinds */
296         else if (buf[0] == 'K')
297         {
298                 if (tokenize(buf+2, 4, zz) == 4)
299                 {
300                         object_kind *k_ptr;
301
302                         int tval, sval;
303                         const char *tval_s = zz[0];
304                         const char *sval_s = zz[1];
305
306                         n1 = strtol(zz[2], NULL, 0);
307                         n2 = strtol(zz[3], NULL, 0);
308
309                         /* Now convert the tval into its numeric equivalent */
310                         if (1 != sscanf(tval_s, "%d", &tval))
311                         {
312                                 tval = tval_find_idx(tval_s);
313                                 if (tval == -1) return 1;
314                         }
315
316                         /* Now find the sval */
317                         if (1 != sscanf(sval_s, "%d", &sval))
318                         {
319                                 sval = lookup_sval(tval, sval_s);
320                                 if (sval == -1) return 1;
321                         }
322
323                         i = lookup_kind(tval, sval);
324
325                         if ((i < 0) || (i >= (long)z_info->k_max)) return (1);
326
327                         k_ptr = &k_info[i];
328
329                         if (n1) k_ptr->x_attr = (byte)n1;
330                         if (n2) k_ptr->x_char = (char)n2;
331
332                         return (0);
333                 }
334         }
335
336
337         /* Process "F:<num>:<a>/<c>" -- attr/char for terrain features */
338         else if (buf[0] == 'F')
339         {
340                 if (tokenize(buf+2, 3, zz) == 3)
341                 {
342                         feature_type *f_ptr;
343                         i = strtol(zz[0], NULL, 0);
344                         n1 = strtol(zz[1], NULL, 0);
345                         n2 = strtol(zz[2], NULL, 0);
346                         if ((i < 0) || (i >= (long)z_info->f_max)) return (1);
347                         f_ptr = &f_info[i];
348                         if (n1) f_ptr->x_attr = (byte)n1;
349                         if (n2) f_ptr->x_char = (char)n2;
350                         return (0);
351                 }
352         }
353
354
355         /* Process "L:<num>:<a>/<c>" -- attr/char for flavors */
356         else if (buf[0] == 'L')
357         {
358                 if (tokenize(buf+2, 3, zz) == 3)
359                 {
360                         flavor_type *flavor_ptr;
361                         i = strtol(zz[0], NULL, 0);
362                         n1 = strtol(zz[1], NULL, 0);
363                         n2 = strtol(zz[2], NULL, 0);
364                         if ((i < 0) || (i >= (long)z_info->flavor_max)) return (1);
365                         flavor_ptr = &flavor_info[i];
366                         if (n1) flavor_ptr->x_attr = (byte)n1;
367                         if (n2) flavor_ptr->x_char = (char)n2;
368                         return (0);
369                 }
370         }
371
372
373         /* Process "S:<num>:<a>/<c>" -- attr/char for special things */
374         else if (buf[0] == 'S')
375         {
376                 if (tokenize(buf+2, 3, zz) == 3)
377                 {
378                         i = strtol(zz[0], NULL, 0);
379                         n1 = strtol(zz[1], NULL, 0);
380                         n2 = strtol(zz[2], NULL, 0);
381                         if ((i < 0) || (i >= (long)N_ELEMENTS(misc_to_attr))) return (1);
382                         misc_to_attr[i] = (byte)n1;
383                         misc_to_char[i] = (char)n2;
384                         return (0);
385                 }
386         }
387
388
389         /* Process "E:<tv>:<a>" -- attribute for inventory objects */
390         else if (buf[0] == 'E')
391         {
392                 if (tokenize(buf+2, 2, zz) == 2)
393                 {
394                         i = strtol(zz[0], NULL, 0) % 128;
395                         n1 = strtol(zz[1], NULL, 0);
396                         if ((i < 0) || (i >= (long)N_ELEMENTS(tval_to_attr))) return (1);
397                         if (n1) tval_to_attr[i] = (byte)n1;
398                         return (0);
399                 }
400         }
401
402
403         /* Process "A:<str>" -- save an "action" for later */
404         else if (buf[0] == 'A')
405         {
406                 text_to_ascii(macro_buffer, sizeof(macro_buffer), buf+2);
407                 return (0);
408         }
409
410         /* Process "P:<str>" -- create macro */
411         else if (buf[0] == 'P')
412         {
413                 char tmp[1024];
414                 text_to_ascii(tmp, sizeof(tmp), buf+2);
415                 macro_add(tmp, macro_buffer);
416                 return (0);
417         }
418
419         /* Process "C:<num>:<str>" -- create keymap */
420         else if (buf[0] == 'C')
421         {
422                 long mode;
423
424                 char tmp[1024];
425
426                 if (tokenize(buf+2, 2, zz) != 2) return (1);
427
428                 mode = strtol(zz[0], NULL, 0);
429                 if ((mode < 0) || (mode >= KEYMAP_MODES)) return (1);
430
431                 text_to_ascii(tmp, sizeof(tmp), zz[1]);
432                 if (!tmp[0] || tmp[1]) return (1);
433                 i = (long)tmp[0];
434
435                 string_free(keymap_act[mode][i]);
436
437                 keymap_act[mode][i] = string_make(macro_buffer);
438
439                 return (0);
440         }
441
442
443         /* Process "V:<num>:<kv>:<rv>:<gv>:<bv>" -- visual info */
444         else if (buf[0] == 'V')
445         {
446                 if (tokenize(buf+2, 5, zz) == 5)
447                 {
448                         i = strtol(zz[0], NULL, 0);
449                         if ((i < 0) || (i >= MAX_COLORS)) return (1);
450                         angband_color_table[i][0] = (byte)strtol(zz[1], NULL, 0);
451                         angband_color_table[i][1] = (byte)strtol(zz[2], NULL, 0);
452                         angband_color_table[i][2] = (byte)strtol(zz[3], NULL, 0);
453                         angband_color_table[i][3] = (byte)strtol(zz[4], NULL, 0);
454                         return (0);
455                 }
456         }
457
458         /* set macro trigger names and a template */
459         /* Process "T:<trigger>:<keycode>:<shift-keycode>" */
460         /* Process "T:<template>:<modifier chr>:<modifier name>:..." */
461         else if (buf[0] == 'T')
462         {
463                 int tok;
464
465                 tok = tokenize(buf + 2, MAX_MACRO_MOD + 2, zz);
466
467                 /* Trigger template */
468                 if (tok >= 4)
469                 {
470                         int i;
471                         int num;
472
473                         /* Free existing macro triggers and trigger template */
474                         macro_trigger_free();
475
476                         /* Clear template done */
477                         if (*zz[0] == '\0') return 0;
478
479                         /* Count modifier-characters */
480                         num = strlen(zz[1]);
481
482                         /* One modifier-character per modifier */
483                         if (num + 2 != tok) return 1;
484
485                         /* Macro template */
486                         macro_template = string_make(zz[0]);
487
488                         /* Modifier chars */
489                         macro_modifier_chr = string_make(zz[1]);
490
491                         /* Modifier names */
492                         for (i = 0; i < num; i++)
493                         {
494                                 macro_modifier_name[i] = string_make(zz[2+i]);
495                         }
496                 }
497
498                 /* Macro trigger */
499                 else if (tok >= 2)
500                 {
501                         char *buf;
502                         cptr s;
503                         char *t;
504
505                         if (max_macrotrigger >= MAX_MACRO_TRIGGER)
506                         {
507                                 msg_print("Too many macro triggers!");
508                                 return 1;
509                         }
510
511                         /* Buffer for the trigger name */
512                         buf = C_ZNEW(strlen(zz[0]) + 1, char);
513
514                         /* Simulate strcpy() and skip the '\' escape character */
515                         s = zz[0];
516                         t = buf;
517
518                         while (*s)
519                         {
520                                 if ('\\' == *s) s++;
521                                 *t++ = *s++;
522                         }
523
524                         /* Terminate the trigger name */
525                         *t = '\0';
526
527                         /* Store the trigger name */
528                         macro_trigger_name[max_macrotrigger] = string_make(buf);
529
530                         /* Free the buffer */
531                         FREE(buf);
532
533                         /* Normal keycode */
534                         macro_trigger_keycode[0][max_macrotrigger] = string_make(zz[1]);
535
536                         /* Special shifted keycode */
537                         if (tok == 3)
538                         {
539                                 macro_trigger_keycode[1][max_macrotrigger] = string_make(zz[2]);
540                         }
541                         /* Shifted keycode is the same as the normal keycode */
542                         else
543                         {
544                                 macro_trigger_keycode[1][max_macrotrigger] = string_make(zz[1]);
545                         }
546
547                         /* Count triggers */
548                         max_macrotrigger++;
549                 }
550
551                 return 0;
552         }
553
554         /* Process "X:<str>" -- turn option off */
555         else if (buf[0] == 'X')
556         {
557                 /* Check non-adult options */
558                 for (i = 0; i < OPT_ADULT; i++)
559                 {
560                         if (option_name(i) && streq(option_name(i), buf + 2))
561                         {
562                                 option_set(i, FALSE);
563                                 return (0);
564                         }
565                 }
566
567                 /* Ignore unknown options */
568                 return (0);
569         }
570
571         /* Process "Y:<str>" -- turn option on */
572         else if (buf[0] == 'Y')
573         {
574                 /* Check non-adult options */
575                 for (i = 0; i < OPT_ADULT; i++)
576                 {
577                         if (option_name(i) && streq(option_name(i), buf + 2))
578                         {
579                                 option_set(i, TRUE);
580                                 return (0);
581                         }
582                 }
583
584                 /* Ignore unknown options */
585                 return (0);
586         }
587
588
589         /* Process "W:<win>:<flag>:<value>" -- window flags */
590         else if (buf[0] == 'W')
591         {
592                 long win, flag, value;
593
594                 if (tokenize(buf + 2, 3, zz) == 3)
595                 {
596                         win = strtol(zz[0], NULL, 0);
597                         flag = strtol(zz[1], NULL, 0);
598                         value = strtol(zz[2], NULL, 0);
599
600                         /* Ignore illegal windows */
601                         /* Hack -- Ignore the main window */
602                         if ((win <= 0) || (win >= ANGBAND_TERM_MAX)) return (1);
603
604                         /* Ignore illegal flags */
605                         if ((flag < 0) || (flag >= (int)N_ELEMENTS(window_flag_desc))) return (1);
606
607                         /* Require a real flag */
608                         if (window_flag_desc[flag])
609                         {
610                                 if (value)
611                                 {
612                                         /* Turn flag on */
613                                         op_ptr->window_flag[win] |= (1L << flag);
614                                 }
615                                 else
616                                 {
617                                         /* Turn flag off */
618                                         op_ptr->window_flag[win] &= ~(1L << flag);
619                                 }
620                         }
621
622                         /* Success */
623                         return (0);
624                 }
625         }
626
627
628         /* Process "M:<type>:<attr>" -- colors for message-types */
629         else if (buf[0] == 'M')
630         {
631                 if (tokenize(buf+2, 2, zz) == 2)
632                 {
633                         long type = strtol(zz[0], NULL, 0);
634                         int color = color_char_to_attr(zz[1][0]);
635
636                         /* Ignore illegal color */
637                         if (color < 0) return (1);
638
639                         /* Store the color */
640                         return (message_color_define((u16b)type, (byte)color));
641                 }
642         }
643
644
645         /* Failure */
646         return (1);
647 }
648
649
650 /*
651  * Helper function for "process_pref_file()"
652  *
653  * Input:
654  *   v: output buffer array
655  *   f: final character
656  *
657  * Output:
658  *   result
659  */
660 static cptr process_pref_file_expr(char **sp, char *fp)
661 {
662         cptr v;
663
664         char *b;
665         char *s;
666
667         char b1 = '[';
668         char b2 = ']';
669
670         char f = ' ';
671
672         /* Initial */
673         s = (*sp);
674
675         /* Skip spaces */
676         while (isspace((unsigned char)*s)) s++;
677
678         /* Save start */
679         b = s;
680
681         /* Default */
682         v = "?o?o?";
683
684         /* Analyze */
685         if (*s == b1)
686         {
687                 const char *p;
688                 const char *t;
689
690                 /* Skip b1 */
691                 s++;
692
693                 /* First */
694                 t = process_pref_file_expr(&s, &f);
695
696                 /* Oops */
697                 if (!*t)
698                 {
699                         /* Nothing */
700                 }
701
702                 /* Function: IOR */
703                 else if (streq(t, "IOR"))
704                 {
705                         v = "0";
706                         while (*s && (f != b2))
707                         {
708                                 t = process_pref_file_expr(&s, &f);
709                                 if (*t && !streq(t, "0")) v = "1";
710                         }
711                 }
712
713                 /* Function: AND */
714                 else if (streq(t, "AND"))
715                 {
716                         v = "1";
717                         while (*s && (f != b2))
718                         {
719                                 t = process_pref_file_expr(&s, &f);
720                                 if (*t && streq(t, "0")) v = "0";
721                         }
722                 }
723
724                 /* Function: NOT */
725                 else if (streq(t, "NOT"))
726                 {
727                         v = "1";
728                         while (*s && (f != b2))
729                         {
730                                 t = process_pref_file_expr(&s, &f);
731                                 if (*t && !streq(t, "0")) v = "0";
732                         }
733                 }
734
735                 /* Function: EQU */
736                 else if (streq(t, "EQU"))
737                 {
738                         v = "1";
739                         if (*s && (f != b2))
740                         {
741                                 t = process_pref_file_expr(&s, &f);
742                         }
743                         while (*s && (f != b2))
744                         {
745                                 p = t;
746                                 t = process_pref_file_expr(&s, &f);
747                                 if (*t && !streq(p, t)) v = "0";
748                         }
749                 }
750
751                 /* Function: LEQ */
752                 else if (streq(t, "LEQ"))
753                 {
754                         v = "1";
755                         if (*s && (f != b2))
756                         {
757                                 t = process_pref_file_expr(&s, &f);
758                         }
759                         while (*s && (f != b2))
760                         {
761                                 p = t;
762                                 t = process_pref_file_expr(&s, &f);
763                                 if (*t && (strcmp(p, t) >= 0)) v = "0";
764                         }
765                 }
766
767                 /* Function: GEQ */
768                 else if (streq(t, "GEQ"))
769                 {
770                         v = "1";
771                         if (*s && (f != b2))
772                         {
773                                 t = process_pref_file_expr(&s, &f);
774                         }
775                         while (*s && (f != b2))
776                         {
777                                 p = t;
778                                 t = process_pref_file_expr(&s, &f);
779                                 if (*t && (strcmp(p, t) <= 0)) v = "0";
780                         }
781                 }
782
783                 /* Oops */
784                 else
785                 {
786                         while (*s && (f != b2))
787                         {
788                                 t = process_pref_file_expr(&s, &f);
789                         }
790                 }
791
792                 /* Verify ending */
793                 if (f != b2) v = "?x?x?";
794
795                 /* Extract final and Terminate */
796                 if ((f = *s) != '\0') *s++ = '\0';
797         }
798
799         /* Other */
800         else
801         {
802                 /* Accept all printables except spaces and brackets */
803                 while (isprint((unsigned char)*s) && !strchr(" []", *s)) ++s;
804
805                 /* Extract final and Terminate */
806                 if ((f = *s) != '\0') *s++ = '\0';
807
808                 /* Variable */
809                 if (*b == '$')
810                 {
811                         /* System */
812                         if (streq(b+1, "SYS"))
813                         {
814                                 v = ANGBAND_SYS;
815                         }
816
817                         /* Graphics */
818                         else if (streq(b+1, "GRAF"))
819                         {
820