Mercurial > hg > xemacs-beta
comparison src/doprnt.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 9ee227acff29 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* Output like sprintf to a buffer of specified size. | |
2 Also takes args differently: pass one pointer to an array of strings | |
3 in addition to the format string which is separate. | |
4 Copyright (C) 1995 Free Software Foundation, Inc. | |
5 Rewritten by mly to use varargs.h. | |
6 Rewritten from scratch by Ben Wing (February 1995) for Mule; expanded | |
7 to full printf spec. | |
8 | |
9 This file is part of XEmacs. | |
10 | |
11 XEmacs is free software; you can redistribute it and/or modify it | |
12 under the terms of the GNU General Public License as published by the | |
13 Free Software Foundation; either version 2, or (at your option) any | |
14 later version. | |
15 | |
16 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
19 for more details. | |
20 | |
21 You should have received a copy of the GNU General Public License | |
22 along with XEmacs; see the file COPYING. If not, write to | |
23 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 Boston, MA 02111-1307, USA. */ | |
25 | |
26 /* Synched up with: Rewritten. Not in FSF. */ | |
27 | |
28 #include <config.h> | |
29 #include "lisp.h" | |
30 | |
31 #include "buffer.h" | |
32 #include "lstream.h" | |
33 | |
34 static CONST char *valid_flags = "-+ #0"; | |
35 | |
36 static CONST char *valid_converters = "diouxXfeEgGcsS"; | |
37 static CONST char *int_converters = "dic"; | |
38 static CONST char *unsigned_int_converters = "ouxX"; | |
39 static CONST char *double_converters = "feEgG"; | |
40 static CONST char *string_converters = "sS"; | |
41 | |
42 struct printf_spec | |
43 { | |
44 int argnum; /* which argument does this spec want? This is one-based: | |
45 The first argument given is numbered 1, the second | |
46 is 2, etc. This is to handle %##$x-type specs. */ | |
47 int minwidth; | |
48 int precision; | |
49 int minus_flag:1; | |
50 int plus_flag:1; | |
51 int space_flag:1; | |
52 int number_flag:1; | |
53 int zero_flag:1; | |
54 int h_flag:1; | |
55 int l_flag:1; | |
56 char converter; /* converter character or 0 for dummy marker | |
57 indicating literal text at the end of the | |
58 specification */ | |
59 Bytecount text_before; /* position of the first character of the | |
60 block of literal text before this spec */ | |
61 Bytecount text_before_len; /* length of that text */ | |
62 }; | |
63 | |
64 union printf_arg | |
65 { | |
66 int i; | |
67 unsigned int ui; | |
68 long l; | |
69 unsigned long ul; | |
70 double d; | |
71 Bufbyte *bp; | |
72 }; | |
73 | |
74 /* We maintain a list of all the % specs in the specification, | |
75 along with the offset and length of the block of literal text | |
76 before each spec. In addition, we have a "dummy" spec that | |
77 represents all the literal text at the end of the specification. | |
78 Its converter is 0. */ | |
79 | |
80 typedef struct | |
81 { | |
82 Dynarr_declare (struct printf_spec); | |
83 } printf_spec_dynarr; | |
84 | |
85 typedef struct | |
86 { | |
87 Dynarr_declare (union printf_arg); | |
88 } printf_arg_dynarr; | |
89 | |
90 /* Append STRING (of length LEN) to STREAM. MINLEN is the minimum field | |
91 width. If MINUS_FLAG is set, left-justify the string in its field; | |
92 otherwise, right-justify. If ZERO_FLAG is set, pad with 0's; otherwise | |
93 pad with spaces. If MAXLEN is non-negative, the string is first | |
94 truncated to that many character. | |
95 | |
96 Note that MINLEN and MAXLEN are Charcounts but LEN is a Bytecount. */ | |
97 | |
98 static void | |
99 doprnt_1 (Lisp_Object stream, CONST Bufbyte *string, Bytecount len, | |
100 Charcount minlen, Charcount maxlen, int minus_flag, int zero_flag) | |
101 { | |
102 Charcount cclen; | |
103 Bufbyte pad; | |
104 Lstream *lstr = XLSTREAM (stream); | |
105 | |
106 cclen = bytecount_to_charcount (string, len); | |
107 | |
108 if (zero_flag) | |
109 pad = '0'; | |
110 else | |
111 pad = ' '; | |
112 | |
113 /* Padding at beginning to right-justify ... */ | |
114 if (minlen > cclen && !minus_flag) | |
115 { | |
116 int to_add = minlen - cclen; | |
117 while (to_add > 0) | |
118 { | |
119 Lstream_putc (lstr, pad); | |
120 to_add--; | |
121 } | |
122 } | |
123 | |
124 if (maxlen >= 0) | |
125 len = charcount_to_bytecount (string, min (maxlen, cclen)); | |
126 Lstream_write (lstr, string, len); | |
127 | |
128 /* Padding at end to left-justify ... */ | |
129 if (minlen > cclen && minus_flag) | |
130 { | |
131 int to_add = minlen - cclen; | |
132 while (to_add > 0) | |
133 { | |
134 Lstream_putc (lstr, pad); | |
135 to_add--; | |
136 } | |
137 } | |
138 } | |
139 | |
140 static CONST Bufbyte * | |
141 parse_off_posnum (CONST Bufbyte *start, CONST Bufbyte *end, int *returned_num) | |
142 { | |
143 Bufbyte arg_convert[100]; | |
144 REGISTER Bufbyte *arg_ptr = arg_convert; | |
145 | |
146 *returned_num = -1; | |
147 while (start != end && isdigit (*start)) | |
148 { | |
149 if (arg_ptr - arg_convert >= sizeof (arg_convert) - 1) | |
150 error ("Format converter number too large"); | |
151 *arg_ptr++ = *start++; | |
152 } | |
153 *arg_ptr = '\0'; | |
154 if (arg_convert != arg_ptr) | |
155 *returned_num = atoi ((char *) arg_convert); | |
156 return start; | |
157 } | |
158 | |
159 #define NEXT_ASCII_BYTE(ch) \ | |
160 do { \ | |
161 if (fmt == fmt_end) \ | |
162 error ("Premature end of format string"); \ | |
163 ch = *fmt; \ | |
164 if (ch >= 0200) \ | |
165 error ("Non-ASCII character in format converter spec"); \ | |
166 fmt++; \ | |
167 } while (0) | |
168 | |
169 static printf_spec_dynarr * | |
170 parse_doprnt_spec (CONST Bufbyte *format, Bytecount format_length) | |
171 { | |
172 CONST Bufbyte *fmt = format; | |
173 CONST Bufbyte *fmt_end = format + format_length; | |
174 printf_spec_dynarr *specs = Dynarr_new (struct printf_spec); | |
175 int prev_argnum = 0; | |
176 | |
177 while (1) | |
178 { | |
179 struct printf_spec spec; | |
180 CONST Bufbyte *text_end; | |
181 Bufbyte ch; | |
182 | |
183 memset (&spec, 0, sizeof (spec)); | |
184 if (fmt == fmt_end) | |
185 return specs; | |
186 text_end = (Bufbyte *) memchr (fmt, '%', fmt_end - fmt); | |
187 if (!text_end) | |
188 text_end = fmt_end; | |
189 spec.text_before = fmt - format; | |
190 spec.text_before_len = text_end - fmt; | |
191 fmt = text_end; | |
192 if (fmt != fmt_end) | |
193 { | |
194 fmt++; /* skip over % */ | |
195 | |
196 /* A % is special -- no arg number. According to ANSI specs, | |
197 field width does not apply to %% conversion. */ | |
198 if (fmt != fmt_end && *fmt == '%') | |
199 { | |
200 spec.converter = '%'; | |
201 Dynarr_add (specs, spec); | |
202 fmt++; | |
203 continue; | |
204 } | |
205 | |
206 /* Is there a field number specifier? */ | |
207 { | |
208 CONST Bufbyte *ptr; | |
209 int fieldspec; | |
210 | |
211 ptr = parse_off_posnum (fmt, fmt_end, &fieldspec); | |
212 if (fieldspec > 0 && ptr != fmt_end && *ptr == '$') | |
213 { | |
214 /* There is a format specifier */ | |
215 prev_argnum = fieldspec; | |
216 fmt = ptr + 1; | |
217 } | |
218 else | |
219 prev_argnum++; | |
220 spec.argnum = prev_argnum; | |
221 } | |
222 | |
223 /* Parse off any flags */ | |
224 NEXT_ASCII_BYTE (ch); | |
225 while (strchr (valid_flags, ch)) | |
226 { | |
227 switch (ch) | |
228 { | |
229 case '-': spec.minus_flag = 1; break; | |
230 case '+': spec.plus_flag = 1; break; | |
231 case ' ': spec.space_flag = 1; break; | |
232 case '#': spec.number_flag = 1; break; | |
233 case '0': spec.zero_flag = 1; break; | |
234 default: abort (); | |
235 } | |
236 NEXT_ASCII_BYTE (ch); | |
237 } | |
238 | |
239 /* Parse off the minimum field width */ | |
240 fmt--; /* back up */ | |
241 fmt = parse_off_posnum (fmt, fmt_end, &spec.minwidth); | |
242 if (spec.minwidth == -1) | |
243 spec.minwidth = 0; | |
244 | |
245 /* Parse off any precision specified */ | |
246 NEXT_ASCII_BYTE (ch); | |
247 if (ch == '.') | |
248 { | |
249 fmt = parse_off_posnum (fmt, fmt_end, &spec.precision); | |
250 if (spec.precision == -1) | |
251 spec.precision = 0; | |
252 NEXT_ASCII_BYTE (ch); | |
253 } | |
254 else | |
255 /* No precision specified */ | |
256 spec.precision = -1; | |
257 | |
258 /* Parse off h or l flag */ | |
259 if (ch == 'h' || ch == 'l') | |
260 { | |
261 if (ch == 'h') | |
262 spec.h_flag = 1; | |
263 else | |
264 spec.l_flag = 1; | |
265 NEXT_ASCII_BYTE (ch); | |
266 } | |
267 | |
268 if (!strchr (valid_converters, ch)) | |
269 error ("Invalid converter character %c", ch); | |
270 spec.converter = ch; | |
271 } | |
272 | |
273 if (spec.space_flag && spec.plus_flag) | |
274 spec.space_flag = 0; | |
275 if (spec.zero_flag && spec.space_flag) | |
276 spec.zero_flag = 0; | |
277 | |
278 Dynarr_add (specs, spec); | |
279 } | |
280 | |
281 RETURN_NOT_REACHED(specs) /* suppress compiler warning */ | |
282 } | |
283 | |
284 static int | |
285 get_args_needed (printf_spec_dynarr *specs) | |
286 { | |
287 int args_needed = 0; | |
288 REGISTER int i; | |
289 | |
290 /* Figure out how many args are needed. This may be less than | |
291 the number of specs because a spec could be %% or could be | |
292 missing (literal text at end of format string) or there | |
293 could be specs where the field number is explicitly given. | |
294 We just look for the maximum argument number that's referenced. */ | |
295 | |
296 for (i = 0; i < Dynarr_length (specs); i++) | |
297 { | |
298 char ch = Dynarr_at (specs, i).converter; | |
299 if (ch && ch != '%') | |
300 { | |
301 int argnum = Dynarr_at (specs, i).argnum; | |
302 if (argnum > args_needed) | |
303 args_needed = argnum; | |
304 } | |
305 } | |
306 | |
307 return args_needed; | |
308 } | |
309 | |
310 static printf_arg_dynarr * | |
311 get_doprnt_args (printf_spec_dynarr *specs, va_list vargs) | |
312 { | |
313 printf_arg_dynarr *args = Dynarr_new (union printf_arg); | |
314 union printf_arg arg; | |
315 REGISTER int i; | |
316 int args_needed = get_args_needed (specs); | |
317 | |
318 memset (&arg, 0, sizeof (union printf_arg)); | |
319 for (i = 1; i <= args_needed; i++) | |
320 { | |
321 int j; | |
322 char ch; | |
323 struct printf_spec *spec = 0; | |
324 | |
325 for (j = 0; j < Dynarr_length (specs); j++) | |
326 { | |
327 spec = Dynarr_atp (specs, j); | |
328 if (spec->argnum == i) | |
329 break; | |
330 } | |
331 | |
332 if (j == Dynarr_length (specs)) | |
333 error ("No conversion spec for argument %d", i); | |
334 | |
335 ch = spec->converter; | |
336 | |
337 /* int even if ch == 'c': "the type used in va_arg is supposed to | |
338 match the actual type **after default promotions**." */ | |
339 | |
340 if (strchr (int_converters, ch)) | |
341 { | |
342 if (spec->h_flag) | |
343 arg.i = va_arg (vargs, short); | |
344 else if (spec->l_flag) | |
345 arg.l = va_arg (vargs, long); | |
346 else | |
347 arg.i = va_arg (vargs, int); | |
348 } | |
349 else if (strchr (unsigned_int_converters, ch)) | |
350 { | |
351 if (spec->h_flag) | |
352 arg.ui = va_arg (vargs, unsigned short); | |
353 else if (spec->l_flag) | |
354 arg.ul = va_arg (vargs, unsigned long); | |
355 else | |
356 arg.ui = va_arg (vargs, unsigned int); | |
357 } | |
358 else if (strchr (double_converters, ch)) | |
359 arg.d = va_arg (vargs, double); | |
360 else if (strchr (string_converters, ch)) | |
361 arg.bp = va_arg (vargs, Bufbyte *); | |
362 else abort (); | |
363 | |
364 Dynarr_add (args, arg); | |
365 } | |
366 | |
367 return args; | |
368 } | |
369 | |
370 /* Generate output from a format-spec FORMAT, of length FORMAT_LENGTH. | |
371 Output goes in BUFFER, which has room for BUFSIZE bytes. | |
372 If the output does not fit, truncate it to fit. | |
373 Returns the number of bytes stored into BUFFER. | |
374 LARGS or VARGS points to the arguments, and NARGS says how many. | |
375 if LARGS is non-zero, it should be a pointer to NARGS worth of | |
376 Lisp arguments. Otherwise, VARGS should be a va_list referring | |
377 to the arguments. */ | |
378 | |
379 static Bytecount | |
380 emacs_doprnt_1 (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
381 Lisp_Object format_reloc, Bytecount format_length, | |
382 int nargs, | |
383 /* #### Gag me, gag me, gag me */ | |
384 CONST Lisp_Object *largs, va_list vargs) | |
385 { | |
386 printf_spec_dynarr *specs = 0; | |
387 printf_arg_dynarr *args = 0; | |
388 REGISTER int i; | |
389 int init_byte_count = Lstream_byte_count (XLSTREAM (stream)); | |
390 | |
391 if (!NILP (format_reloc)) | |
392 { | |
393 format_nonreloc = string_data (XSTRING (format_reloc)); | |
394 format_length = string_length (XSTRING (format_reloc)); | |
395 } | |
396 if (format_length < 0) | |
397 format_length = (Bytecount) strlen ((CONST char *) format_nonreloc); | |
398 | |
399 specs = parse_doprnt_spec (format_nonreloc, format_length); | |
400 if (largs) | |
401 { | |
402 /* allow too many args for string, but not too few */ | |
403 if (nargs < get_args_needed (specs)) | |
404 signal_error (Qwrong_number_of_arguments, | |
405 list3 (Qformat, | |
406 make_int (nargs), | |
407 !NILP (format_reloc) ? format_reloc : | |
408 make_string (format_nonreloc, format_length))); | |
409 } | |
410 else | |
411 { | |
412 args = get_doprnt_args (specs, vargs); | |
413 } | |
414 | |
415 for (i = 0; i < Dynarr_length (specs); i++) | |
416 { | |
417 struct printf_spec *spec = Dynarr_atp (specs, i); | |
418 char ch; | |
419 | |
420 /* Copy the text before */ | |
421 if (!NILP (format_reloc)) /* refetch in case of GC below */ | |
422 format_nonreloc = string_data (XSTRING (format_reloc)); | |
423 doprnt_1 (stream, format_nonreloc + spec->text_before, | |
424 spec->text_before_len, 0, -1, 0, 0); | |
425 | |
426 ch = spec->converter; | |
427 | |
428 if (!ch) | |
429 continue; | |
430 | |
431 if (ch == '%') | |
432 { | |
433 doprnt_1 (stream, (Bufbyte *) &ch, 1, 0, -1, 0, 0); | |
434 continue; | |
435 } | |
436 | |
437 if (largs && (spec->argnum < 1 || spec->argnum > nargs)) | |
438 error ("Invalid repositioning argument %d", spec->argnum); | |
439 | |
440 else if (ch == 'S' || ch == 's') | |
441 { | |
442 Bufbyte *string; | |
443 Bytecount string_len; | |
444 | |
445 if (!largs) | |
446 { | |
447 string = Dynarr_at (args, spec->argnum - 1).bp; | |
448 string_len = strlen ((char *) string); | |
449 } | |
450 else | |
451 { | |
452 Lisp_Object obj = largs[spec->argnum - 1]; | |
453 struct Lisp_String *ls; | |
454 | |
455 if (ch == 'S') | |
456 { | |
457 /* For `S', prin1 the argument and then treat like | |
458 a string. */ | |
459 ls = XSTRING (Fprin1_to_string (obj, Qnil)); | |
460 } | |
461 else if (STRINGP (obj)) | |
462 ls = XSTRING (obj); | |
463 else if (SYMBOLP (obj)) | |
464 ls = XSYMBOL (obj)->name; | |
465 else | |
466 { | |
467 /* convert to string using princ. */ | |
468 ls = XSTRING (Fprin1_to_string (obj, Qt)); | |
469 } | |
470 string = string_data (ls); | |
471 string_len = string_length (ls); | |
472 } | |
473 | |
474 doprnt_1 (stream, string, string_len, spec->minwidth, | |
475 spec->precision, spec->minus_flag, spec->zero_flag); | |
476 } | |
477 | |
478 else | |
479 { | |
480 /* Must be a number. */ | |
481 union printf_arg arg; | |
482 | |
483 if (!largs) | |
484 { | |
485 arg = Dynarr_at (args, spec->argnum - 1); | |
486 } | |
487 else | |
488 { | |
489 Lisp_Object obj = largs[spec->argnum - 1]; | |
490 if (!INT_OR_FLOATP (obj)) | |
491 { | |
492 error ("format specifier %%%c doesn't match argument type", | |
493 ch); | |
494 } | |
495 else if (strchr (double_converters, ch)) | |
496 arg.d = XFLOATINT (obj); | |
497 else | |
498 { | |
499 int val; | |
500 | |
501 if (FLOATP (obj)) | |
502 val = XINT (Ftruncate (obj)); | |
503 else | |
504 val = XINT (obj); | |
505 if (strchr (unsigned_int_converters, ch)) | |
506 { | |
507 if (spec->l_flag) | |
508 arg.ul = (unsigned long) val; | |
509 else | |
510 arg.ui = (unsigned int) val; | |
511 } | |
512 else | |
513 { | |
514 if (spec->l_flag) | |
515 arg.l = (long) val; | |
516 else | |
517 arg.i = val; | |
518 } | |
519 } | |
520 } | |
521 | |
522 | |
523 if (ch == 'c') | |
524 { | |
525 Emchar a; | |
526 Bytecount charlen; | |
527 Bufbyte charbuf[MAX_EMCHAR_LEN]; | |
528 | |
529 if (spec->l_flag) | |
530 a = (Emchar) arg.l; | |
531 else | |
532 a = (Emchar) arg.i; | |
533 | |
534 if (!valid_char_p (a)) | |
535 error ("invalid character value %d to %%c spec", a); | |
536 | |
537 charlen = set_charptr_emchar (charbuf, a); | |
538 doprnt_1 (stream, charbuf, charlen, spec->minwidth, | |
539 -1, spec->minus_flag, spec->zero_flag); | |
540 } | |
541 | |
542 else | |
543 { | |
544 char text_to_print[500]; | |
545 char constructed_spec[100]; | |
546 | |
547 /* Partially reconstruct the spec and use sprintf() to | |
548 format the string. */ | |
549 | |
550 /* Make sure nothing stupid happens */ | |
551 /* DO NOT REMOVE THE (int) CAST! Incorrect results will | |
552 follow! */ | |
553 spec->precision = min (spec->precision, | |
554 (int) (sizeof (text_to_print) - 50)); | |
555 | |
556 constructed_spec[0] = 0; | |
557 strcat (constructed_spec, "%"); | |
558 if (spec->plus_flag) | |
559 strcat (constructed_spec, "+"); | |
560 if (spec->space_flag) | |
561 strcat (constructed_spec, " "); | |
562 if (spec->number_flag) | |
563 strcat (constructed_spec, "#"); | |
564 if (spec->precision >= 0) | |
565 { | |
566 strcat (constructed_spec, "."); | |
567 sprintf (constructed_spec + strlen (constructed_spec), "%d", | |
568 spec->precision); | |
569 } | |
570 sprintf (constructed_spec + strlen (constructed_spec), "%c", ch); | |
571 | |
572 /* sprintf the mofo */ | |
573 /* we have to use separate calls to sprintf(), rather than | |
574 a single big conditional, because of the different types | |
575 of the arguments */ | |
576 if (strchr (double_converters, ch)) | |
577 sprintf (text_to_print, constructed_spec, arg.d); | |
578 else if (strchr (unsigned_int_converters, ch)) | |
579 { | |
580 if (spec->l_flag) | |
581 sprintf (text_to_print, constructed_spec, arg.ul); | |
582 else | |
583 sprintf (text_to_print, constructed_spec, arg.ui); | |
584 } | |
585 else | |
586 { | |
587 if (spec->l_flag) | |
588 sprintf (text_to_print, constructed_spec, arg.l); | |
589 else | |
590 sprintf (text_to_print, constructed_spec, arg.i); | |
591 } | |
592 | |
593 doprnt_1 (stream, (Bufbyte *) text_to_print, | |
594 strlen (text_to_print), | |
595 spec->minwidth, -1, spec->minus_flag, spec->zero_flag); | |
596 } | |
597 } | |
598 } | |
599 | |
600 /* #### will not get freed if error */ | |
601 if (specs) | |
602 Dynarr_free (specs); | |
603 if (args) | |
604 Dynarr_free (args); | |
605 return Lstream_byte_count (XLSTREAM (stream)) - init_byte_count; | |
606 } | |
607 | |
608 /* You really don't want to know why this is necessary... */ | |
609 static Bytecount | |
610 emacs_doprnt_2 (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
611 Lisp_Object format_reloc, Bytecount format_length, int nargs, | |
612 CONST Lisp_Object *largs, ...) | |
613 { | |
614 va_list vargs; | |
615 Bytecount val; | |
616 va_start (vargs, largs); | |
617 val = emacs_doprnt_1 (stream, format_nonreloc, format_reloc, | |
618 format_length, nargs, largs, vargs); | |
619 va_end (vargs); | |
620 return val; | |
621 } | |
622 | |
623 /*********************** external entry points ***********************/ | |
624 | |
625 #ifdef I18N3 | |
626 /* A note about I18N3 translating: the format string should get | |
627 translated, but not under all circumstances. When the format | |
628 string is a Lisp string, what should happen is that Fformat() | |
629 should format the untranslated args[0] and return that, and also | |
630 call Fgettext() on args[0] and, if that is different, format it | |
631 and store it in the `string-translatable' property of | |
632 the returned string. See Fgettext(). */ | |
633 #endif | |
634 | |
635 /* Send formatted output to STREAM. The format string comes from | |
636 either FORMAT_NONRELOC (of length FORMAT_LENGTH; -1 means use | |
637 strlen() to determine the length) or from FORMAT_RELOC, which | |
638 should be a Lisp string. Return the number of bytes written | |
639 to the stream. | |
640 | |
641 DO NOT pass the data from a Lisp string as the FORMAT_NONRELOC | |
642 parameter, because this function can cause GC. */ | |
643 | |
644 Bytecount | |
645 emacs_doprnt_c (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
646 Lisp_Object format_reloc, Bytecount format_length, | |
647 ...) | |
648 { | |
649 int val; | |
650 va_list vargs; | |
651 | |
652 va_start (vargs, format_length); | |
653 val = emacs_doprnt_1 (stream, format_nonreloc, format_reloc, | |
654 format_length, 0, 0, vargs); | |
655 va_end (vargs); | |
656 return val; | |
657 } | |
658 | |
659 /* Like emacs_doprnt_c but the args come in va_list format. */ | |
660 | |
661 Bytecount | |
662 emacs_doprnt_va (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
663 Lisp_Object format_reloc, Bytecount format_length, | |
664 va_list vargs) | |
665 { | |
666 return emacs_doprnt_1 (stream, format_nonreloc, format_reloc, | |
667 format_length, 0, 0, vargs); | |
668 } | |
669 | |
670 /* Like emacs_doprnt_c but the args are Lisp objects instead of | |
671 C arguments. This causes somewhat different behavior from | |
672 the above two functions (which should act like printf). | |
673 See `format' for a description of this behavior. */ | |
674 | |
675 Bytecount | |
676 emacs_doprnt_lisp (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
677 Lisp_Object format_reloc, Bytecount format_length, | |
678 int nargs, CONST Lisp_Object *largs) | |
679 { | |
680 return emacs_doprnt_2 (stream, format_nonreloc, format_reloc, | |
681 format_length, nargs, largs); | |
682 } | |
683 | |
684 /* Like the previous function but takes a variable number of arguments. */ | |
685 | |
686 Bytecount | |
687 emacs_doprnt_lisp_2 (Lisp_Object stream, CONST Bufbyte *format_nonreloc, | |
688 Lisp_Object format_reloc, Bytecount format_length, | |
689 int nargs, ...) | |
690 { | |
691 Lisp_Object *foo; | |
692 va_list vargs; | |
693 int i; | |
694 | |
695 foo = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object)); | |
696 va_start (vargs, nargs); | |
697 for (i = 0; i < nargs; i++) | |
698 foo[i] = va_arg (vargs, Lisp_Object); | |
699 va_end (vargs); | |
700 | |
701 return emacs_doprnt_2 (stream, format_nonreloc, format_reloc, | |
702 format_length, nargs, foo); | |
703 } | |
704 | |
705 /* The following four functions work like the above three but | |
706 return their output as a Lisp string instead of sending it | |
707 to a stream. */ | |
708 | |
709 Lisp_Object | |
710 emacs_doprnt_string_c (CONST Bufbyte *format_nonreloc, | |
711 Lisp_Object format_reloc, Bytecount format_length, | |
712 ...) | |
713 { | |
714 va_list vargs; | |
715 Lisp_Object obj; | |
716 Lisp_Object stream = make_resizing_buffer_output_stream (); | |
717 struct gcpro gcpro1; | |
718 | |
719 GCPRO1 (stream); | |
720 va_start (vargs, format_length); | |
721 emacs_doprnt_1 (stream, format_nonreloc, format_reloc, | |
722 format_length, 0, 0, vargs); | |
723 va_end (vargs); | |
724 Lstream_flush (XLSTREAM (stream)); | |
725 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
726 Lstream_byte_count (XLSTREAM (stream))); | |
727 UNGCPRO; | |
728 Lstream_delete (XLSTREAM (stream)); | |
729 return obj; | |
730 } | |
731 | |
732 Lisp_Object | |
733 emacs_doprnt_string_va (CONST Bufbyte *format_nonreloc, | |
734 Lisp_Object format_reloc, Bytecount format_length, | |
735 va_list vargs) | |
736 { | |
737 /* I'm fairly sure that this function cannot actually GC. | |
738 That can only happen when the arguments to emacs_doprnt_1() are | |
739 Lisp objects rather than C args. */ | |
740 Lisp_Object obj; | |
741 Lisp_Object stream = make_resizing_buffer_output_stream (); | |
742 struct gcpro gcpro1; | |
743 | |
744 GCPRO1 (stream); | |
745 emacs_doprnt_1 (stream, format_nonreloc, format_reloc, | |
746 format_length, 0, 0, vargs); | |
747 Lstream_flush (XLSTREAM (stream)); | |
748 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
749 Lstream_byte_count (XLSTREAM (stream))); | |
750 UNGCPRO; | |
751 Lstream_delete (XLSTREAM (stream)); | |
752 return obj; | |
753 } | |
754 | |
755 Lisp_Object | |
756 emacs_doprnt_string_lisp (CONST Bufbyte *format_nonreloc, | |
757 Lisp_Object format_reloc, Bytecount format_length, | |
758 int nargs, CONST Lisp_Object *largs) | |
759 { | |
760 Lisp_Object obj; | |
761 Lisp_Object stream = make_resizing_buffer_output_stream (); | |
762 struct gcpro gcpro1; | |
763 | |
764 GCPRO1 (stream); | |
765 emacs_doprnt_2 (stream, format_nonreloc, format_reloc, | |
766 format_length, nargs, largs); | |
767 Lstream_flush (XLSTREAM (stream)); | |
768 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
769 Lstream_byte_count (XLSTREAM (stream))); | |
770 UNGCPRO; | |
771 Lstream_delete (XLSTREAM (stream)); | |
772 return obj; | |
773 } | |
774 | |
775 Lisp_Object | |
776 emacs_doprnt_string_lisp_2 (CONST Bufbyte *format_nonreloc, | |
777 Lisp_Object format_reloc, Bytecount format_length, | |
778 int nargs, ...) | |
779 { | |
780 Lisp_Object obj; | |
781 Lisp_Object stream = make_resizing_buffer_output_stream (); | |
782 struct gcpro gcpro1; | |
783 Lisp_Object *foo; | |
784 va_list vargs; | |
785 int i; | |
786 | |
787 foo = (Lisp_Object *) alloca (nargs * sizeof (Lisp_Object)); | |
788 va_start (vargs, nargs); | |
789 for (i = 0; i < nargs; i++) | |
790 foo[i] = va_arg (vargs, Lisp_Object); | |
791 va_end (vargs); | |
792 | |
793 GCPRO1 (stream); | |
794 emacs_doprnt_2 (stream, format_nonreloc, format_reloc, | |
795 format_length, nargs, foo); | |
796 Lstream_flush (XLSTREAM (stream)); | |
797 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
798 Lstream_byte_count (XLSTREAM (stream))); | |
799 UNGCPRO; | |
800 Lstream_delete (XLSTREAM (stream)); | |
801 return obj; | |
802 } |