printf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*
  2. * Mach Operating System
  3. * Copyright (c) 1993 Carnegie Mellon University
  4. * All Rights Reserved.
  5. *
  6. * Permission to use, copy, modify and distribute this software and its
  7. * documentation is hereby granted, provided that both the copyright
  8. * notice and this permission notice appear in all copies of the
  9. * software, derivative works or modified versions, and any portions
  10. * thereof, and that both notices appear in supporting documentation.
  11. *
  12. * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
  13. * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
  14. * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
  15. *
  16. * Carnegie Mellon requests users of this software to return to
  17. *
  18. * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
  19. * School of Computer Science
  20. * Carnegie Mellon University
  21. * Pittsburgh PA 15213-3890
  22. *
  23. * any improvements or extensions that they make and grant Carnegie Mellon
  24. * the rights to redistribute these changes.
  25. */
  26. /*
  27. * Common code for printf et al.
  28. *
  29. * The calling routine typically takes a variable number of arguments,
  30. * and passes the address of the first one. This implementation
  31. * assumes a straightforward, stack implementation, aligned to the
  32. * machine's wordsize. Increasing addresses are assumed to point to
  33. * successive arguments (left-to-right), as is the case for a machine
  34. * with a downward-growing stack with arguments pushed right-to-left.
  35. *
  36. * To write, for example, fprintf() using this routine, the code
  37. *
  38. * fprintf(fd, format, args)
  39. * FILE *fd;
  40. * char *format;
  41. * {
  42. * va_list listp;
  43. * va_start(listp, fmt);
  44. * _doprnt(format, &args, fd);
  45. * va_end(listp);
  46. * }
  47. *
  48. * would suffice. (This example does not handle the fprintf's "return
  49. * value" correctly, but who looks at the return value of fprintf
  50. * anyway?)
  51. *
  52. * This version implements the following printf features:
  53. *
  54. * %d decimal conversion
  55. * %u unsigned conversion
  56. * %p pointer address
  57. * %x hexadecimal conversion
  58. * %X hexadecimal conversion with capital letters
  59. * %o octal conversion
  60. * %c character
  61. * %s string
  62. * %m.n field width, precision
  63. * %-m.n left adjustment
  64. * %0m.n zero-padding
  65. * %*.* width and precision taken from arguments
  66. *
  67. * This version does not implement %f, %e, or %g. It accepts, but
  68. * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not
  69. * work correctly on machines for which sizeof(long) != sizeof(int).
  70. * It does not even parse %D, %O, or %U; you should be using %ld, %o and
  71. * %lu if you mean long conversion.
  72. *
  73. * As mentioned, this version does not return any reasonable value.
  74. *
  75. * Permission is granted to use, modify, or propagate this code as
  76. * long as this notice is incorporated.
  77. *
  78. * Steve Summit 3/25/87
  79. */
  80. /*
  81. * Added formats for decoding device registers:
  82. *
  83. * printf("reg = %b", regval, "<base><arg>*")
  84. *
  85. * where <base> is the output base expressed as a control character:
  86. * i.e. '\10' gives octal, '\20' gives hex. Each <arg> is a sequence of
  87. * characters, the first of which gives the bit number to be inspected
  88. * (origin 1), and the rest (up to a control character (<= 32)) give the
  89. * name of the register. Thus
  90. * printf("reg = %b\n", 3, "\10\2BITTWO\1BITONE")
  91. * would produce
  92. * reg = 3<BITTWO,BITONE>
  93. *
  94. * If the second character in <arg> is also a control character, it
  95. * indicates the last bit of a bit field. In this case, printf will extract
  96. * bits <1> to <2> and print it. Characters following the second control
  97. * character are printed before the bit field.
  98. * printf("reg = %b\n", 0xb, "\10\4\3FIELD1=\2BITTWO\1BITONE")
  99. * would produce
  100. * reg = b<FIELD1=2,BITONE>
  101. */
  102. /*
  103. * Added for general use:
  104. * # prefix for alternate format:
  105. * 0x (0X) for hex
  106. * leading 0 for octal
  107. * + print '+' if positive
  108. * blank print ' ' if positive
  109. *
  110. * z signed hexadecimal
  111. * r signed, 'radix'
  112. * n unsigned, 'radix'
  113. *
  114. * D,U,O,Z same as corresponding lower-case versions
  115. * (compatibility)
  116. */
  117. #include <string.h>
  118. #include <device/cons.h>
  119. #include <kern/printf.h>
  120. #include <mach/boolean.h>
  121. #include <kern/lock.h>
  122. #include <stdarg.h>
  123. #define isdigit(d) ((d) >= '0' && (d) <= '9')
  124. #define Ctod(c) ((c) - '0')
  125. #define MAXBUF (sizeof(long long int) * 8) /* enough for binary */
  126. void printnum(
  127. unsigned long long u,
  128. int base,
  129. void (*putc)( char, vm_offset_t ),
  130. vm_offset_t putc_arg)
  131. {
  132. char buf[MAXBUF]; /* build number here */
  133. char * p = &buf[MAXBUF-1];
  134. static char digs[] = "0123456789abcdef";
  135. do {
  136. *p-- = digs[u % base];
  137. u /= base;
  138. } while (u != 0);
  139. while (++p != &buf[MAXBUF])
  140. (*putc)(*p, putc_arg);
  141. }
  142. boolean_t _doprnt_truncates = FALSE;
  143. void _doprnt(
  144. const char *fmt,
  145. va_list argp,
  146. /* character output routine */
  147. void (*putc)( char, vm_offset_t),
  148. int radix, /* default radix - for '%r' */
  149. vm_offset_t putc_arg)
  150. {
  151. int length;
  152. int prec;
  153. boolean_t ladjust;
  154. char padc;
  155. long long n;
  156. unsigned long long u;
  157. int have_long_long;
  158. int plus_sign;
  159. int sign_char;
  160. boolean_t altfmt, truncate;
  161. int base;
  162. char c;
  163. while ((c = *fmt) != '\0') {
  164. if (c != '%') {
  165. (*putc)(c, putc_arg);
  166. fmt++;
  167. continue;
  168. }
  169. fmt++;
  170. length = 0;
  171. prec = -1;
  172. ladjust = FALSE;
  173. padc = ' ';
  174. plus_sign = 0;
  175. sign_char = 0;
  176. altfmt = FALSE;
  177. have_long_long = FALSE;
  178. while (TRUE) {
  179. c = *fmt;
  180. if (c == '#') {
  181. altfmt = TRUE;
  182. }
  183. else if (c == '-') {
  184. ladjust = TRUE;
  185. }
  186. else if (c == '+') {
  187. plus_sign = '+';
  188. }
  189. else if (c == ' ') {
  190. if (plus_sign == 0)
  191. plus_sign = ' ';
  192. }
  193. else
  194. break;
  195. fmt++;
  196. }
  197. if (c == '0') {
  198. padc = '0';
  199. c = *++fmt;
  200. }
  201. if (isdigit(c)) {
  202. while(isdigit(c)) {
  203. length = 10 * length + Ctod(c);
  204. c = *++fmt;
  205. }
  206. }
  207. else if (c == '*') {
  208. length = va_arg(argp, int);
  209. c = *++fmt;
  210. if (length < 0) {
  211. ladjust = !ladjust;
  212. length = -length;
  213. }
  214. }
  215. if (c == '.') {
  216. c = *++fmt;
  217. if (isdigit(c)) {
  218. prec = 0;
  219. while(isdigit(c)) {
  220. prec = 10 * prec + Ctod(c);
  221. c = *++fmt;
  222. }
  223. }
  224. else if (c == '*') {
  225. prec = va_arg(argp, int);
  226. c = *++fmt;
  227. }
  228. }
  229. if (c == 'l')
  230. c = *++fmt; /* need it if sizeof(int) < sizeof(long) */
  231. if (c == 'l') {
  232. c = *++fmt; /* handle `long long' */
  233. have_long_long = TRUE;
  234. }
  235. truncate = FALSE;
  236. switch(c) {
  237. case 'b':
  238. case 'B':
  239. {
  240. char *p;
  241. boolean_t any;
  242. int i;
  243. if (! have_long_long)
  244. u = va_arg(argp, unsigned long);
  245. else
  246. u = va_arg(argp, unsigned long long);
  247. p = va_arg(argp, char *);
  248. base = *p++;
  249. printnum(u, base, putc, putc_arg);
  250. if (u == 0)
  251. break;
  252. any = FALSE;
  253. while ((i = *p++)) {
  254. /* NOTE: The '32' here is because ascii space */
  255. if (*p <= 32) {
  256. /*
  257. * Bit field
  258. */
  259. int j;
  260. if (any)
  261. (*putc)(',', putc_arg);
  262. else {
  263. (*putc)('<', putc_arg);
  264. any = TRUE;
  265. }
  266. j = *p++;
  267. for (; (c = *p) > 32; p++)
  268. (*putc)(c, putc_arg);
  269. printnum((unsigned)( (u>>(j-1)) & ((2<<(i-j))-1)),
  270. base, putc, putc_arg);
  271. }
  272. else if (u & (1<<(i-1))) {
  273. if (any)
  274. (*putc)(',', putc_arg);
  275. else {
  276. (*putc)('<', putc_arg);
  277. any = TRUE;
  278. }
  279. for (; (c = *p) > 32; p++)
  280. (*putc)(c, putc_arg);
  281. }
  282. else {
  283. for (; *p > 32; p++)
  284. continue;
  285. }
  286. }
  287. if (any)
  288. (*putc)('>', putc_arg);
  289. break;
  290. }
  291. case 'c':
  292. c = va_arg(argp, int);
  293. (*putc)(c, putc_arg);
  294. break;
  295. case 's':
  296. {
  297. char *p;
  298. char *p2;
  299. if (prec == -1)
  300. prec = 0x7fffffff; /* MAXINT */
  301. p = va_arg(argp, char *);
  302. if (p == (char *)0)
  303. p = "";
  304. if (length > 0 && !ladjust) {
  305. n = 0;
  306. p2 = p;
  307. for (; *p != '\0' && n < prec; p++)
  308. n++;
  309. p = p2;
  310. while (n < length) {
  311. (*putc)(' ', putc_arg);
  312. n++;
  313. }
  314. }
  315. n = 0;
  316. while (*p != '\0') {
  317. if (++n > prec)
  318. break;
  319. (*putc)(*p++, putc_arg);
  320. }
  321. if (n < length && ladjust) {
  322. while (n < length) {
  323. (*putc)(' ', putc_arg);
  324. n++;
  325. }
  326. }
  327. break;
  328. }
  329. case 'o':
  330. truncate = _doprnt_truncates;
  331. case 'O':
  332. base = 8;
  333. goto print_unsigned;
  334. case 'd':
  335. truncate = _doprnt_truncates;
  336. case 'D':
  337. base = 10;
  338. goto print_signed;
  339. case 'u':
  340. truncate = _doprnt_truncates;
  341. case 'U':
  342. base = 10;
  343. goto print_unsigned;
  344. case 'p':
  345. case 'x':
  346. truncate = _doprnt_truncates;
  347. case 'X':
  348. base = 16;
  349. goto print_unsigned;
  350. case 'z':
  351. truncate = _doprnt_truncates;
  352. case 'Z':
  353. base = 16;
  354. goto print_signed;
  355. case 'r':
  356. truncate = _doprnt_truncates;
  357. case 'R':
  358. base = radix;
  359. goto print_signed;
  360. case 'n':
  361. truncate = _doprnt_truncates;
  362. case 'N':
  363. base = radix;
  364. goto print_unsigned;
  365. print_signed:
  366. if (! have_long_long)
  367. n = va_arg(argp, long);
  368. else
  369. n = va_arg(argp, long long);
  370. if (n >= 0) {
  371. u = n;
  372. sign_char = plus_sign;
  373. }
  374. else {
  375. u = -n;
  376. sign_char = '-';
  377. }
  378. goto print_num;
  379. print_unsigned:
  380. if (! have_long_long)
  381. u = va_arg(argp, unsigned long);
  382. else
  383. u = va_arg(argp, unsigned long long);
  384. goto print_num;
  385. print_num:
  386. {
  387. char buf[MAXBUF]; /* build number here */
  388. char * p = &buf[MAXBUF-1];
  389. static char digits[] = "0123456789abcdef";
  390. char *prefix = 0;
  391. if (truncate) u = (long)((int)(u));
  392. if (u != 0 && altfmt) {
  393. if (base == 8)
  394. prefix = "0";
  395. else if (base == 16)
  396. prefix = "0x";
  397. }
  398. do {
  399. *p-- = digits[u % base];
  400. u /= base;
  401. } while (u != 0);
  402. length -= (&buf[MAXBUF-1] - p);
  403. if (sign_char)
  404. length--;
  405. if (prefix)
  406. length -= strlen(prefix);
  407. if (padc == ' ' && !ladjust) {
  408. /* blank padding goes before prefix */
  409. while (--length >= 0)
  410. (*putc)(' ', putc_arg);
  411. }
  412. if (sign_char)
  413. (*putc)(sign_char, putc_arg);
  414. if (prefix)
  415. while (*prefix)
  416. (*putc)(*prefix++, putc_arg);
  417. if (padc == '0') {
  418. /* zero padding goes after sign and prefix */
  419. while (--length >= 0)
  420. (*putc)('0', putc_arg);
  421. }
  422. while (++p != &buf[MAXBUF])
  423. (*putc)(*p, putc_arg);
  424. if (ladjust) {
  425. while (--length >= 0)
  426. (*putc)(' ', putc_arg);
  427. }
  428. break;
  429. }
  430. case '\0':
  431. fmt--;
  432. break;
  433. default:
  434. (*putc)(c, putc_arg);
  435. }
  436. fmt++;
  437. }
  438. }
  439. /*
  440. * Printing (to console)
  441. */
  442. int vprintf(const char *fmt, va_list listp)
  443. {
  444. _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
  445. return 0;
  446. }
  447. /*VARARGS1*/
  448. int printf(const char *fmt, ...)
  449. {
  450. va_list listp;
  451. va_start(listp, fmt);
  452. vprintf(fmt, listp);
  453. va_end(listp);
  454. return 0;
  455. }
  456. int indent = 0;
  457. /*
  458. * Printing (to console) with indentation.
  459. */
  460. /*VARARGS1*/
  461. void iprintf(const char *fmt, ...)
  462. {
  463. va_list listp;
  464. int i;
  465. for (i = indent; i > 0; ){
  466. if (i >= 8) {
  467. printf("\t");
  468. i -= 8;
  469. }
  470. else {
  471. printf(" ");
  472. i--;
  473. }
  474. }
  475. va_start(listp, fmt);
  476. _doprnt(fmt, listp, (void (*)( char, vm_offset_t)) cnputc, 16, 0);
  477. va_end(listp);
  478. }
  479. /*
  480. * Printing to generic buffer
  481. * Returns #bytes printed.
  482. * Strings are zero-terminated.
  483. */
  484. static void
  485. sputc(
  486. char c,
  487. vm_offset_t arg)
  488. {
  489. char **bufp = (char **) arg;
  490. char *p = *bufp;
  491. *p++ = c;
  492. *bufp = p;
  493. }
  494. int
  495. sprintf(char *buf, const char *fmt, ...)
  496. {
  497. va_list listp;
  498. char *start = buf;
  499. va_start(listp, fmt);
  500. _doprnt(fmt, listp, sputc, 16, (vm_offset_t)&buf);
  501. va_end(listp);
  502. *buf = 0;
  503. return (buf - start);
  504. }
  505. struct vsnprintf_cookie
  506. {
  507. char *buf;
  508. int index;
  509. int max_len;
  510. };
  511. static void
  512. snputc(char c, vm_offset_t arg)
  513. {
  514. struct vsnprintf_cookie *cookie = (void *) arg;
  515. if (cookie->index < cookie->max_len)
  516. cookie->buf[cookie->index ++] = c;
  517. }
  518. int
  519. vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  520. {
  521. struct vsnprintf_cookie cookie
  522. = { .buf = buf, .index = 0, .max_len = size };
  523. _doprnt (fmt, args, snputc, 16, (vm_offset_t)&cookie);
  524. cookie.buf[cookie.index] = '\0';
  525. return cookie.index;
  526. }
  527. int
  528. snprintf(char *buf, size_t size, const char *fmt, ...)
  529. {
  530. int written;
  531. va_list listp;
  532. va_start(listp, fmt);
  533. written = vsnprintf(buf, size, fmt, listp);
  534. va_end(listp);
  535. return written;
  536. }
  537. void safe_gets(
  538. char *str,
  539. int maxlen)
  540. {
  541. char *lp;
  542. int c;
  543. char *strmax = str + maxlen - 1; /* allow space for trailing 0 */
  544. lp = str;
  545. for (;;) {
  546. c = cngetc();
  547. switch (c) {
  548. case '\n':
  549. case '\r':
  550. printf("\n");
  551. *lp++ = 0;
  552. return;
  553. case '\b':
  554. case '#':
  555. case '\177':
  556. if (lp > str) {
  557. printf("\b \b");
  558. lp--;
  559. }
  560. continue;
  561. case '@':
  562. case 'u'&037:
  563. lp = str;
  564. printf("\n\r");
  565. continue;
  566. default:
  567. if (c >= ' ' && c < '\177') {
  568. if (lp < strmax) {
  569. *lp++ = c;
  570. printf("%c", c);
  571. }
  572. else {
  573. printf("%c", '\007'); /* beep */
  574. }
  575. }
  576. }
  577. }
  578. }