blob: 15cd4e6ce482104cc8e778f9f9a5b78711b5cbb2 [file] [log] [blame]
Guido van Rossumfe3f1a21994-09-29 09:42:55 +00001/***********************************************************
2Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* New getargs implementation */
26
27/* XXX There are several unchecked sprintf or strcat calls in this file.
28 XXX The only way these can become a danger is if some C code in the
29 XXX Python source (or in an extension) uses ridiculously long names
30 XXX or riduculously deep nesting in format strings. */
31
32#include "allobjects.h"
33
34
35int getargs PROTO((object *, char *, ...));
36int newgetargs PROTO((object *, char *, ...));
37int vgetargs PROTO((object *, char *, va_list));
38
39
40/* Forward */
41static int vgetargs1 PROTO((object *, char *, va_list, int));
42static void seterror PROTO((int, char *, int *, char *, char *));
43static char *convertitem PROTO((object *, char **, va_list *, int *, char *));
44static char *converttuple PROTO((object *, char **, va_list *,
45 int *, char *, int));
46static char *convertsimple PROTO((object *, char **, va_list *, char *));
47static char *convertsimple1 PROTO((object *, char **, va_list *));
48
49
50#ifdef HAVE_STDARG_PROTOTYPES
51/* VARARGS2 */
52int getargs(object *args, char *format, ...)
53#else
54/* VARARGS */
55int getargs(va_alist) va_dcl
56#endif
57{
58 int retval;
59 va_list va;
60#ifdef HAVE_STDARG_PROTOTYPES
61
62 va_start(va, format);
63#else
64 object *args;
65 char *format;
66
67 va_start(va);
68 args = va_arg(va, object *);
69 format = va_arg(va, char *);
70#endif
71 retval = vgetargs1(args, format, va, 1);
72 va_end(va);
73 return retval;
74}
75
76
77#ifdef HAVE_STDARG_PROTOTYPES
78/* VARARGS2 */
79int newgetargs(object *args, char *format, ...)
80#else
81/* VARARGS */
82int newgetargs(va_alist) va_dcl
83#endif
84{
85 int retval;
86 va_list va;
87#ifdef HAVE_STDARG_PROTOTYPES
88
89 va_start(va, format);
90#else
91 object *args;
92 char *format;
93
94 va_start(va);
95 args = va_arg(va, object *);
96 format = va_arg(va, char *);
97#endif
98 retval = vgetargs1(args, format, va, 0);
99 va_end(va);
100 return retval;
101}
102
103
104int
105vgetargs(args, format, va)
106 object *args;
107 char *format;
108 va_list va;
109{
110 return vgetargs1(args, format, va, 0);
111}
112
113
114static int
115vgetargs1(args, format, va, compat)
116 object *args;
117 char *format;
118 va_list va;
119 int compat;
120{
121 char msgbuf[256];
122 int levels[32];
123 char *fname = NULL;
124 char *message = NULL;
125 int min = -1;
126 int max = 0;
127 int level = 0;
128 char *formatsave = format;
129 int i, len;
130 char *msg;
131
132 for (;;) {
133 int c = *format++;
134 if (c == '(' /* ')' */) {
135 if (level == 0)
136 max++;
137 level++;
138 }
139 else if (/* '(' */ c == ')') {
140 if (level == 0)
141 fatal(/* '(' */
142 "excess ')' in getargs format");
143 else
144 level--;
145 }
146 else if (c == '\0')
147 break;
148 else if (c == ':') {
149 fname = format;
150 break;
151 }
152 else if (c == ';') {
153 message = format;
154 break;
155 }
156 else if (level != 0)
157 ; /* Pass */
158 else if (isalpha(c))
159 max++;
160 else if (c == '|')
161 min = max;
162 }
163
164 if (level != 0)
165 fatal(/* '(' */ "missing ')' in getargs format");
166
167 if (min < 0)
168 min = max;
169
170 format = formatsave;
171
172 if (compat) {
173 if (max == 0) {
174 if (args == NULL)
175 return 1;
176 sprintf(msgbuf, "%s requires no arguments",
177 fname==NULL ? "function" : fname);
178 err_setstr(TypeError, msgbuf);
179 return 0;
180 }
181 else if (min == 1 && max == 1) {
Guido van Rossum13d0ed11994-11-10 22:35:48 +0000182 if (args == NULL) {
183 sprintf(msgbuf,
184 "%s requires at least one argument",
185 fname==NULL ? "function" : fname);
186 err_setstr(TypeError, msgbuf);
187 return 0;
188 }
Guido van Rossumfe3f1a21994-09-29 09:42:55 +0000189 msg = convertitem(args, &format, &va, levels, msgbuf);
190 if (msg == NULL)
191 return 1;
192 seterror(levels[0], msg, levels+1, fname, message);
193 return 0;
194 }
195 else {
196 err_setstr(SystemError,
197 "old style getargs format uses new features");
198 return 0;
199 }
200 }
201
202 if (!is_tupleobject(args)) {
203 err_setstr(SystemError,
204 "new style getargs format but argument is not a tuple");
205 return 0;
206 }
207
208 len = gettuplesize(args);
209
210 if (len < min || max < len) {
211 if (message == NULL) {
212 sprintf(msgbuf,
213 "%s requires %s %d argument%s; %d given",
214 fname==NULL ? "function" : fname,
215 min==max ? "exactly"
216 : len < min ? "at least" : "at most",
217 len < min ? min : max,
218 (len < min ? min : max) == 1 ? "" : "s",
219 len);
220 message = msgbuf;
221 }
222 err_setstr(TypeError, message);
223 return 0;
224 }
225
226 for (i = 0; i < len; i++) {
227 if (*format == '|')
228 format++;
229 msg = convertitem(gettupleitem(args, i), &format, &va,
230 levels, msgbuf);
231 if (msg) {
232 seterror(i+1, msg, levels, fname, message);
233 return 0;
234 }
235 }
236
237 return 1;
238}
239
240
241
242static void
243seterror(iarg, msg, levels, fname, message)
244 int iarg;
245 char *msg;
246 int *levels;
247 char *fname;
248 char *message;
249{
250 char buf[256];
251 int i;
252 char *p = buf;
253
254 if (iarg == 0 && message == NULL)
255 message = msg;
256 else if (message == NULL) {
257 if (fname != NULL) {
258 sprintf(p, "%s, ", fname);
259 p += strlen(p);
260 }
261 sprintf(p, "argument %d", iarg);
262 i = 0;
263 p += strlen(p);
264 while (levels[i] > 0) {
265 sprintf(p, ", item %d", levels[i]-1);
266 p += strlen(p);
267 i++;
268 }
269 sprintf(p, ": expected %s found", msg);
270 message = buf;
271 }
272 err_setstr(TypeError, message);
273}
274
275
276/* Convert a tuple argument.
277 On entry, *p_format points to the character _after_ the opening '('.
278 On successful exit, *p_format points to the closing ')'.
279 If successful:
280 *p_format and *p_va are updated,
281 *levels and *msgbuf are untouched,
282 and NULL is returned.
283 If the argument is invalid:
284 *p_format is unchanged,
285 *p_va is undefined,
286 *levels is a 0-terminated list of item numbers,
287 *msgbuf contains an error message, whose format is:
288 "<typename1>, <typename2>", where:
289 <typename1> is the name of the expected type, and
290 <typename2> is the name of the actual type,
291 (so you can surround it by "expected ... found"),
292 and msgbuf is returned.
293*/
294
295static char *
296converttuple(arg, p_format, p_va, levels, msgbuf, toplevel)
297 object *arg;
298 char **p_format;
299 va_list *p_va;
300 int *levels;
301 char *msgbuf;
302 int toplevel;
303{
304 int level = 0;
305 int n = 0;
306 char *format = *p_format;
307 int i;
308
309 for (;;) {
310 int c = *format++;
311 if (c == '(') {
312 if (level == 0)
313 n++;
314 level++;
315 }
316 else if (c == ')') {
317 if (level == 0)
318 break;
319 level--;
320 }
321 else if (c == ':' || c == ';' || c == '\0')
322 break;
323 else if (level == 0 && isalpha(c))
324 n++;
325 }
326
327 if (!is_tupleobject(arg)) {
328 levels[0] = 0;
329 sprintf(msgbuf,
330 toplevel ? "%d arguments, %s" : "%d-tuple, %s",
331 n, arg == None ? "None" : arg->ob_type->tp_name);
332 return msgbuf;
333 }
334
335 if ((i = gettuplesize(arg)) != n) {
336 levels[0] = 0;
337 sprintf(msgbuf,
338 toplevel ? "%d arguments, %d" : "%d-tuple, %d-tuple",
339 n, i);
340 return msgbuf;
341 }
342
343 format = *p_format;
344 for (i = 0; i < n; i++) {
345 char *msg;
346 msg = convertitem(gettupleitem(arg, i), &format, p_va,
347 levels+1, msgbuf);
348 if (msg != NULL) {
349 levels[0] = i+1;
350 return msg;
351 }
352 }
353
354 *p_format = format;
355 return NULL;
356}
357
358
359/* Convert a single item. */
360
361static char *
362convertitem(arg, p_format, p_va, levels, msgbuf)
363 object *arg;
364 char **p_format;
365 va_list *p_va;
366 int *levels;
367 char *msgbuf;
368{
369 char *msg;
370 char *format = *p_format;
371
372 if (*format == '(' /* ')' */) {
373 format++;
374 msg = converttuple(arg, &format, p_va, levels, msgbuf, 0);
375 if (msg == NULL)
376 format++;
377 }
378 else {
379 msg = convertsimple(arg, &format, p_va, msgbuf);
380 if (msg != NULL)
381 levels[0] = 0;
382 }
383 if (msg == NULL)
384 *p_format = format;
385 return msg;
386}
387
388
389/* Convert a non-tuple argument. Adds to convertsimple1 functionality
390 by appending ", <actual argument type>" to error message. */
391
392static char *
393convertsimple(arg, p_format, p_va, msgbuf)
394 object *arg;
395 char **p_format;
396 va_list *p_va;
397 char *msgbuf;
398{
399 char *msg = convertsimple1(arg, p_format, p_va);
400 if (msg != NULL) {
401 sprintf(msgbuf, "%.50s, %.50s", msg,
402 arg == None ? "None" : arg->ob_type->tp_name);
403 msg = msgbuf;
404 }
405 return msg;
406}
407
408
409/* Convert a non-tuple argument. Return NULL if conversion went OK,
410 or a string representing the expected type if the conversion failed.
411 When failing, an exception may or may not have been raised.
412 Don't call if a tuple is expected. */
413
414static char *
415convertsimple1(arg, p_format, p_va)
416 object *arg;
417 char **p_format;
418 va_list *p_va;
419{
420 char *format = *p_format;
421 char c = *format++;
422
423 switch (c) {
424
425 case 'b': /* byte -- very short int */
426 {
427 char *p = va_arg(*p_va, char *);
428 long ival = getintvalue(arg);
429 if (ival == -1 && err_occurred())
430 return "integer<b>";
431 else
432 *p = ival;
433 break;
434 }
435
436 case 'h': /* short int */
437 {
438 short *p = va_arg(*p_va, short *);
439 long ival = getintvalue(arg);
440 if (ival == -1 && err_occurred())
441 return "integer<h>";
442 else
443 *p = ival;
444 break;
445 }
446
447 case 'i': /* int */
448 {
449 int *p = va_arg(*p_va, int *);
450 long ival = getintvalue(arg);
451 if (ival == -1 && err_occurred())
452 return "integer<i>";
453 else
454 *p = ival;
455 break;
456 }
457
458 case 'l': /* long int */
459 {
460 long *p = va_arg(*p_va, long *);
461 long ival = getintvalue(arg);
462 if (ival == -1 && err_occurred())
463 return "integer<l>";
464 else
465 *p = ival;
466 break;
467 }
468
469 case 'f': /* float */
470 {
471 float *p = va_arg(*p_va, float *);
472 double dval = getfloatvalue(arg);
473 if (err_occurred())
474 return "float<f>";
475 else
476 *p = dval;
477 break;
478 }
479
480 case 'd': /* double */
481 {
482 double *p = va_arg(*p_va, double *);
483 double dval = getfloatvalue(arg);
484 if (err_occurred())
485 return "float<d>";
486 else
487 *p = dval;
488 break;
489 }
490
491 case 'c': /* char */
492 {
493 char *p = va_arg(*p_va, char *);
494 if (is_stringobject(arg) && getstringsize(arg) == 1)
495 *p = getstringvalue(arg)[0];
496 else
497 return "char";
498 break;
499 }
500
501 case 's': /* string */
502 {
503 char **p = va_arg(*p_va, char **);
504 if (is_stringobject(arg))
505 *p = getstringvalue(arg);
506 else
507 return "string";
508 if (*format == '#') {
509 int *q = va_arg(*p_va, int *);
510 *q = getstringsize(arg);
511 format++;
512 }
513 else if (strlen(*p) != getstringsize(arg))
514 return "string without null bytes";
515 break;
516 }
517
518 case 'z': /* string, may be NULL (None) */
519 {
520 char **p = va_arg(*p_va, char **);
521 if (arg == None)
522 *p = 0;
523 else if (is_stringobject(arg))
524 *p = getstringvalue(arg);
525 else
526 return "None or string";
527 if (*format == '#') {
528 int *q = va_arg(*p_va, int *);
529 if (arg == None)
530 *q = 0;
531 else
532 *q = getstringsize(arg);
533 format++;
534 }
535 else if (*p != NULL && strlen(*p) != getstringsize(arg))
536 return "None or string without null bytes";
537 break;
538 }
539
540 case 'S': /* string object */
541 {
542 object **p = va_arg(*p_va, object **);
543 if (is_stringobject(arg))
544 *p = arg;
545 else
546 return "string";
547 break;
548 }
549
550 case 'O': /* object */
551 {
552 typeobject *type;
553 object **p;
554 if (*format == '!') {
555 format++;
556 type = va_arg(*p_va, typeobject*);
557 if (arg->ob_type != type)
558 return type->tp_name;
559 else {
560 p = va_arg(*p_va, object **);
561 *p = arg;
562 }
563 }
564 else if (*format == '?') {
565 inquiry pred = va_arg(*p_va, inquiry);
566 format++;
567 if ((*pred)(arg)) {
568 p = va_arg(*p_va, object **);
569 *p = arg;
570 }
571 }
572 else if (*format == '&') {
573 typedef int (*converter) PROTO((object *, void *));
574 converter convert = va_arg(*p_va, converter);
575 void *addr = va_arg(*p_va, void *);
576 format++;
577 if (! (*convert)(arg, addr))
578 return "";
579 }
580 else {
581 p = va_arg(*p_va, object **);
582 *p = arg;
583 }
584 break;
585 }
586
587 default:
588 return "impossible<bad format char>";
589
590 }
591
592 *p_format = format;
593 return NULL;
594}