blob: 605cb01957535d7312160713a73dc0020f01b5ef [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) {
182 msg = convertitem(args, &format, &va, levels, msgbuf);
183 if (msg == NULL)
184 return 1;
185 seterror(levels[0], msg, levels+1, fname, message);
186 return 0;
187 }
188 else {
189 err_setstr(SystemError,
190 "old style getargs format uses new features");
191 return 0;
192 }
193 }
194
195 if (!is_tupleobject(args)) {
196 err_setstr(SystemError,
197 "new style getargs format but argument is not a tuple");
198 return 0;
199 }
200
201 len = gettuplesize(args);
202
203 if (len < min || max < len) {
204 if (message == NULL) {
205 sprintf(msgbuf,
206 "%s requires %s %d argument%s; %d given",
207 fname==NULL ? "function" : fname,
208 min==max ? "exactly"
209 : len < min ? "at least" : "at most",
210 len < min ? min : max,
211 (len < min ? min : max) == 1 ? "" : "s",
212 len);
213 message = msgbuf;
214 }
215 err_setstr(TypeError, message);
216 return 0;
217 }
218
219 for (i = 0; i < len; i++) {
220 if (*format == '|')
221 format++;
222 msg = convertitem(gettupleitem(args, i), &format, &va,
223 levels, msgbuf);
224 if (msg) {
225 seterror(i+1, msg, levels, fname, message);
226 return 0;
227 }
228 }
229
230 return 1;
231}
232
233
234
235static void
236seterror(iarg, msg, levels, fname, message)
237 int iarg;
238 char *msg;
239 int *levels;
240 char *fname;
241 char *message;
242{
243 char buf[256];
244 int i;
245 char *p = buf;
246
247 if (iarg == 0 && message == NULL)
248 message = msg;
249 else if (message == NULL) {
250 if (fname != NULL) {
251 sprintf(p, "%s, ", fname);
252 p += strlen(p);
253 }
254 sprintf(p, "argument %d", iarg);
255 i = 0;
256 p += strlen(p);
257 while (levels[i] > 0) {
258 sprintf(p, ", item %d", levels[i]-1);
259 p += strlen(p);
260 i++;
261 }
262 sprintf(p, ": expected %s found", msg);
263 message = buf;
264 }
265 err_setstr(TypeError, message);
266}
267
268
269/* Convert a tuple argument.
270 On entry, *p_format points to the character _after_ the opening '('.
271 On successful exit, *p_format points to the closing ')'.
272 If successful:
273 *p_format and *p_va are updated,
274 *levels and *msgbuf are untouched,
275 and NULL is returned.
276 If the argument is invalid:
277 *p_format is unchanged,
278 *p_va is undefined,
279 *levels is a 0-terminated list of item numbers,
280 *msgbuf contains an error message, whose format is:
281 "<typename1>, <typename2>", where:
282 <typename1> is the name of the expected type, and
283 <typename2> is the name of the actual type,
284 (so you can surround it by "expected ... found"),
285 and msgbuf is returned.
286*/
287
288static char *
289converttuple(arg, p_format, p_va, levels, msgbuf, toplevel)
290 object *arg;
291 char **p_format;
292 va_list *p_va;
293 int *levels;
294 char *msgbuf;
295 int toplevel;
296{
297 int level = 0;
298 int n = 0;
299 char *format = *p_format;
300 int i;
301
302 for (;;) {
303 int c = *format++;
304 if (c == '(') {
305 if (level == 0)
306 n++;
307 level++;
308 }
309 else if (c == ')') {
310 if (level == 0)
311 break;
312 level--;
313 }
314 else if (c == ':' || c == ';' || c == '\0')
315 break;
316 else if (level == 0 && isalpha(c))
317 n++;
318 }
319
320 if (!is_tupleobject(arg)) {
321 levels[0] = 0;
322 sprintf(msgbuf,
323 toplevel ? "%d arguments, %s" : "%d-tuple, %s",
324 n, arg == None ? "None" : arg->ob_type->tp_name);
325 return msgbuf;
326 }
327
328 if ((i = gettuplesize(arg)) != n) {
329 levels[0] = 0;
330 sprintf(msgbuf,
331 toplevel ? "%d arguments, %d" : "%d-tuple, %d-tuple",
332 n, i);
333 return msgbuf;
334 }
335
336 format = *p_format;
337 for (i = 0; i < n; i++) {
338 char *msg;
339 msg = convertitem(gettupleitem(arg, i), &format, p_va,
340 levels+1, msgbuf);
341 if (msg != NULL) {
342 levels[0] = i+1;
343 return msg;
344 }
345 }
346
347 *p_format = format;
348 return NULL;
349}
350
351
352/* Convert a single item. */
353
354static char *
355convertitem(arg, p_format, p_va, levels, msgbuf)
356 object *arg;
357 char **p_format;
358 va_list *p_va;
359 int *levels;
360 char *msgbuf;
361{
362 char *msg;
363 char *format = *p_format;
364
365 if (*format == '(' /* ')' */) {
366 format++;
367 msg = converttuple(arg, &format, p_va, levels, msgbuf, 0);
368 if (msg == NULL)
369 format++;
370 }
371 else {
372 msg = convertsimple(arg, &format, p_va, msgbuf);
373 if (msg != NULL)
374 levels[0] = 0;
375 }
376 if (msg == NULL)
377 *p_format = format;
378 return msg;
379}
380
381
382/* Convert a non-tuple argument. Adds to convertsimple1 functionality
383 by appending ", <actual argument type>" to error message. */
384
385static char *
386convertsimple(arg, p_format, p_va, msgbuf)
387 object *arg;
388 char **p_format;
389 va_list *p_va;
390 char *msgbuf;
391{
392 char *msg = convertsimple1(arg, p_format, p_va);
393 if (msg != NULL) {
394 sprintf(msgbuf, "%.50s, %.50s", msg,
395 arg == None ? "None" : arg->ob_type->tp_name);
396 msg = msgbuf;
397 }
398 return msg;
399}
400
401
402/* Convert a non-tuple argument. Return NULL if conversion went OK,
403 or a string representing the expected type if the conversion failed.
404 When failing, an exception may or may not have been raised.
405 Don't call if a tuple is expected. */
406
407static char *
408convertsimple1(arg, p_format, p_va)
409 object *arg;
410 char **p_format;
411 va_list *p_va;
412{
413 char *format = *p_format;
414 char c = *format++;
415
416 switch (c) {
417
418 case 'b': /* byte -- very short int */
419 {
420 char *p = va_arg(*p_va, char *);
421 long ival = getintvalue(arg);
422 if (ival == -1 && err_occurred())
423 return "integer<b>";
424 else
425 *p = ival;
426 break;
427 }
428
429 case 'h': /* short int */
430 {
431 short *p = va_arg(*p_va, short *);
432 long ival = getintvalue(arg);
433 if (ival == -1 && err_occurred())
434 return "integer<h>";
435 else
436 *p = ival;
437 break;
438 }
439
440 case 'i': /* int */
441 {
442 int *p = va_arg(*p_va, int *);
443 long ival = getintvalue(arg);
444 if (ival == -1 && err_occurred())
445 return "integer<i>";
446 else
447 *p = ival;
448 break;
449 }
450
451 case 'l': /* long int */
452 {
453 long *p = va_arg(*p_va, long *);
454 long ival = getintvalue(arg);
455 if (ival == -1 && err_occurred())
456 return "integer<l>";
457 else
458 *p = ival;
459 break;
460 }
461
462 case 'f': /* float */
463 {
464 float *p = va_arg(*p_va, float *);
465 double dval = getfloatvalue(arg);
466 if (err_occurred())
467 return "float<f>";
468 else
469 *p = dval;
470 break;
471 }
472
473 case 'd': /* double */
474 {
475 double *p = va_arg(*p_va, double *);
476 double dval = getfloatvalue(arg);
477 if (err_occurred())
478 return "float<d>";
479 else
480 *p = dval;
481 break;
482 }
483
484 case 'c': /* char */
485 {
486 char *p = va_arg(*p_va, char *);
487 if (is_stringobject(arg) && getstringsize(arg) == 1)
488 *p = getstringvalue(arg)[0];
489 else
490 return "char";
491 break;
492 }
493
494 case 's': /* string */
495 {
496 char **p = va_arg(*p_va, char **);
497 if (is_stringobject(arg))
498 *p = getstringvalue(arg);
499 else
500 return "string";
501 if (*format == '#') {
502 int *q = va_arg(*p_va, int *);
503 *q = getstringsize(arg);
504 format++;
505 }
506 else if (strlen(*p) != getstringsize(arg))
507 return "string without null bytes";
508 break;
509 }
510
511 case 'z': /* string, may be NULL (None) */
512 {
513 char **p = va_arg(*p_va, char **);
514 if (arg == None)
515 *p = 0;
516 else if (is_stringobject(arg))
517 *p = getstringvalue(arg);
518 else
519 return "None or string";
520 if (*format == '#') {
521 int *q = va_arg(*p_va, int *);
522 if (arg == None)
523 *q = 0;
524 else
525 *q = getstringsize(arg);
526 format++;
527 }
528 else if (*p != NULL && strlen(*p) != getstringsize(arg))
529 return "None or string without null bytes";
530 break;
531 }
532
533 case 'S': /* string object */
534 {
535 object **p = va_arg(*p_va, object **);
536 if (is_stringobject(arg))
537 *p = arg;
538 else
539 return "string";
540 break;
541 }
542
543 case 'O': /* object */
544 {
545 typeobject *type;
546 object **p;
547 if (*format == '!') {
548 format++;
549 type = va_arg(*p_va, typeobject*);
550 if (arg->ob_type != type)
551 return type->tp_name;
552 else {
553 p = va_arg(*p_va, object **);
554 *p = arg;
555 }
556 }
557 else if (*format == '?') {
558 inquiry pred = va_arg(*p_va, inquiry);
559 format++;
560 if ((*pred)(arg)) {
561 p = va_arg(*p_va, object **);
562 *p = arg;
563 }
564 }
565 else if (*format == '&') {
566 typedef int (*converter) PROTO((object *, void *));
567 converter convert = va_arg(*p_va, converter);
568 void *addr = va_arg(*p_va, void *);
569 format++;
570 if (! (*convert)(arg, addr))
571 return "";
572 }
573 else {
574 p = va_arg(*p_va, object **);
575 *p = arg;
576 }
577 break;
578 }
579
580 default:
581 return "impossible<bad format char>";
582
583 }
584
585 *p_format = format;
586 return NULL;
587}