Add Bocfel interpreter
[projects/chimara/chimara.git] / interpreters / bocfel / util.c
1 /*-
2  * Copyright 2010-2012 Chris Spiegel.
3  *
4  * This file is part of Bocfel.
5  *
6  * Bocfel is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version
8  * 2 or 3, as published by the Free Software Foundation.
9  *
10  * Bocfel is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Bocfel.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdarg.h>
23
24 #include "util.h"
25 #include "screen.h"
26 #include "unicode.h"
27 #include "zterp.h"
28
29 #ifdef ZTERP_GLK
30 #include <glk.h>
31 #include <libchimara/garglk.h>
32 #endif
33
34 #ifndef ZTERP_NO_SAFETY_CHECKS
35 unsigned long zassert_pc;
36
37 void assert_fail(const char *fmt, ...)
38 {
39   va_list ap;
40   char str[1024];
41
42   va_start(ap, fmt);
43   vsnprintf(str, sizeof str, fmt, ap);
44   va_end(ap);
45
46   snprintf(str + strlen(str), sizeof str - strlen(str), " (pc = 0x%lx)", zassert_pc);
47
48   die("%s", str);
49 }
50 #endif
51
52 void warning(const char *fmt, ...)
53 {
54   va_list ap;
55   char str[1024];
56
57   va_start(ap, fmt);
58   vsnprintf(str, sizeof str, fmt, ap);
59   va_end(ap);
60
61   show_message("WARNING: %s", str);
62 }
63
64 void die(const char *fmt, ...)
65 {
66   va_list ap;
67   char str[1024];
68
69   va_start(ap, fmt);
70   vsnprintf(str, sizeof str, fmt, ap);
71   va_end(ap);
72
73   show_message("fatal error: %s", str);
74
75 #ifdef ZTERP_GLK
76 #ifdef GARGLK
77   fprintf(stderr, "%s\n", str);
78 #endif
79   glk_exit();
80 #endif
81
82   exit(EXIT_FAILURE);
83 }
84
85 /* This is not POSIX compliant, but it gets the job done.
86  * It should not be called more than once.
87  */
88 static int zoptind = 0;
89 static const char *zoptarg;
90 static int zgetopt(int argc, char **argv, const char *optstring)
91 {
92   static const char *p = "";
93   const char *optp;
94   int c;
95
96   if(*p == 0)
97   {
98     /* No more arguments. */
99     if(++zoptind >= argc) return -1;
100
101     p = argv[zoptind];
102
103     /* No more options. */
104     if(p[0] != '-' || p[1] == 0) return -1;
105
106     /* Handle “--” */
107     if(*++p == '-')
108     {
109       zoptind++;
110       return -1;
111     }
112   }
113
114   c = *p++;
115
116   optp = strchr(optstring, c);
117   if(optp == NULL) return '?';
118
119   if(optp[1] == ':')
120   {
121     if(*p != 0) zoptarg = p;
122     else        zoptarg = argv[++zoptind];
123
124     p = "";
125     if(zoptarg == NULL) return '?';
126   }
127
128   return c;
129 }
130
131 char *xstrdup(const char *s)
132 {
133   size_t n;
134   char *r;
135
136   n = strlen(s) + 1;
137
138   r = malloc(n);
139   if(r != NULL) memcpy(r, s, n);
140
141   return r;
142 }
143
144 int process_arguments(int argc, char **argv)
145 {
146   int c;
147
148   while( (c = zgetopt(argc, argv, "a:A:cCdDeE:fFgGiklLmn:N:rR:sS:tT:u:UvxXyz:Z:")) != -1 )
149   {
150     switch(c)
151     {
152       case 'a':
153         options.eval_stack_size = strtol(zoptarg, NULL, 10);
154         break;
155       case 'A':
156         options.call_stack_size = strtol(zoptarg, NULL, 10);
157         break;
158       case 'c':
159         options.disable_color = 1;
160         break;
161       case 'C':
162         options.disable_config = 1;
163         break;
164       case 'd':
165         options.disable_timed = 1;
166         break;
167       case 'D':
168         options.disable_sound = 1;
169         break;
170       case 'e':
171         options.enable_escape = 1;
172         break;
173       case 'E':
174         options.escape_string = xstrdup(zoptarg);
175         break;
176       case 'f':
177         options.disable_fixed = 1;
178         break;
179       case 'F':
180         options.assume_fixed = 1;
181         break;
182       case 'g':
183         options.disable_graphics_font = 1;
184         break;
185       case 'G':
186         options.enable_alt_graphics = 1;
187         break;
188       case 'i':
189         options.show_id = 1;
190         break;
191       case 'k':
192         options.disable_term_keys = 1;
193         break;
194       case 'l':
195         options.disable_utf8 = 1;
196         break;
197       case 'L':
198         options.force_utf8 = 1;
199         break;
200       case 'm':
201         options.disable_meta_commands = 1;
202         break;
203       case 'n':
204         options.int_number = strtol(zoptarg, NULL, 10);
205         break;
206       case 'N':
207         options.int_version = zoptarg[0];
208         break;
209       case 'r':
210         options.replay_on = 1;
211         break;
212       case 'R':
213         options.replay_name = xstrdup(zoptarg);
214         break;
215       case 's':
216         options.record_on = 1;
217         break;
218       case 'S':
219         options.record_name = xstrdup(zoptarg);
220         break;
221       case 't':
222         options.transcript_on = 1;
223         break;
224       case 'T':
225         options.transcript_name = xstrdup(zoptarg);
226         break;
227       case 'u':
228         options.max_saves = strtol(zoptarg, NULL, 10);
229         break;
230       case 'U':
231         options.disable_undo_compression = 1;
232         break;
233       case 'v':
234         options.show_version = 1;
235         break;
236       case 'x':
237         options.disable_abbreviations = 1;
238         break;
239       case 'X':
240         options.enable_censorship = 1;
241         break;
242       case 'y':
243         options.overwrite_transcript = 1;
244         break;
245       case 'z':
246         options.random_seed = strtol(zoptarg, NULL, 10);
247         break;
248       case 'Z':
249         options.random_device = xstrdup(zoptarg);
250         break;
251       default:
252         return 0;
253     }
254   }
255
256   /* Just ignore excess stories for now. */
257   if(zoptind < argc) game_file = argv[zoptind];
258
259   return 1;
260 }