1 /******************************************************************************
2 Copyright (c) 1995, 1996 Xerox Corporation. All rights reserved.
3 Portions of this code were written by Stephen White, aka ghond.
4 Use and copying of this software and preparation of derivative works based
5 upon this software are permitted. Any distribution of this software or
6 derivative works must comply with all applicable United States export
7 control laws. This software is made available AS IS, and Xerox Corporation
8 makes no warranty about the software, its performance or its conformity to
9 any specification. Any person obtaining a copy of this software is requested
10 to send their name and post office or electronic mail address to:
11 Pavel Curtis
12 Xerox PARC
13 3333 Coyote Hill Rd.
14 Palo Alto, CA 94304
15 Pavel@Xerox.Com
16 *****************************************************************************/
17
18 /*****************************************************************************
19 * Routines for use by non-DB modules with persistent state stored in the DB
20 *****************************************************************************/
21
22 #include "my-ctype.h"
23 #include <float.h>
24 #include "my-stdarg.h"
25 #include "my-stdio.h"
26 #include "my-stdlib.h"
27
28 #include "db_io.h"
29 #include "db_private.h"
30 #include "exceptions.h"
31 #include "list.h"
32 #include "log.h"
33 #include "numbers.h"
34 #include "parser.h"
35 #include "storage.h"
36 #include "streams.h"
37 #include "structures.h"
38 #include "str_intern.h"
39 #include "unparse.h"
40 #include "version.h"
41
42
43 /*********** Input ***********/
44
45 static FILE *input;
46
47 void
dbpriv_set_dbio_input(FILE * f)48 dbpriv_set_dbio_input(FILE * f)
49 {
50 input = f;
51 }
52
53 void
dbio_read_line(char * s,int n)54 dbio_read_line(char *s, int n)
55 {
56 fgets(s, n, input);
57 }
58
59 int
dbio_scanf(const char * format,...)60 dbio_scanf(const char *format,...)
61 {
62 va_list args;
63 int count;
64 const char *ptr;
65
66 va_start(args, format);
67 /* The following line would be nice, but unfortunately those darlings on
68 * the ANSI C committee apparently didn't feel it worthwhile to include
69 * support for functions wrapping `scanf' *even though* they included
70 * symmetric such support for functions wrapping `printf'. (*sigh*)
71 * Fortunately, we only use a small fraction of the full functionality of
72 * scanf in the server, so it's not unbearably unpleasant to have to
73 * reimplement it here.
74 */
75 /* count = vfscanf(input, format, args); */
76
77 count = 0;
78 for (ptr = format; *ptr; ptr++) {
79 int c, n, *ip;
80 unsigned *up;
81 char *cp;
82
83 if (isspace(*ptr)) {
84 do
85 c = fgetc(input);
86 while (isspace(c));
87 ungetc(c, input);
88 } else if (*ptr != '%') {
89 do
90 c = fgetc(input);
91 while (isspace(c));
92
93 if (c == EOF)
94 return count ? count : EOF;
95 else if (c != *ptr) {
96 ungetc(c, input);
97 return count;
98 }
99 } else
100 switch (*++ptr) {
101 case 'd':
102 ip = va_arg(args, int *);
103 n = fscanf(input, "%d", ip);
104 goto finish;
105 case 'u':
106 up = va_arg(args, unsigned *);
107 n = fscanf(input, "%u", up);
108 goto finish;
109 case 'c':
110 cp = va_arg(args, char *);
111 n = fscanf(input, "%c", cp);
112 finish:
113 if (n == 1)
114 count++;
115 else if (n == 0)
116 return count;
117 else /* n == EOF */
118 return count ? count : EOF;
119 break;
120 default:
121 panic("DBIO_SCANF: Unsupported directive!");
122 }
123 }
124
125 va_end(args);
126
127 return count;
128 }
129
130 int
dbio_read_num(void)131 dbio_read_num(void)
132 {
133 char s[20];
134 char *p;
135 int i;
136
137 fgets(s, 20, input);
138 i = strtol(s, &p, 10);
139 if (isspace(*s) || *p != '\n')
140 errlog("DBIO_READ_NUM: Bad number: \"%s\" at file pos. %ld\n",
141 s, ftell(input));
142 return i;
143 }
144
145 double
dbio_read_float(void)146 dbio_read_float(void)
147 {
148 char s[40];
149 char *p;
150 double d;
151
152 fgets(s, 40, input);
153 d = strtod(s, &p);
154 if (isspace(*s) || *p != '\n')
155 errlog("DBIO_READ_FLOAT: Bad number: \"%s\" at file pos. %ld\n",
156 s, ftell(input));
157 return d;
158 }
159
160 Objid
dbio_read_objid(void)161 dbio_read_objid(void)
162 {
163 return dbio_read_num();
164 }
165
166 const char *
dbio_read_string(void)167 dbio_read_string(void)
168 {
169 static Stream *str = 0;
170 static char buffer[1024];
171 int len, used_stream = 0;
172
173 if (str == 0)
174 str = new_stream(1024);
175
176 try_again:
177 fgets(buffer, sizeof(buffer), input);
178 len = strlen(buffer);
179 if (len == sizeof(buffer) - 1 && buffer[len - 1] != '\n') {
180 stream_add_string(str, buffer);
181 used_stream = 1;
182 goto try_again;
183 }
184 if (buffer[len - 1] == '\n')
185 buffer[len - 1] = '\0';
186
187 if (used_stream) {
188 stream_add_string(str, buffer);
189 return reset_stream(str);
190 } else
191 return buffer;
192 }
193
194 const char *
dbio_read_string_intern(void)195 dbio_read_string_intern(void)
196 {
197 const char *s, *r;
198
199 s = dbio_read_string();
200 r = str_intern(s);
201
202 /* puts(r); */
203
204 return r;
205 }
206
207
208 Var
dbio_read_var(void)209 dbio_read_var(void)
210 {
211 Var r;
212 int i, l = dbio_read_num();
213
214 if (l == (int) TYPE_ANY && dbio_input_version == DBV_Prehistory)
215 l = TYPE_NONE; /* Old encoding for VM's empty temp register
216 * and any as-yet unassigned variables.
217 */
218 r.type = (var_type) l;
219 switch (l) {
220 case TYPE_CLEAR:
221 case TYPE_NONE:
222 break;
223 case _TYPE_STR:
224 r.v.str = dbio_read_string_intern();
225 r.type |= TYPE_COMPLEX_FLAG;
226 break;
227 case TYPE_OBJ:
228 case TYPE_ERR:
229 case TYPE_INT:
230 case TYPE_CATCH:
231 case TYPE_FINALLY:
232 r.v.num = dbio_read_num();
233 break;
234 case _TYPE_FLOAT:
235 r = new_float(dbio_read_float());
236 break;
237 case _TYPE_LIST:
238 l = dbio_read_num();
239 r = new_list(l);
240 for (i = 0; i < l; i++)
241 r.v.list[i + 1] = dbio_read_var();
242 break;
243 default:
244 errlog("DBIO_READ_VAR: Unknown type (%d) at DB file pos. %ld\n",
245 l, ftell(input));
246 r = zero;
247 break;
248 }
249 return r;
250 }
251
252 struct state {
253 char prev_char;
254 const char *(*fmtr) (void *);
255 void *data;
256 };
257
258 static const char *
program_name(struct state * s)259 program_name(struct state *s)
260 {
261 if (!s->fmtr)
262 return s->data;
263 else
264 return (*s->fmtr) (s->data);
265 }
266
267 static void
my_error(void * data,const char * msg)268 my_error(void *data, const char *msg)
269 {
270 errlog("PARSER: Error in %s:\n", program_name(data));
271 errlog(" %s\n", msg);
272 }
273
274 static void
my_warning(void * data,const char * msg)275 my_warning(void *data, const char *msg)
276 {
277 oklog("PARSER: Warning in %s:\n", program_name(data));
278 oklog(" %s\n", msg);
279 }
280
281 static int
my_getc(void * data)282 my_getc(void *data)
283 {
284 struct state *s = data;
285 int c;
286
287 c = fgetc(input);
288 if (c == '.' && s->prev_char == '\n') {
289 /* end-of-verb marker in DB */
290 c = fgetc(input); /* skip next newline */
291 return EOF;
292 }
293 if (c == EOF)
294 my_error(data, "Unexpected EOF");
295 s->prev_char = c;
296 return c;
297 }
298
299 static Parser_Client parser_client =
300 {my_error, my_warning, my_getc};
301
302 Program *
dbio_read_program(DB_Version version,const char * (* fmtr)(void *),void * data)303 dbio_read_program(DB_Version version, const char *(*fmtr) (void *), void *data)
304 {
305 struct state s;
306
307 s.prev_char = '\n';
308 s.fmtr = fmtr;
309 s.data = data;
310 return parse_program(version, parser_client, &s);
311 }
312
313
314 /*********** Output ***********/
315
316 Exception dbpriv_dbio_failed;
317
318 static FILE *output;
319
320 void
dbpriv_set_dbio_output(FILE * f)321 dbpriv_set_dbio_output(FILE * f)
322 {
323 output = f;
324 }
325
326 void
dbio_printf(const char * format,...)327 dbio_printf(const char *format,...)
328 {
329 va_list args;
330
331 va_start(args, format);
332 if (vfprintf(output, format, args) < 0)
333 RAISE(dbpriv_dbio_failed, 0);
334 va_end(args);
335 }
336
337 void
dbio_write_num(int n)338 dbio_write_num(int n)
339 {
340 dbio_printf("%d\n", n);
341 }
342
343 void
dbio_write_float(double d)344 dbio_write_float(double d)
345 {
346 static const char *fmt = 0;
347 static char buffer[10];
348
349 if (!fmt) {
350 sprintf(buffer, "%%.%dg\n", DBL_DIG + 4);
351 fmt = buffer;
352 }
353 dbio_printf(fmt, d);
354 }
355
356 void
dbio_write_objid(Objid oid)357 dbio_write_objid(Objid oid)
358 {
359 dbio_write_num(oid);
360 }
361
362 void
dbio_write_string(const char * s)363 dbio_write_string(const char *s)
364 {
365 dbio_printf("%s\n", s ? s : "");
366 }
367
368 void
dbio_write_var(Var v)369 dbio_write_var(Var v)
370 {
371 int i;
372
373 dbio_write_num((int) v.type & TYPE_DB_MASK);
374 switch ((int) v.type) {
375 case TYPE_CLEAR:
376 case TYPE_NONE:
377 break;
378 case TYPE_STR:
379 dbio_write_string(v.v.str);
380 break;
381 case TYPE_OBJ:
382 case TYPE_ERR:
383 case TYPE_INT:
384 case TYPE_CATCH:
385 case TYPE_FINALLY:
386 dbio_write_num(v.v.num);
387 break;
388 case TYPE_FLOAT:
389 dbio_write_float(*v.v.fnum);
390 break;
391 case TYPE_LIST:
392 dbio_write_num(v.v.list[0].v.num);
393 for (i = 0; i < v.v.list[0].v.num; i++)
394 dbio_write_var(v.v.list[i + 1]);
395 break;
396 }
397 }
398
399 static void
receiver(void * data,const char * line)400 receiver(void *data, const char *line)
401 {
402 dbio_printf("%s\n", line);
403 }
404
405 void
dbio_write_program(Program * program)406 dbio_write_program(Program * program)
407 {
408 unparse_program(program, receiver, 0, 1, 0, MAIN_VECTOR);
409 dbio_printf(".\n");
410 }
411
412 void
dbio_write_forked_program(Program * program,int f_index)413 dbio_write_forked_program(Program * program, int f_index)
414 {
415 unparse_program(program, receiver, 0, 1, 0, f_index);
416 dbio_printf(".\n");
417 }
418
419 char rcsid_db_io[] = "$Id: db_io.c,v 1.5 1998/12/14 13:17:34 nop Exp $";
420
421 /*
422 * $Log: db_io.c,v $
423 * Revision 1.5 1998/12/14 13:17:34 nop
424 * Merge UNSAFE_OPTS (ref fixups); fix Log tag placement to fit CVS whims
425 *
426 * Revision 1.4 1998/02/19 07:36:16 nop
427 * Initial string interning during db load.
428 *
429 * Revision 1.3 1997/07/07 03:24:53 nop
430 * Merge UNSAFE_OPTS (r5) after extensive testing.
431 *
432 * Revision 1.2.2.1 1997/03/20 18:07:51 bjj
433 * Add a flag to the in-memory type identifier so that inlines can cheaply
434 * identify Vars that need actual work done to ref/free/dup them. Add the
435 * appropriate inlines to utils.h and replace old functions in utils.c with
436 * complex_* functions which only handle the types with external storage.
437 *
438 * Revision 1.2 1997/03/03 04:18:27 nop
439 * GNU Indent normalization
440 *
441 * Revision 1.1.1.1 1997/03/03 03:44:59 nop
442 * LambdaMOO 1.8.0p5
443 *
444 * Revision 2.5 1996/03/19 07:16:12 pavel
445 * Increased precision of floating-point numbers printed in the DB file.
446 * Release 1.8.0p2.
447 *
448 * Revision 2.4 1996/03/10 01:04:16 pavel
449 * Increased the precision of printed floating-point numbers by two digits.
450 * Release 1.8.0.
451 *
452 * Revision 2.3 1996/02/08 07:19:15 pavel
453 * Renamed err/logf() to errlog/oklog() and TYPE_NUM to TYPE_INT. Added
454 * dbio_read/write_float(). Updated copyright notice for 1996.
455 * Release 1.8.0beta1.
456 *
457 * Revision 2.2 1995/12/28 00:44:51 pavel
458 * Added support for receiving MOO-compilation warnings during loading and for
459 * printing useful error and warning messages in the log.
460 * Release 1.8.0alpha3.
461 *
462 * Revision 2.1 1995/12/11 07:59:50 pavel
463 * Fixed broken #includes. Removed another silly use of `unsigned'.
464 *
465 * Release 1.8.0alpha2.
466 *
467 * Revision 2.0 1995/11/30 04:20:10 pavel
468 * New baseline version, corresponding to release 1.8.0alpha1.
469 *
470 * Revision 1.1 1995/11/30 04:19:56 pavel
471 * Initial revision
472 */
473