Mercurial > hg > xemacs-beta
annotate src/doprnt.c @ 5307:c096d8051f89
Have NATNUMP give t for positive bignums; check limits appropriately.
src/ChangeLog addition:
2010-11-20 Aidan Kehoe <kehoea@parhasard.net>
* abbrev.c (Fexpand_abbrev):
* alloc.c:
* alloc.c (Fmake_list):
* alloc.c (Fmake_vector):
* alloc.c (Fmake_bit_vector):
* alloc.c (Fmake_byte_code):
* alloc.c (Fmake_string):
* alloc.c (vars_of_alloc):
* bytecode.c (UNUSED):
* bytecode.c (Fbyte_code):
* chartab.c (decode_char_table_range):
* cmds.c (Fself_insert_command):
* data.c (check_integer_range):
* data.c (Fnatnump):
* data.c (Fnonnegativep):
* data.c (Fstring_to_number):
* elhash.c (hash_table_size_validate):
* elhash.c (decode_hash_table_size):
* eval.c (Fbacktrace_frame):
* event-stream.c (lisp_number_to_milliseconds):
* event-stream.c (Faccept_process_output):
* event-stream.c (Frecent_keys):
* event-stream.c (Fdispatch_event):
* events.c (Fmake_event):
* events.c (Fevent_timestamp):
* events.c (Fevent_timestamp_lessp):
* events.h:
* events.h (struct command_builder):
* file-coding.c (gzip_putprop):
* fns.c:
* fns.c (check_sequence_range):
* fns.c (Frandom):
* fns.c (Fnthcdr):
* fns.c (Flast):
* fns.c (Fnbutlast):
* fns.c (Fbutlast):
* fns.c (Fmember):
* fns.c (Ffill):
* fns.c (Freduce):
* fns.c (replace_string_range_1):
* fns.c (Freplace):
* font-mgr.c (Ffc_pattern_get):
* frame-msw.c (msprinter_set_frame_properties):
* glyphs.c (check_valid_xbm_inline):
* indent.c (Fmove_to_column):
* intl-win32.c (mswindows_multibyte_to_unicode_putprop):
* lisp.h:
* lisp.h (ARRAY_DIMENSION_LIMIT):
* lread.c (decode_mode_1):
* mule-ccl.c (ccl_get_compiled_code):
* number.h:
* process-unix.c (unix_open_multicast_group):
* process.c (Fset_process_window_size):
* profile.c (Fstart_profiling):
* unicode.c (Funicode_to_char):
Change NATNUMP to return 1 for positive bignums; changes uses of
it and of CHECK_NATNUM appropriately, usually by checking for an
integer in an appropriate range.
Add array-dimension-limit and use it in #'make-vector,
#'make-string. Add array-total-size-limit, array-rank-limit while
we're at it, for the sake of any Common Lisp-oriented code that
uses these limits.
Rename check_int_range to check_integer_range, have it take
Lisp_Objects (and thus bignums) instead.
Remove bignum_butlast(), just set int_n to an appropriately large
integer if N is a bignum.
Accept bignums in check_sequence_range(), change the functions
that use check_sequence_range() appropriately.
Move the definition of NATNUMP() to number.h; document why it's a
reasonable name, contradicting an old comment.
tests/ChangeLog addition:
2010-11-20 Aidan Kehoe <kehoea@parhasard.net>
* automated/lisp-tests.el:
* automated/lisp-tests.el (featurep):
* automated/lisp-tests.el (wrong-type-argument):
* automated/mule-tests.el (featurep):
Check for args-out-of-range errors instead of wrong-type-argument
errors in various places when code is handed a large bignum
instead of a fixnum.
Also check for the wrong-type-argument errors when giving the same
code a non-integer value.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sat, 20 Nov 2010 16:49:11 +0000 |
parents | 378a34562cbe |
children | 308d34e9f07d |
rev | line source |
---|---|
428 | 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. | |
793 | 5 Copyright (C) 2001, 2002 Ben Wing. |
428 | 6 Rewritten by mly to use varargs.h. |
7 Rewritten from scratch by Ben Wing (February 1995) for Mule; expanded | |
8 to full printf spec. | |
1983 | 9 Support for bignums, ratios, and bigfloats added April 2004 by Jerry James. |
428 | 10 |
11 This file is part of XEmacs. | |
12 | |
13 XEmacs is free software; you can redistribute it and/or modify it | |
14 under the terms of the GNU General Public License as published by the | |
15 Free Software Foundation; either version 2, or (at your option) any | |
16 later version. | |
17 | |
18 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
21 for more details. | |
22 | |
23 You should have received a copy of the GNU General Public License | |
24 along with XEmacs; see the file COPYING. If not, write to | |
25 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
26 Boston, MA 02111-1307, USA. */ | |
27 | |
793 | 28 /* Synched up with: Rewritten by Ben Wing. Not in FSF. */ |
428 | 29 |
30 #include <config.h> | |
31 #include "lisp.h" | |
32 | |
33 #include "buffer.h" | |
34 #include "lstream.h" | |
35 | |
446 | 36 static const char * const valid_flags = "-+ #0"; |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
37 static const char * const valid_converters = "dic" "ouxX" "feEgG" "sS" "b" |
1983 | 38 #if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) |
39 "npyY" | |
40 #endif | |
41 #ifdef HAVE_BIGFLOAT | |
42 "FhHkK" | |
43 #endif | |
44 ; | |
446 | 45 static const char * const int_converters = "dic"; |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
46 static const char * const unsigned_int_converters = "ouxXb"; |
446 | 47 static const char * const double_converters = "feEgG"; |
48 static const char * const string_converters = "sS"; | |
1983 | 49 #if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
50 static const char * const bignum_converters = "npyY\337"; |
1983 | 51 #endif |
52 #ifdef HAVE_BIGFLOAT | |
53 static const char * const bigfloat_converters = "FhHkK"; | |
54 #endif | |
428 | 55 |
56 typedef struct printf_spec printf_spec; | |
57 struct printf_spec | |
58 { | |
59 int argnum; /* which argument does this spec want? This is one-based: | |
60 The first argument given is numbered 1, the second | |
61 is 2, etc. This is to handle %##$x-type specs. */ | |
62 int minwidth; | |
63 int precision; | |
64 unsigned int minus_flag:1; | |
65 unsigned int plus_flag:1; | |
66 unsigned int space_flag:1; | |
67 unsigned int number_flag:1; | |
68 unsigned int zero_flag:1; | |
69 unsigned int h_flag:1; | |
70 unsigned int l_flag:1; | |
71 unsigned int forwarding_precision:1; | |
72 char converter; /* converter character or 0 for dummy marker | |
73 indicating literal text at the end of the | |
74 specification */ | |
75 Bytecount text_before; /* position of the first character of the | |
76 block of literal text before this spec */ | |
77 Bytecount text_before_len; /* length of that text */ | |
78 }; | |
79 | |
80 typedef union printf_arg printf_arg; | |
81 union printf_arg | |
82 { | |
83 long l; | |
84 unsigned long ul; | |
85 double d; | |
867 | 86 Ibyte *bp; |
1983 | 87 Lisp_Object obj; |
428 | 88 }; |
89 | |
90 /* We maintain a list of all the % specs in the specification, | |
91 along with the offset and length of the block of literal text | |
92 before each spec. In addition, we have a "dummy" spec that | |
93 represents all the literal text at the end of the specification. | |
94 Its converter is 0. */ | |
95 | |
96 typedef struct | |
97 { | |
98 Dynarr_declare (struct printf_spec); | |
99 } printf_spec_dynarr; | |
100 | |
101 typedef struct | |
102 { | |
103 Dynarr_declare (union printf_arg); | |
104 } printf_arg_dynarr; | |
105 | |
448 | 106 /* Append STRING (of length LEN bytes) to STREAM. |
107 MINLEN is the minimum field width. | |
108 If MINUS_FLAG is set, left-justify the string in its field; | |
109 otherwise, right-justify. | |
110 If ZERO_FLAG is set, pad with 0's; otherwise pad with spaces. | |
111 If MAXLEN is non-negative, the string is first truncated on the | |
112 right to that many characters. | |
428 | 113 |
114 Note that MINLEN and MAXLEN are Charcounts but LEN is a Bytecount. */ | |
115 | |
116 static void | |
867 | 117 doprnt_2 (Lisp_Object stream, const Ibyte *string, Bytecount len, |
428 | 118 Charcount minlen, Charcount maxlen, int minus_flag, int zero_flag) |
119 { | |
120 Lstream *lstr = XLSTREAM (stream); | |
448 | 121 Charcount cclen = bytecount_to_charcount (string, len); |
122 int to_add = minlen - cclen; | |
428 | 123 |
124 /* Padding at beginning to right-justify ... */ | |
448 | 125 if (!minus_flag) |
126 while (to_add-- > 0) | |
127 Lstream_putc (lstr, zero_flag ? '0' : ' '); | |
428 | 128 |
448 | 129 if (0 <= maxlen && maxlen < cclen) |
130 len = charcount_to_bytecount (string, maxlen); | |
428 | 131 Lstream_write (lstr, string, len); |
132 | |
133 /* Padding at end to left-justify ... */ | |
448 | 134 if (minus_flag) |
135 while (to_add-- > 0) | |
136 Lstream_putc (lstr, zero_flag ? '0' : ' '); | |
428 | 137 } |
138 | |
867 | 139 static const Ibyte * |
140 parse_off_posnum (const Ibyte *start, const Ibyte *end, int *returned_num) | |
428 | 141 { |
867 | 142 Ibyte arg_convert[100]; |
143 REGISTER Ibyte *arg_ptr = arg_convert; | |
428 | 144 |
145 *returned_num = -1; | |
146 while (start != end && isdigit (*start)) | |
147 { | |
647 | 148 if (arg_ptr - arg_convert >= (int) sizeof (arg_convert) - 1) |
149 syntax_error ("Format converter number too large", Qunbound); | |
428 | 150 *arg_ptr++ = *start++; |
151 } | |
152 *arg_ptr = '\0'; | |
153 if (arg_convert != arg_ptr) | |
154 *returned_num = atoi ((char *) arg_convert); | |
155 return start; | |
156 } | |
157 | |
793 | 158 #define NEXT_ASCII_BYTE(ch) \ |
159 do { \ | |
160 if (fmt == fmt_end) \ | |
161 syntax_error ("Premature end of format string", Qunbound); \ | |
162 ch = *fmt; \ | |
163 if (ch >= 0200) \ | |
164 syntax_error ("Non-ASCII character in format converter spec", \ | |
165 Qunbound); \ | |
166 fmt++; \ | |
428 | 167 } while (0) |
168 | |
169 #define RESOLVE_FLAG_CONFLICTS(spec) \ | |
170 do { \ | |
171 if (spec.space_flag && spec.plus_flag) \ | |
172 spec.space_flag = 0; \ | |
173 if (spec.zero_flag && spec.space_flag) \ | |
174 spec.zero_flag = 0; \ | |
175 } while (0) | |
176 | |
177 static printf_spec_dynarr * | |
867 | 178 parse_doprnt_spec (const Ibyte *format, Bytecount format_length) |
428 | 179 { |
867 | 180 const Ibyte *fmt = format; |
181 const Ibyte *fmt_end = format + format_length; | |
428 | 182 printf_spec_dynarr *specs = Dynarr_new (printf_spec); |
183 int prev_argnum = 0; | |
184 | |
185 while (1) | |
186 { | |
187 struct printf_spec spec; | |
867 | 188 const Ibyte *text_end; |
189 Ibyte ch; | |
428 | 190 |
191 xzero (spec); | |
192 if (fmt == fmt_end) | |
193 return specs; | |
867 | 194 text_end = (Ibyte *) memchr (fmt, '%', fmt_end - fmt); |
428 | 195 if (!text_end) |
196 text_end = fmt_end; | |
197 spec.text_before = fmt - format; | |
198 spec.text_before_len = text_end - fmt; | |
199 fmt = text_end; | |
200 if (fmt != fmt_end) | |
201 { | |
202 fmt++; /* skip over % */ | |
203 | |
204 /* A % is special -- no arg number. According to ANSI specs, | |
205 field width does not apply to %% conversion. */ | |
206 if (fmt != fmt_end && *fmt == '%') | |
207 { | |
208 spec.converter = '%'; | |
209 Dynarr_add (specs, spec); | |
210 fmt++; | |
211 continue; | |
212 } | |
213 | |
214 /* Is there a field number specifier? */ | |
215 { | |
867 | 216 const Ibyte *ptr; |
428 | 217 int fieldspec; |
218 | |
219 ptr = parse_off_posnum (fmt, fmt_end, &fieldspec); | |
220 if (fieldspec > 0 && ptr != fmt_end && *ptr == '$') | |
221 { | |
222 /* There is a format specifier */ | |
223 prev_argnum = fieldspec; | |
224 fmt = ptr + 1; | |
225 } | |
226 else | |
227 prev_argnum++; | |
228 spec.argnum = prev_argnum; | |
229 } | |
230 | |
231 /* Parse off any flags */ | |
232 NEXT_ASCII_BYTE (ch); | |
233 while (strchr (valid_flags, ch)) | |
234 { | |
235 switch (ch) | |
236 { | |
446 | 237 case '-': spec.minus_flag = 1; break; |
238 case '+': spec.plus_flag = 1; break; | |
239 case ' ': spec.space_flag = 1; break; | |
428 | 240 case '#': spec.number_flag = 1; break; |
446 | 241 case '0': spec.zero_flag = 1; break; |
2500 | 242 default: ABORT (); |
428 | 243 } |
244 NEXT_ASCII_BYTE (ch); | |
245 } | |
246 | |
247 /* Parse off the minimum field width */ | |
248 fmt--; /* back up */ | |
249 | |
250 /* | |
251 * * means the field width was passed as an argument. | |
252 * Mark the current spec as one that forwards its | |
253 * field width and flags to the next spec in the array. | |
254 * Then create a new spec and continue with the parsing. | |
255 */ | |
256 if (fmt != fmt_end && *fmt == '*') | |
257 { | |
258 spec.converter = '*'; | |
259 RESOLVE_FLAG_CONFLICTS(spec); | |
260 Dynarr_add (specs, spec); | |
261 xzero (spec); | |
262 spec.argnum = ++prev_argnum; | |
263 fmt++; | |
264 } | |
265 else | |
266 { | |
267 fmt = parse_off_posnum (fmt, fmt_end, &spec.minwidth); | |
268 if (spec.minwidth == -1) | |
269 spec.minwidth = 0; | |
270 } | |
271 | |
272 /* Parse off any precision specified */ | |
273 NEXT_ASCII_BYTE (ch); | |
274 if (ch == '.') | |
275 { | |
276 /* | |
277 * * means the precision was passed as an argument. | |
278 * Mark the current spec as one that forwards its | |
279 * fieldwidth, flags and precision to the next spec in | |
280 * the array. Then create a new spec and continue | |
281 * with the parse. | |
282 */ | |
283 if (fmt != fmt_end && *fmt == '*') | |
284 { | |
285 spec.converter = '*'; | |
286 spec.forwarding_precision = 1; | |
287 RESOLVE_FLAG_CONFLICTS(spec); | |
288 Dynarr_add (specs, spec); | |
289 xzero (spec); | |
290 spec.argnum = ++prev_argnum; | |
291 fmt++; | |
292 } | |
293 else | |
294 { | |
295 fmt = parse_off_posnum (fmt, fmt_end, &spec.precision); | |
296 if (spec.precision == -1) | |
297 spec.precision = 0; | |
298 } | |
299 NEXT_ASCII_BYTE (ch); | |
300 } | |
301 else | |
302 /* No precision specified */ | |
303 spec.precision = -1; | |
304 | |
305 /* Parse off h or l flag */ | |
306 if (ch == 'h' || ch == 'l') | |
307 { | |
308 if (ch == 'h') | |
309 spec.h_flag = 1; | |
310 else | |
311 spec.l_flag = 1; | |
312 NEXT_ASCII_BYTE (ch); | |
313 } | |
314 | |
315 if (!strchr (valid_converters, ch)) | |
563 | 316 syntax_error ("Invalid converter character", make_char (ch)); |
428 | 317 spec.converter = ch; |
318 } | |
319 | |
320 RESOLVE_FLAG_CONFLICTS(spec); | |
321 Dynarr_add (specs, spec); | |
322 } | |
323 | |
1204 | 324 RETURN_NOT_REACHED(specs); /* suppress compiler warning */ |
428 | 325 } |
326 | |
327 static int | |
328 get_args_needed (printf_spec_dynarr *specs) | |
329 { | |
330 int args_needed = 0; | |
331 REGISTER int i; | |
332 | |
333 /* Figure out how many args are needed. This may be less than | |
334 the number of specs because a spec could be %% or could be | |
335 missing (literal text at end of format string) or there | |
336 could be specs where the field number is explicitly given. | |
337 We just look for the maximum argument number that's referenced. */ | |
338 | |
339 for (i = 0; i < Dynarr_length (specs); i++) | |
340 { | |
341 char ch = Dynarr_at (specs, i).converter; | |
342 if (ch && ch != '%') | |
343 { | |
344 int argnum = Dynarr_at (specs, i).argnum; | |
345 if (argnum > args_needed) | |
346 args_needed = argnum; | |
347 } | |
348 } | |
349 | |
350 return args_needed; | |
351 } | |
352 | |
353 static printf_arg_dynarr * | |
354 get_doprnt_args (printf_spec_dynarr *specs, va_list vargs) | |
355 { | |
356 printf_arg_dynarr *args = Dynarr_new (printf_arg); | |
357 union printf_arg arg; | |
358 REGISTER int i; | |
359 int args_needed = get_args_needed (specs); | |
360 | |
361 xzero (arg); | |
362 for (i = 1; i <= args_needed; i++) | |
363 { | |
364 int j; | |
365 char ch; | |
366 struct printf_spec *spec = 0; | |
367 | |
368 for (j = 0; j < Dynarr_length (specs); j++) | |
369 { | |
370 spec = Dynarr_atp (specs, j); | |
371 if (spec->argnum == i) | |
372 break; | |
373 } | |
374 | |
375 if (j == Dynarr_length (specs)) | |
1318 | 376 syntax_error ("No conversion spec for argument", make_int (i)); |
428 | 377 |
378 ch = spec->converter; | |
379 | |
380 if (strchr (int_converters, ch)) | |
381 { | |
446 | 382 if (spec->l_flag) |
428 | 383 arg.l = va_arg (vargs, long); |
384 else | |
446 | 385 /* int even if ch == 'c' or spec->h_flag: |
386 "the type used in va_arg is supposed to match the | |
387 actual type **after default promotions**." | |
388 Hence we read an int, not a short, if spec->h_flag. */ | |
389 arg.l = va_arg (vargs, int); | |
428 | 390 } |
391 else if (strchr (unsigned_int_converters, ch)) | |
392 { | |
446 | 393 if (spec->l_flag) |
428 | 394 arg.ul = va_arg (vargs, unsigned long); |
395 else | |
446 | 396 /* unsigned int even if ch == 'c' or spec->h_flag */ |
397 arg.ul = (unsigned long) va_arg (vargs, unsigned int); | |
428 | 398 } |
399 else if (strchr (double_converters, ch)) | |
400 arg.d = va_arg (vargs, double); | |
401 else if (strchr (string_converters, ch)) | |
867 | 402 arg.bp = va_arg (vargs, Ibyte *); |
1983 | 403 #if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) |
404 else if (strchr (bignum_converters, ch)) | |
405 arg.obj = va_arg (vargs, Lisp_Object); | |
406 #endif | |
407 #ifdef HAVE_BIGFLOAT | |
408 else if (strchr (bigfloat_converters, ch)) | |
409 arg.obj = va_arg (vargs, Lisp_Object); | |
410 #endif | |
2500 | 411 else ABORT (); |
428 | 412 |
413 Dynarr_add (args, arg); | |
414 } | |
415 | |
416 return args; | |
417 } | |
418 | |
771 | 419 /* Most basic entry point into string formatting. |
420 | |
421 Generate output from a format-spec (either a Lisp string | |
422 FORMAT_RELOC, or a C string FORMAT_NONRELOC of length FORMAT_LENGTH | |
423 -- which *MUST NOT* come from Lisp string data, unless GC is | |
424 inhibited). Output goes to STREAM. Returns the number of bytes | |
425 stored into STREAM. Arguments are either C-type arguments in | |
426 va_list VARGS, or an array of Lisp objects in LARGS of size | |
427 NARGS. (Behavior is different in the two cases -- you either get | |
428 standard sprintf() behavior or `format' behavior.) */ | |
428 | 429 |
430 static Bytecount | |
867 | 431 emacs_doprnt_1 (Lisp_Object stream, const Ibyte *format_nonreloc, |
771 | 432 Bytecount format_length, Lisp_Object format_reloc, |
433 int nargs, const Lisp_Object *largs, va_list vargs) | |
428 | 434 { |
435 printf_spec_dynarr *specs = 0; | |
436 printf_arg_dynarr *args = 0; | |
437 REGISTER int i; | |
438 int init_byte_count = Lstream_byte_count (XLSTREAM (stream)); | |
771 | 439 int count; |
428 | 440 |
441 if (!NILP (format_reloc)) | |
442 { | |
443 format_nonreloc = XSTRING_DATA (format_reloc); | |
444 format_length = XSTRING_LENGTH (format_reloc); | |
445 } | |
446 if (format_length < 0) | |
442 | 447 format_length = (Bytecount) strlen ((const char *) format_nonreloc); |
428 | 448 |
449 specs = parse_doprnt_spec (format_nonreloc, format_length); | |
771 | 450 count = record_unwind_protect_freeing_dynarr (specs); |
451 | |
428 | 452 if (largs) |
453 { | |
446 | 454 /* allow too many args for string, but not too few */ |
428 | 455 if (nargs < get_args_needed (specs)) |
563 | 456 signal_error_1 (Qwrong_number_of_arguments, |
1318 | 457 list3 (Qformat, |
458 make_int (nargs), | |
459 !NILP (format_reloc) ? format_reloc : | |
460 make_string (format_nonreloc, format_length))); | |
428 | 461 } |
462 else | |
463 { | |
464 args = get_doprnt_args (specs, vargs); | |
771 | 465 record_unwind_protect_freeing_dynarr (args); |
428 | 466 } |
467 | |
468 for (i = 0; i < Dynarr_length (specs); i++) | |
469 { | |
470 struct printf_spec *spec = Dynarr_atp (specs, i); | |
471 char ch; | |
472 | |
473 /* Copy the text before */ | |
474 if (!NILP (format_reloc)) /* refetch in case of GC below */ | |
475 format_nonreloc = XSTRING_DATA (format_reloc); | |
446 | 476 |
771 | 477 doprnt_2 (stream, format_nonreloc + spec->text_before, |
446 | 478 spec->text_before_len, 0, -1, 0, 0); |
428 | 479 |
480 ch = spec->converter; | |
481 | |
482 if (!ch) | |
483 continue; | |
484 | |
485 if (ch == '%') | |
486 { | |
867 | 487 doprnt_2 (stream, (Ibyte *) &ch, 1, 0, -1, 0, 0); |
428 | 488 continue; |
489 } | |
490 | |
491 /* The char '*' as converter means the field width, precision | |
492 was specified as an argument. Extract the data and forward | |
493 it to the next spec, to which it will apply. */ | |
494 if (ch == '*') | |
495 { | |
496 struct printf_spec *nextspec = Dynarr_atp (specs, i + 1); | |
497 Lisp_Object obj = largs[spec->argnum - 1]; | |
498 | |
499 if (INTP (obj)) | |
500 { | |
501 if (spec->forwarding_precision) | |
502 { | |
503 nextspec->precision = XINT (obj); | |
504 nextspec->minwidth = spec->minwidth; | |
505 } | |
506 else | |
507 { | |
508 nextspec->minwidth = XINT (obj); | |
446 | 509 if (XINT (obj) < 0) |
428 | 510 { |
511 spec->minus_flag = 1; | |
512 nextspec->minwidth = - nextspec->minwidth; | |
513 } | |
514 } | |
446 | 515 nextspec->minus_flag = spec->minus_flag; |
516 nextspec->plus_flag = spec->plus_flag; | |
517 nextspec->space_flag = spec->space_flag; | |
428 | 518 nextspec->number_flag = spec->number_flag; |
446 | 519 nextspec->zero_flag = spec->zero_flag; |
428 | 520 } |
521 continue; | |
522 } | |
523 | |
524 if (largs && (spec->argnum < 1 || spec->argnum > nargs)) | |
771 | 525 syntax_error ("Invalid repositioning argument", |
526 make_int (spec->argnum)); | |
428 | 527 |
528 else if (ch == 'S' || ch == 's') | |
529 { | |
867 | 530 Ibyte *string; |
428 | 531 Bytecount string_len; |
532 | |
533 if (!largs) | |
534 { | |
535 string = Dynarr_at (args, spec->argnum - 1).bp; | |
771 | 536 #if 0 |
537 /* [[ error() can be called with null string arguments. | |
428 | 538 E.g., in fileio.c, the return value of strerror() |
539 is never checked. We'll print (null), like some | |
540 printf implementations do. Would it be better (and safe) | |
541 to signal an error instead? Or should we just use the | |
771 | 542 empty string? -dkindred@cs.cmu.edu 8/1997 ]] |
543 Do not hide bugs. --ben | |
428 | 544 */ |
545 if (!string) | |
867 | 546 string = (Ibyte *) "(null)"; |
771 | 547 #else |
548 assert (string); | |
549 #endif | |
428 | 550 string_len = strlen ((char *) string); |
551 } | |
552 else | |
553 { | |
554 Lisp_Object obj = largs[spec->argnum - 1]; | |
793 | 555 Lisp_Object ls; |
428 | 556 |
557 if (ch == 'S') | |
558 { | |
559 /* For `S', prin1 the argument and then treat like | |
560 a string. */ | |
4394
cacc942c0d0f
Avoid clearing print-gensym-alist inappropriately when printing hash tables.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4333
diff
changeset
|
561 ls = prin1_to_string (obj, 0); |
428 | 562 } |
563 else if (STRINGP (obj)) | |
793 | 564 ls = obj; |
428 | 565 else if (SYMBOLP (obj)) |
566 ls = XSYMBOL (obj)->name; | |
567 else | |
568 { | |
569 /* convert to string using princ. */ | |
4394
cacc942c0d0f
Avoid clearing print-gensym-alist inappropriately when printing hash tables.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4333
diff
changeset
|
570 ls = prin1_to_string (obj, 1); |
428 | 571 } |
793 | 572 string = XSTRING_DATA (ls); |
573 string_len = XSTRING_LENGTH (ls); | |
428 | 574 } |
575 | |
771 | 576 doprnt_2 (stream, string, string_len, spec->minwidth, |
428 | 577 spec->precision, spec->minus_flag, spec->zero_flag); |
578 } | |
579 | |
580 else | |
581 { | |
582 /* Must be a number. */ | |
583 union printf_arg arg; | |
584 | |
585 if (!largs) | |
586 { | |
587 arg = Dynarr_at (args, spec->argnum - 1); | |
588 } | |
589 else | |
590 { | |
591 Lisp_Object obj = largs[spec->argnum - 1]; | |
592 if (CHARP (obj)) | |
593 obj = make_int (XCHAR (obj)); | |
1983 | 594 if (!NUMBERP (obj)) |
428 | 595 { |
2267 | 596 /* WARNING! This MUST be big enough for the sprintf below */ |
2272 | 597 CIbyte msg[48]; |
598 sprintf (msg, | |
2267 | 599 "format specifier %%%c doesn't match argument type", |
600 ch); | |
4876
437323273039
Cosmetic: Use Qunbound, not Qnil as second arg to call to syntax_error() to get cleaner error message
Ben Wing <ben@xemacs.org>
parents:
4678
diff
changeset
|
601 syntax_error (msg, Qunbound); |
428 | 602 } |
603 else if (strchr (double_converters, ch)) | |
1983 | 604 { |
5252
378a34562cbe
Fix style, documentation for rounding functions and multiple values.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4976
diff
changeset
|
605 if (INTP (obj)) |
378a34562cbe
Fix style, documentation for rounding functions and multiple values.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4976
diff
changeset
|
606 arg.d = XINT (obj); |
378a34562cbe
Fix style, documentation for rounding functions and multiple values.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4976
diff
changeset
|
607 else if (FLOATP (obj)) |
378a34562cbe
Fix style, documentation for rounding functions and multiple values.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4976
diff
changeset
|
608 arg.d = XFLOAT_DATA (obj); |
1983 | 609 #ifdef HAVE_BIGNUM |
610 else if (BIGNUMP (obj)) | |
611 arg.d = bignum_to_double (XBIGNUM_DATA (obj)); | |
612 #endif | |
613 #ifdef HAVE_RATIO | |
614 else if (RATIOP (obj)) | |
615 arg.d = ratio_to_double (XRATIO_DATA (obj)); | |
616 #endif | |
617 #ifdef HAVE_BIGFLOAT | |
618 else if (BIGFLOATP (obj)) | |
619 { | |
620 arg.obj = obj; | |
621 switch (ch) | |
622 { | |
623 case 'f': ch = 'F'; break; | |
624 case 'e': ch = 'h'; break; | |
625 case 'E': ch = 'H'; break; | |
626 case 'g': ch = 'k'; break; | |
627 case 'G': ch = 'K'; break; | |
628 } | |
629 } | |
630 #endif | |
631 } | |
428 | 632 else |
633 { | |
446 | 634 if (FLOATP (obj)) |
4678
b5e1d4f6b66f
Make #'floor, #'ceiling, #'round, #'truncate conform to Common Lisp.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4394
diff
changeset
|
635 obj = Ftruncate (obj, Qnil); |
1983 | 636 #ifdef HAVE_BIGFLOAT |
637 else if (BIGFLOATP (obj)) | |
638 { | |
639 #ifdef HAVE_BIGNUM | |
640 bignum_set_bigfloat (scratch_bignum, | |
641 XBIGFLOAT_DATA (obj)); | |
642 if (strchr (unsigned_int_converters, ch) && | |
643 bignum_sign (scratch_bignum) < 0) | |
644 dead_wrong_type_argument (Qnonnegativep, obj); | |
645 obj = | |
646 Fcanonicalize_number (make_bignum_bg (scratch_bignum)); | |
647 #else /* !HAVE_BIGNUM */ | |
648 obj = make_int (bigfloat_to_long (XBIGFLOAT_DATA (obj))); | |
649 #endif /* HAVE_BIGNUM */ | |
650 } | |
651 #endif /* HAVE_BIGFLOAT */ | |
652 #ifdef HAVE_RATIO | |
653 else if (RATIOP (obj)) | |
654 { | |
655 arg.obj = obj; | |
656 switch (ch) | |
657 { | |
658 case 'i': case 'd': ch = 'n'; break; | |
659 case 'o': ch = 'p'; break; | |
660 case 'x': ch = 'y'; break; | |
661 case 'X': ch = 'Y'; break; | |
4333
3483b381b0a9
Take out some debug code; correct some original code.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4329
diff
changeset
|
662 case 'b': ch = '\337'; break; |
1983 | 663 default: /* ch == 'u' */ |
664 if (strchr (unsigned_int_converters, ch) && | |
665 ratio_sign (XRATIO_DATA (obj)) < 0) | |
666 dead_wrong_type_argument (Qnonnegativep, obj); | |
667 else | |
668 ch = 'n'; | |
669 } | |
670 } | |
671 #endif | |
672 #ifdef HAVE_BIGNUM | |
673 if (BIGNUMP (obj)) | |
674 { | |
675 arg.obj = obj; | |
676 switch (ch) | |
677 { | |
678 case 'i': case 'd': ch = 'n'; break; | |
679 case 'o': ch = 'p'; break; | |
680 case 'x': ch = 'y'; break; | |
681 case 'X': ch = 'Y'; break; | |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
682 case 'b': ch = '\337'; break; |
1983 | 683 default: /* ch == 'u' */ |
684 if (strchr (unsigned_int_converters, ch) && | |
685 bignum_sign (XBIGNUM_DATA (obj)) < 0) | |
686 dead_wrong_type_argument (Qnatnump, obj); | |
687 else | |
688 ch = 'n'; | |
689 } | |
690 } | |
691 #endif | |
692 if (INTP (obj)) | |
693 { | |
694 if (strchr (unsigned_int_converters, ch)) | |
695 { | |
696 #ifdef HAVE_BIGNUM | |
697 if (XINT (obj) < 0) | |
698 dead_wrong_type_argument (Qnatnump, obj); | |
699 #endif | |
700 arg.ul = (unsigned long) XUINT (obj); | |
701 } | |
702 else | |
703 arg.l = XINT (obj); | |
704 } | |
428 | 705 } |
706 } | |
707 | |
708 if (ch == 'c') | |
709 { | |
867 | 710 Ichar a; |
428 | 711 Bytecount charlen; |
867 | 712 Ibyte charbuf[MAX_ICHAR_LEN]; |
428 | 713 |
867 | 714 a = (Ichar) arg.l; |
428 | 715 |
867 | 716 if (!valid_ichar_p (a)) |
2267 | 717 { |
718 /* WARNING! This MUST be big enough for the sprintf below */ | |
2272 | 719 CIbyte msg[60]; |
720 sprintf (msg, "invalid character value %d to %%c spec", | |
2267 | 721 a); |
4876
437323273039
Cosmetic: Use Qunbound, not Qnil as second arg to call to syntax_error() to get cleaner error message
Ben Wing <ben@xemacs.org>
parents:
4678
diff
changeset
|
722 syntax_error (msg, Qunbound); |
2267 | 723 } |
428 | 724 |
867 | 725 charlen = set_itext_ichar (charbuf, a); |
771 | 726 doprnt_2 (stream, charbuf, charlen, spec->minwidth, |
428 | 727 -1, spec->minus_flag, spec->zero_flag); |
728 } | |
1983 | 729 #if defined(HAVE_BIGNUM) || defined(HAVE_RATIO) |
730 else if (strchr (bignum_converters, ch)) | |
731 { | |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
732 int base = 16; |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
733 |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
734 if (ch == 'n') |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
735 base = 10; |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
736 else if (ch == 'p') |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
737 base = 8; |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
738 else if (ch == '\337') |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
739 base = 2; |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
740 |
1983 | 741 #ifdef HAVE_BIGNUM |
742 if (BIGNUMP (arg.obj)) | |
743 { | |
1995 | 744 Ibyte *text_to_print = |
745 (Ibyte *) bignum_to_string (XBIGNUM_DATA (arg.obj), | |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
746 base); |
1995 | 747 doprnt_2 (stream, text_to_print, |
748 strlen ((const char *) text_to_print), | |
1983 | 749 spec->minwidth, -1, spec->minus_flag, |
750 spec->zero_flag); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4876
diff
changeset
|
751 xfree (text_to_print); |
1983 | 752 } |
753 #endif | |
754 #ifdef HAVE_RATIO | |
755 if (RATIOP (arg.obj)) | |
756 { | |
1995 | 757 Ibyte *text_to_print = |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
758 (Ibyte *) ratio_to_string (XRATIO_DATA (arg.obj), base); |
1995 | 759 doprnt_2 (stream, text_to_print, |
760 strlen ((const char *) text_to_print), | |
1983 | 761 spec->minwidth, -1, spec->minus_flag, |
762 spec->zero_flag); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4876
diff
changeset
|
763 xfree (text_to_print); |
1983 | 764 } |
765 #endif | |
766 } | |
767 #endif /* HAVE_BIGNUM || HAVE_RATIO */ | |
768 #ifdef HAVE_BIGFLOAT | |
769 else if (strchr (bigfloat_converters, ch)) | |
770 { | |
1995 | 771 Ibyte *text_to_print = |
772 (Ibyte *) bigfloat_to_string (XBIGFLOAT_DATA (arg.obj), 10); | |
773 doprnt_2 (stream, text_to_print, | |
774 strlen ((const char *) text_to_print), | |
1983 | 775 spec->minwidth, -1, spec->minus_flag, spec->zero_flag); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4876
diff
changeset
|
776 xfree (text_to_print); |
1983 | 777 } |
778 #endif /* HAVE_BIGFLOAT */ | |
4329
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
779 else if (ch == 'b') |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
780 { |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
781 Ascbyte *text_to_print = alloca_array (char, SIZEOF_LONG * 8 + 1); |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
782 |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
783 ulong_to_bit_string (text_to_print, arg.ul); |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
784 doprnt_2 (stream, (Ibyte *)text_to_print, |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
785 qxestrlen ((Ibyte *)text_to_print), |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
786 spec->minwidth, -1, spec->minus_flag, spec->zero_flag); |
d9eb5ea14f65
Provide %b in #'format; use it for converting between ints and bit vectors.
Aidan Kehoe <kehoea@parhasard.net>
parents:
4287
diff
changeset
|
787 } |
428 | 788 else |
789 { | |
4287 | 790 Ascbyte *text_to_print; |
3706 | 791 Ascbyte constructed_spec[100]; |
792 Ascbyte *p = constructed_spec; | |
4287 | 793 int alloca_sz = 350; |
794 int min = spec->minwidth, prec = spec->precision; | |
795 | |
796 if (prec < 0) | |
797 prec = 0; | |
798 if (min < 0) | |
799 min = 0; | |
800 | |
801 if (32+min+prec > alloca_sz) | |
802 alloca_sz = 32 + min + prec; | |
803 | |
804 text_to_print = alloca_array(char, alloca_sz); | |
428 | 805 |
448 | 806 /* Mostly reconstruct the spec and use sprintf() to |
428 | 807 format the string. */ |
808 | |
446 | 809 *p++ = '%'; |
810 if (spec->plus_flag) *p++ = '+'; | |
811 if (spec->space_flag) *p++ = ' '; | |
812 if (spec->number_flag) *p++ = '#'; | |
448 | 813 if (spec->minus_flag) *p++ = '-'; |
814 if (spec->zero_flag) *p++ = '0'; | |
446 | 815 |
448 | 816 if (spec->minwidth >= 0) |
577 | 817 { |
818 long_to_string (p, spec->minwidth); | |
819 p += strlen (p); | |
820 } | |
448 | 821 if (spec->precision >= 0) |
428 | 822 { |
446 | 823 *p++ = '.'; |
577 | 824 long_to_string (p, spec->precision); |
825 p += strlen (p); | |
428 | 826 } |
448 | 827 |
428 | 828 if (strchr (double_converters, ch)) |
442 | 829 { |
446 | 830 *p++ = ch; |
831 *p++ = '\0'; | |
442 | 832 sprintf (text_to_print, constructed_spec, arg.d); |
833 } | |
428 | 834 else |
835 { | |
448 | 836 *p++ = 'l'; /* Always use longs with sprintf() */ |
837 *p++ = ch; | |
838 *p++ = '\0'; | |
446 | 839 |
840 if (strchr (unsigned_int_converters, ch)) | |
841 sprintf (text_to_print, constructed_spec, arg.ul); | |
842 else | |
428 | 843 sprintf (text_to_print, constructed_spec, arg.l); |
844 } | |
845 | |
867 | 846 doprnt_2 (stream, (Ibyte *) text_to_print, |
448 | 847 strlen (text_to_print), 0, -1, 0, 0); |
428 | 848 } |
849 } | |
850 } | |
851 | |
771 | 852 unbind_to (count); |
428 | 853 return Lstream_byte_count (XLSTREAM (stream)) - init_byte_count; |
854 } | |
855 | |
771 | 856 /* Basic external entry point into string formatting. See |
857 emacs_doprnt_1(). | |
858 */ | |
859 | |
860 Bytecount | |
867 | 861 emacs_doprnt_va (Lisp_Object stream, const Ibyte *format_nonreloc, |
771 | 862 Bytecount format_length, Lisp_Object format_reloc, |
863 va_list vargs) | |
864 { | |
865 return emacs_doprnt_1 (stream, format_nonreloc, format_length, | |
866 format_reloc, 0, 0, vargs); | |
867 } | |
868 | |
869 /* Basic external entry point into string formatting. See | |
870 emacs_doprnt_1(). | |
871 */ | |
872 | |
873 Bytecount | |
867 | 874 emacs_doprnt (Lisp_Object stream, const Ibyte *format_nonreloc, |
771 | 875 Bytecount format_length, Lisp_Object format_reloc, |
876 int nargs, const Lisp_Object *largs, ...) | |
428 | 877 { |
878 va_list vargs; | |
879 Bytecount val; | |
880 va_start (vargs, largs); | |
771 | 881 val = emacs_doprnt_1 (stream, format_nonreloc, format_length, |
882 format_reloc, nargs, largs, vargs); | |
428 | 883 va_end (vargs); |
884 return val; | |
885 } | |
886 | |
771 | 887 /* Similar to `format' in that its arguments are Lisp objects rather than C |
888 objects. (For the versions that take C objects, see the | |
889 emacs_[v]sprintf... functions below.) Accepts the format string as | |
890 either a C string (FORMAT_NONRELOC, which *MUST NOT* come from Lisp | |
891 string data, unless GC is inhibited) or a Lisp string (FORMAT_RELOC). | |
892 Return resulting formatted string as a Lisp string. | |
428 | 893 |
771 | 894 All arguments are GCPRO'd, including FORMAT_RELOC; this makes it OK to |
895 pass newly created objects into this function (as often happens). | |
428 | 896 |
771 | 897 #### It shouldn't be necessary to specify the number of arguments. |
898 This would require some rewriting of the doprnt() functions, though. | |
899 */ | |
428 | 900 |
901 Lisp_Object | |
867 | 902 emacs_vsprintf_string_lisp (const CIbyte *format_nonreloc, |
771 | 903 Lisp_Object format_reloc, int nargs, |
904 const Lisp_Object *largs) | |
428 | 905 { |
771 | 906 Lisp_Object stream; |
428 | 907 Lisp_Object obj; |
771 | 908 struct gcpro gcpro1, gcpro2; |
909 GCPRO2 (largs[0], format_reloc); | |
910 gcpro1.nvars = nargs; | |
428 | 911 |
771 | 912 stream = make_resizing_buffer_output_stream (); |
867 | 913 emacs_doprnt (stream, (Ibyte *) format_nonreloc, format_nonreloc ? |
771 | 914 strlen (format_nonreloc) : 0, |
915 format_reloc, nargs, largs); | |
428 | 916 Lstream_flush (XLSTREAM (stream)); |
917 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
918 Lstream_byte_count (XLSTREAM (stream))); | |
771 | 919 Lstream_delete (XLSTREAM (stream)); |
428 | 920 UNGCPRO; |
921 return obj; | |
922 } | |
923 | |
771 | 924 /* Like emacs_vsprintf_string_lisp() but accepts its extra args directly |
925 (using variable arguments), rather than as an array. */ | |
926 | |
428 | 927 Lisp_Object |
867 | 928 emacs_sprintf_string_lisp (const CIbyte *format_nonreloc, |
771 | 929 Lisp_Object format_reloc, int nargs, ...) |
428 | 930 { |
771 | 931 Lisp_Object *args = alloca_array (Lisp_Object, nargs); |
932 va_list va; | |
933 int i; | |
428 | 934 Lisp_Object obj; |
935 | |
771 | 936 va_start (va, nargs); |
937 for (i = 0; i < nargs; i++) | |
938 args[i] = va_arg (va, Lisp_Object); | |
939 va_end (va); | |
940 obj = emacs_vsprintf_string_lisp (format_nonreloc, format_reloc, nargs, | |
941 args); | |
428 | 942 return obj; |
943 } | |
944 | |
771 | 945 /* Like emacs_vsprintf_string_lisp() but returns a malloc()ed memory block. |
946 Return length out through LEN_OUT, if not null. */ | |
947 | |
867 | 948 Ibyte * |
949 emacs_vsprintf_malloc_lisp (const CIbyte *format_nonreloc, | |
771 | 950 Lisp_Object format_reloc, int nargs, |
951 const Lisp_Object *largs, Bytecount *len_out) | |
952 { | |
953 Lisp_Object stream; | |
867 | 954 Ibyte *retval; |
771 | 955 Bytecount len; |
956 struct gcpro gcpro1, gcpro2; | |
957 | |
958 GCPRO2 (largs[0], format_reloc); | |
959 gcpro1.nvars = nargs; | |
960 | |
961 stream = make_resizing_buffer_output_stream (); | |
867 | 962 emacs_doprnt (stream, (Ibyte *) format_nonreloc, format_nonreloc ? |
771 | 963 strlen (format_nonreloc) : 0, |
964 format_reloc, nargs, largs); | |
965 Lstream_flush (XLSTREAM (stream)); | |
966 len = Lstream_byte_count (XLSTREAM (stream)); | |
2367 | 967 retval = xnew_ibytes (len + 1); |
771 | 968 memcpy (retval, resizing_buffer_stream_ptr (XLSTREAM (stream)), len); |
969 retval[len] = '\0'; | |
970 Lstream_delete (XLSTREAM (stream)); | |
971 | |
972 if (len_out) | |
973 *len_out = len; | |
974 UNGCPRO; | |
975 return retval; | |
976 } | |
977 | |
978 /* Like emacs_sprintf_string_lisp() but returns a malloc()ed memory block. | |
979 Return length out through LEN_OUT, if not null. */ | |
980 | |
867 | 981 Ibyte * |
982 emacs_sprintf_malloc_lisp (Bytecount *len_out, const CIbyte *format_nonreloc, | |
771 | 983 Lisp_Object format_reloc, int nargs, ...) |
984 { | |
985 Lisp_Object *args = alloca_array (Lisp_Object, nargs); | |
986 va_list va; | |
987 int i; | |
867 | 988 Ibyte *retval; |
771 | 989 |
990 va_start (va, nargs); | |
991 for (i = 0; i < nargs; i++) | |
992 args[i] = va_arg (va, Lisp_Object); | |
993 va_end (va); | |
994 retval = emacs_vsprintf_malloc_lisp (format_nonreloc, format_reloc, nargs, | |
995 args, len_out); | |
996 return retval; | |
997 } | |
998 | |
999 /* vsprintf()-like replacement. Returns a Lisp string. Data | |
1000 from Lisp strings is OK because we explicitly inhibit GC. */ | |
1001 | |
428 | 1002 Lisp_Object |
867 | 1003 emacs_vsprintf_string (const CIbyte *format, va_list vargs) |
428 | 1004 { |
771 | 1005 Lisp_Object stream = make_resizing_buffer_output_stream (); |
428 | 1006 Lisp_Object obj; |
771 | 1007 int count = begin_gc_forbidden (); |
428 | 1008 |
867 | 1009 emacs_doprnt_va (stream, (Ibyte *) format, strlen (format), Qnil, |
771 | 1010 vargs); |
428 | 1011 Lstream_flush (XLSTREAM (stream)); |
1012 obj = make_string (resizing_buffer_stream_ptr (XLSTREAM (stream)), | |
1013 Lstream_byte_count (XLSTREAM (stream))); | |
1014 Lstream_delete (XLSTREAM (stream)); | |
771 | 1015 end_gc_forbidden (count); |
428 | 1016 return obj; |
1017 } | |
1018 | |
771 | 1019 /* sprintf()-like replacement. Returns a Lisp string. Data |
1020 from Lisp strings is OK because we explicitly inhibit GC. */ | |
1021 | |
428 | 1022 Lisp_Object |
867 | 1023 emacs_sprintf_string (const CIbyte *format, ...) |
771 | 1024 { |
1025 va_list vargs; | |
1026 Lisp_Object retval; | |
1027 | |
1028 va_start (vargs, format); | |
1029 retval = emacs_vsprintf_string (format, vargs); | |
1030 va_end (vargs); | |
1031 return retval; | |
1032 } | |
1033 | |
1034 /* vsprintf()-like replacement. Returns a malloc()ed memory block. Data | |
1035 from Lisp strings is OK because we explicitly inhibit GC. Return | |
1036 length out through LEN_OUT, if not null. */ | |
1037 | |
867 | 1038 Ibyte * |
1039 emacs_vsprintf_malloc (const CIbyte *format, va_list vargs, | |
771 | 1040 Bytecount *len_out) |
428 | 1041 { |
771 | 1042 int count = begin_gc_forbidden (); |
428 | 1043 Lisp_Object stream = make_resizing_buffer_output_stream (); |
867 | 1044 Ibyte *retval; |
771 | 1045 Bytecount len; |
1046 | |
867 | 1047 emacs_doprnt_va (stream, (Ibyte *) format, strlen (format), Qnil, |
771 | 1048 vargs); |
1049 Lstream_flush (XLSTREAM (stream)); | |
1050 len = Lstream_byte_count (XLSTREAM (stream)); | |
2367 | 1051 retval = xnew_ibytes (len + 1); |
771 | 1052 memcpy (retval, resizing_buffer_stream_ptr (XLSTREAM (stream)), len); |
1053 retval[len] = '\0'; | |
1054 end_gc_forbidden (count); | |
1055 Lstream_delete (XLSTREAM (stream)); | |
1056 | |
1057 if (len_out) | |
1058 *len_out = len; | |
1059 return retval; | |
1060 } | |
1061 | |
1062 /* sprintf()-like replacement. Returns a malloc()ed memory block. Data | |
1063 from Lisp strings is OK because we explicitly inhibit GC. Return length | |
1064 out through LEN_OUT, if not null. */ | |
428 | 1065 |
867 | 1066 Ibyte * |
1067 emacs_sprintf_malloc (Bytecount *len_out, const CIbyte *format, ...) | |
771 | 1068 { |
1069 va_list vargs; | |
867 | 1070 Ibyte *retval; |
771 | 1071 |
1072 va_start (vargs, format); | |
1073 retval = emacs_vsprintf_malloc (format, vargs, len_out); | |
428 | 1074 va_end (vargs); |
771 | 1075 return retval; |
1076 } | |
1077 | |
1078 /* vsprintf() replacement. Writes output into OUTPUT, which better | |
1079 have enough space for the output. Data from Lisp strings is OK | |
1080 because we explicitly inhibit GC. */ | |
1081 | |
1082 Bytecount | |
867 | 1083 emacs_vsprintf (Ibyte *output, const CIbyte *format, va_list vargs) |
771 | 1084 { |
1085 Bytecount retval; | |
1086 int count = begin_gc_forbidden (); | |
1087 Lisp_Object stream = make_resizing_buffer_output_stream (); | |
1088 Bytecount len; | |
428 | 1089 |
867 | 1090 retval = emacs_doprnt_va (stream, (Ibyte *) format, strlen (format), Qnil, |
771 | 1091 vargs); |
428 | 1092 Lstream_flush (XLSTREAM (stream)); |
771 | 1093 len = Lstream_byte_count (XLSTREAM (stream)); |
1094 memcpy (output, resizing_buffer_stream_ptr (XLSTREAM (stream)), len); | |
1095 output[len] = '\0'; | |
1096 end_gc_forbidden (count); | |
428 | 1097 Lstream_delete (XLSTREAM (stream)); |
771 | 1098 |
1099 return retval; | |
428 | 1100 } |
771 | 1101 |
1102 /* sprintf() replacement. Writes output into OUTPUT, which better | |
1103 have enough space for the output. Data from Lisp strings is OK | |
1104 because we explicitly inhibit GC. */ | |
1105 | |
1106 Bytecount | |
867 | 1107 emacs_sprintf (Ibyte *output, const CIbyte *format, ...) |
771 | 1108 { |
1109 va_list vargs; | |
1110 Bytecount retval; | |
1111 | |
1112 va_start (vargs, format); | |
1113 retval = emacs_vsprintf (output, format, vargs); | |
1114 va_end (vargs); | |
1115 return retval; | |
1116 } |