cordprnt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. /*
  2. * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
  3. *
  4. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  5. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  6. *
  7. * Permission is hereby granted to use or copy this program
  8. * for any purpose, provided the above notices are retained on all copies.
  9. * Permission to modify the code and to distribute modified code is granted,
  10. * provided the above notices are retained, and a notice that the code was
  11. * modified is included with the above copyright notice.
  12. */
  13. /* An sprintf implementation that understands cords. This is probably */
  14. /* not terribly portable. It assumes an ANSI stdarg.h. It further */
  15. /* assumes that I can make copies of va_list variables, and read */
  16. /* arguments repeatedly by applyting va_arg to the copies. This */
  17. /* could be avoided at some performance cost. */
  18. /* We also assume that unsigned and signed integers of various kinds */
  19. /* have the same sizes, and can be cast back and forth. */
  20. /* We assume that void * and char * have the same size. */
  21. /* All this cruft is needed because we want to rely on the underlying */
  22. /* sprintf implementation whenever possible. */
  23. /* Boehm, September 21, 1995 6:00 pm PDT */
  24. #include "cord.h"
  25. #include "ec.h"
  26. #include <stdio.h>
  27. #include <stdarg.h>
  28. #include <string.h>
  29. #include "gc.h"
  30. #define CONV_SPEC_LEN 50 /* Maximum length of a single */
  31. /* conversion specification. */
  32. #define CONV_RESULT_LEN 50 /* Maximum length of any */
  33. /* conversion with default */
  34. /* width and prec. */
  35. static int ec_len(CORD_ec x)
  36. {
  37. return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
  38. }
  39. /* Possible nonumeric precision values. */
  40. # define NONE -1
  41. # define VARIABLE -2
  42. /* Copy the conversion specification from CORD_pos into the buffer buf */
  43. /* Return negative on error. */
  44. /* Source initially points one past the leading %. */
  45. /* It is left pointing at the conversion type. */
  46. /* Assign field width and precision to *width and *prec. */
  47. /* If width or prec is *, VARIABLE is assigned. */
  48. /* Set *left to 1 if left adjustment flag is present. */
  49. /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
  50. /* -1 if 'h' is present. */
  51. static int extract_conv_spec(CORD_pos source, char *buf,
  52. int * width, int *prec, int *left, int * long_arg)
  53. {
  54. register int result = 0;
  55. register int current_number = 0;
  56. register int saw_period = 0;
  57. register int saw_number = 0;
  58. register int chars_so_far = 0;
  59. register char current;
  60. *width = NONE;
  61. buf[chars_so_far++] = '%';
  62. while(CORD_pos_valid(source)) {
  63. if (chars_so_far >= CONV_SPEC_LEN) return(-1);
  64. current = CORD_pos_fetch(source);
  65. buf[chars_so_far++] = current;
  66. switch(current) {
  67. case '*':
  68. saw_number = 1;
  69. current_number = VARIABLE;
  70. break;
  71. case '0':
  72. if (!saw_number) {
  73. /* Zero fill flag; ignore */
  74. break;
  75. } /* otherwise fall through: */
  76. case '1':
  77. case '2':
  78. case '3':
  79. case '4':
  80. case '5':
  81. case '6':
  82. case '7':
  83. case '8':
  84. case '9':
  85. saw_number = 1;
  86. current_number *= 10;
  87. current_number += current - '0';
  88. break;
  89. case '.':
  90. saw_period = 1;
  91. if(saw_number) {
  92. *width = current_number;
  93. saw_number = 0;
  94. }
  95. current_number = 0;
  96. break;
  97. case 'l':
  98. case 'L':
  99. *long_arg = 1;
  100. current_number = 0;
  101. break;
  102. case 'h':
  103. *long_arg = -1;
  104. current_number = 0;
  105. break;
  106. case ' ':
  107. case '+':
  108. case '#':
  109. current_number = 0;
  110. break;
  111. case '-':
  112. *left = 1;
  113. current_number = 0;
  114. break;
  115. case 'd':
  116. case 'i':
  117. case 'o':
  118. case 'u':
  119. case 'x':
  120. case 'X':
  121. case 'f':
  122. case 'e':
  123. case 'E':
  124. case 'g':
  125. case 'G':
  126. case 'c':
  127. case 'C':
  128. case 's':
  129. case 'S':
  130. case 'p':
  131. case 'n':
  132. case 'r':
  133. goto done;
  134. default:
  135. return(-1);
  136. }
  137. CORD_next(source);
  138. }
  139. return(-1);
  140. done:
  141. if (saw_number) {
  142. if (saw_period) {
  143. *prec = current_number;
  144. } else {
  145. *prec = NONE;
  146. *width = current_number;
  147. }
  148. } else {
  149. *prec = NONE;
  150. }
  151. buf[chars_so_far] = '\0';
  152. return(result);
  153. }
  154. int CORD_vsprintf(CORD * out, CORD format, va_list args)
  155. {
  156. CORD_ec result;
  157. register int count;
  158. register char current;
  159. CORD_pos pos;
  160. char conv_spec[CONV_SPEC_LEN + 1];
  161. CORD_ec_init(result);
  162. for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
  163. current = CORD_pos_fetch(pos);
  164. if (current == '%') {
  165. CORD_next(pos);
  166. if (!CORD_pos_valid(pos)) return(-1);
  167. current = CORD_pos_fetch(pos);
  168. if (current == '%') {
  169. CORD_ec_append(result, current);
  170. } else {
  171. int width, prec;
  172. int left_adj = 0;
  173. int long_arg = 0;
  174. CORD arg;
  175. size_t len;
  176. if (extract_conv_spec(pos, conv_spec,
  177. &width, &prec,
  178. &left_adj, &long_arg) < 0) {
  179. return(-1);
  180. }
  181. current = CORD_pos_fetch(pos);
  182. switch(current) {
  183. case 'n':
  184. /* Assign length to next arg */
  185. if (long_arg == 0) {
  186. int * pos_ptr;
  187. pos_ptr = va_arg(args, int *);
  188. *pos_ptr = ec_len(result);
  189. } else if (long_arg > 0) {
  190. long * pos_ptr;
  191. pos_ptr = va_arg(args, long *);
  192. *pos_ptr = ec_len(result);
  193. } else {
  194. short * pos_ptr;
  195. pos_ptr = va_arg(args, short *);
  196. *pos_ptr = ec_len(result);
  197. }
  198. goto done;
  199. case 'r':
  200. /* Append cord and any padding */
  201. if (width == VARIABLE) width = va_arg(args, int);
  202. if (prec == VARIABLE) prec = va_arg(args, int);
  203. arg = va_arg(args, CORD);
  204. len = CORD_len(arg);
  205. if (prec != NONE && len > prec) {
  206. if (prec < 0) return(-1);
  207. arg = CORD_substr(arg, 0, prec);
  208. len = prec;
  209. }
  210. if (width != NONE && len < width) {
  211. char * blanks = GC_MALLOC_ATOMIC(width-len+1);
  212. memset(blanks, ' ', width-len);
  213. blanks[width-len] = '\0';
  214. if (left_adj) {
  215. arg = CORD_cat(arg, blanks);
  216. } else {
  217. arg = CORD_cat(blanks, arg);
  218. }
  219. }
  220. CORD_ec_append_cord(result, arg);
  221. goto done;
  222. case 'c':
  223. if (width == NONE && prec == NONE) {
  224. register char c;
  225. c = (char)va_arg(args, int);
  226. CORD_ec_append(result, c);
  227. goto done;
  228. }
  229. break;
  230. case 's':
  231. if (width == NONE && prec == NONE) {
  232. char * str = va_arg(args, char *);
  233. register char c;
  234. while ((c = *str++)) {
  235. CORD_ec_append(result, c);
  236. }
  237. goto done;
  238. }
  239. break;
  240. default:
  241. break;
  242. }
  243. /* Use standard sprintf to perform conversion */
  244. {
  245. register char * buf;
  246. va_list vsprintf_args;
  247. int max_size = 0;
  248. int res;
  249. # ifdef __va_copy
  250. __va_copy(vsprintf_args, args);
  251. # else
  252. # if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
  253. va_copy(vsprintf_args, args);
  254. # else
  255. vsprintf_args = args;
  256. # endif
  257. # endif
  258. if (width == VARIABLE) width = va_arg(args, int);
  259. if (prec == VARIABLE) prec = va_arg(args, int);
  260. if (width != NONE) max_size = width;
  261. if (prec != NONE && prec > max_size) max_size = prec;
  262. max_size += CONV_RESULT_LEN;
  263. if (max_size >= CORD_BUFSZ) {
  264. buf = GC_MALLOC_ATOMIC(max_size + 1);
  265. } else {
  266. if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
  267. < max_size) {
  268. CORD_ec_flush_buf(result);
  269. }
  270. buf = result[0].ec_bufptr;
  271. }
  272. switch(current) {
  273. case 'd':
  274. case 'i':
  275. case 'o':
  276. case 'u':
  277. case 'x':
  278. case 'X':
  279. case 'c':
  280. if (long_arg <= 0) {
  281. (void) va_arg(args, int);
  282. } else if (long_arg > 0) {
  283. (void) va_arg(args, long);
  284. }
  285. break;
  286. case 's':
  287. case 'p':
  288. (void) va_arg(args, char *);
  289. break;
  290. case 'f':
  291. case 'e':
  292. case 'E':
  293. case 'g':
  294. case 'G':
  295. (void) va_arg(args, double);
  296. break;
  297. default:
  298. return(-1);
  299. }
  300. res = vsprintf(buf, conv_spec, vsprintf_args);
  301. len = (size_t)res;
  302. if ((char *)(GC_word)res == buf) {
  303. /* old style vsprintf */
  304. len = strlen(buf);
  305. } else if (res < 0) {
  306. return(-1);
  307. }
  308. if (buf != result[0].ec_bufptr) {
  309. register char c;
  310. while ((c = *buf++)) {
  311. CORD_ec_append(result, c);
  312. }
  313. } else {
  314. result[0].ec_bufptr = buf + len;
  315. }
  316. }
  317. done:;
  318. }
  319. } else {
  320. CORD_ec_append(result, current);
  321. }
  322. }
  323. count = ec_len(result);
  324. *out = CORD_balance(CORD_ec_to_cord(result));
  325. return(count);
  326. }
  327. int CORD_sprintf(CORD * out, CORD format, ...)
  328. {
  329. va_list args;
  330. int result;
  331. va_start(args, format);
  332. result = CORD_vsprintf(out, format, args);
  333. va_end(args);
  334. return(result);
  335. }
  336. int CORD_fprintf(FILE * f, CORD format, ...)
  337. {
  338. va_list args;
  339. int result;
  340. CORD out;
  341. va_start(args, format);
  342. result = CORD_vsprintf(&out, format, args);
  343. va_end(args);
  344. if (result > 0) CORD_put(out, f);
  345. return(result);
  346. }
  347. int CORD_vfprintf(FILE * f, CORD format, va_list args)
  348. {
  349. int result;
  350. CORD out;
  351. result = CORD_vsprintf(&out, format, args);
  352. if (result > 0) CORD_put(out, f);
  353. return(result);
  354. }
  355. int CORD_printf(CORD format, ...)
  356. {
  357. va_list args;
  358. int result;
  359. CORD out;
  360. va_start(args, format);
  361. result = CORD_vsprintf(&out, format, args);
  362. va_end(args);
  363. if (result > 0) CORD_put(out, stdout);
  364. return(result);
  365. }
  366. int CORD_vprintf(CORD format, va_list args)
  367. {
  368. int result;
  369. CORD out;
  370. result = CORD_vsprintf(&out, format, args);
  371. if (result > 0) CORD_put(out, stdout);
  372. return(result);
  373. }