comparison src/doprnt.c @ 428:3ecd8885ac67 r21-2-22

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