hexdump.c revision 9979
1240116Smarcel/*- 2240116Smarcel * Copyright (c) 1986, 1988, 1991, 1993 3240116Smarcel * The Regents of the University of California. All rights reserved. 4240116Smarcel * (c) UNIX System Laboratories, Inc. 5240116Smarcel * All or some portions of this file are derived from material licensed 6240116Smarcel * to the University of California by American Telephone and Telegraph 7240116Smarcel * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8240116Smarcel * the permission of UNIX System Laboratories, Inc. 9240116Smarcel * 10240116Smarcel * Redistribution and use in source and binary forms, with or without 11240116Smarcel * modification, are permitted provided that the following conditions 12240116Smarcel * are met: 13240116Smarcel * 1. Redistributions of source code must retain the above copyright 14240116Smarcel * notice, this list of conditions and the following disclaimer. 15240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 16240116Smarcel * notice, this list of conditions and the following disclaimer in the 17240116Smarcel * documentation and/or other materials provided with the distribution. 18240116Smarcel * 3. All advertising materials mentioning features or use of this software 19240116Smarcel * must display the following acknowledgement: 20240116Smarcel * This product includes software developed by the University of 21240116Smarcel * California, Berkeley and its contributors. 22240116Smarcel * 4. Neither the name of the University nor the names of its contributors 23240116Smarcel * may be used to endorse or promote products derived from this software 24240116Smarcel * without specific prior written permission. 25240116Smarcel * 26240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28240116Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29272049Srodrigc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30240116Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33258289Sjmmv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36240116Smarcel * SUCH DAMAGE. 37240116Smarcel * 38258289Sjmmv * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94 39258289Sjmmv * $Id: subr_prf.c,v 1.15 1995/08/06 22:00:17 davidg Exp $ 40240116Smarcel */ 41240116Smarcel 42240116Smarcel#include <sys/param.h> 43240116Smarcel#include <sys/systm.h> 44240116Smarcel#include <sys/buf.h> 45240116Smarcel#include <sys/conf.h> 46240116Smarcel#include <sys/reboot.h> 47258289Sjmmv#include <sys/msgbuf.h> 48258289Sjmmv#include <sys/proc.h> 49240116Smarcel#include <sys/ioctl.h> 50240116Smarcel#include <sys/vnode.h> 51240116Smarcel#include <sys/file.h> 52240116Smarcel#include <sys/tty.h> 53240116Smarcel#include <sys/tprintf.h> 54240116Smarcel#include <sys/syslog.h> 55240116Smarcel#include <sys/malloc.h> 56240116Smarcel#include <machine/cons.h> 57240116Smarcel 58240116Smarcel/* 59240116Smarcel * Note that stdarg.h and the ANSI style va_start macro is used for both 60240116Smarcel * ANSI and traditional C compilers. 61240116Smarcel */ 62240116Smarcel#include <machine/stdarg.h> 63240116Smarcel 64240116Smarcel#ifdef KADB 65240116Smarcel#include <machine/kdbparam.h> 66240116Smarcel#endif 67240116Smarcel 68240116Smarcel 69240116Smarcel#define TOCONS 0x01 70240116Smarcel#define TOTTY 0x02 71240116Smarcel#define TOLOG 0x04 72240116Smarcel 73240116Smarcelstruct tty *constty; /* pointer to console "window" tty */ 74240116Smarcel 75240116Smarcelvoid (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ 76240116Smarcel 77240116Smarcelvoid logpri __P((int level)); 78240116Smarcelstatic void putchar __P((int ch, int flags, struct tty *tp)); 79240116Smarcelstatic char *ksprintn __P((u_long num, int base, int *len)); 80258289Sjmmv 81258289Sjmmvint consintr = 1; /* Ok to handle console interrupts? */ 82258289Sjmmv 83258289Sjmmv/* 84258289Sjmmv * Variable panicstr contains argument to first call to panic; used as flag 85258289Sjmmv * to indicate that the kernel has already called panic. 86258289Sjmmv */ 87258289Sjmmvconst char *panicstr; 88258289Sjmmv 89258289Sjmmv/* 90258289Sjmmv * Panic is called on unresolvable fatal errors. It prints "panic: mesg", 91258289Sjmmv * and then reboots. If we are called twice, then we avoid trying to sync 92258289Sjmmv * the disks as this often leads to recursive panics. 93240116Smarcel */ 94240116Smarcel#ifdef __GNUC__ 95240116Smarcel__dead /* panic() does not return */ 96240116Smarcel#endif 97240116Smarcelvoid 98240116Smarcel#ifdef __STDC__ 99240116Smarcelpanic(const char *fmt, ...) 100258289Sjmmv#else 101258289Sjmmvpanic(fmt, va_alist) 102240116Smarcel char *fmt; 103240116Smarcel#endif 104240116Smarcel{ 105240116Smarcel int bootopt; 106240116Smarcel va_list ap; 107240116Smarcel 108240116Smarcel bootopt = RB_AUTOBOOT | RB_DUMP; 109258289Sjmmv if (panicstr) 110258289Sjmmv bootopt |= RB_NOSYNC; 111240116Smarcel else 112240116Smarcel panicstr = fmt; 113240116Smarcel 114240116Smarcel va_start(ap, fmt); 115240116Smarcel printf("panic: %r\n", fmt, ap); 116240116Smarcel va_end(ap); 117240116Smarcel 118240116Smarcel#ifdef KGDB 119240116Smarcel kgdb_panic(); 120240116Smarcel#endif 121240116Smarcel#ifdef KADB 122240116Smarcel if (boothowto & RB_KDB) 123240116Smarcel kdbpanic(); 124240116Smarcel#endif 125240116Smarcel#ifdef DDB 126240116Smarcel Debugger ("panic"); 127240116Smarcel#endif 128240116Smarcel boot(bootopt); 129240116Smarcel} 130240116Smarcel 131240116Smarcel/* 132240116Smarcel * Warn that a system table is full. 133240116Smarcel */ 134240116Smarcelvoid 135240116Smarceltablefull(tab) 136240116Smarcel const char *tab; 137240116Smarcel{ 138240116Smarcel 139240116Smarcel log(LOG_ERR, "%s: table is full\n", tab); 140240116Smarcel} 141240116Smarcel 142240116Smarcel/* 143258289Sjmmv * Uprintf prints to the controlling terminal for the current process. 144258289Sjmmv * It may block if the tty queue is overfull. No message is printed if 145258289Sjmmv * the queue does not clear in a reasonable time. 146258289Sjmmv */ 147258289Sjmmvvoid 148258289Sjmmv#ifdef __STDC__ 149258289Sjmmvuprintf(const char *fmt, ...) 150258289Sjmmv#else 151258289Sjmmvuprintf(fmt, va_alist) 152258289Sjmmv char *fmt; 153258289Sjmmv#endif 154258289Sjmmv{ 155258289Sjmmv register struct proc *p = curproc; 156258289Sjmmv va_list ap; 157258289Sjmmv 158258289Sjmmv if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 159258289Sjmmv va_start(ap, fmt); 160258289Sjmmv kprintf(fmt, TOTTY, p->p_session->s_ttyp, ap); 161258289Sjmmv va_end(ap); 162258289Sjmmv } 163258289Sjmmv} 164258289Sjmmv 165258289Sjmmvtpr_t 166258289Sjmmvtprintf_open(p) 167258289Sjmmv register struct proc *p; 168258289Sjmmv{ 169258289Sjmmv 170258289Sjmmv if (p->p_flag & P_CONTROLT && p->p_session->s_ttyvp) { 171258289Sjmmv SESSHOLD(p->p_session); 172258289Sjmmv return ((tpr_t) p->p_session); 173258289Sjmmv } 174258289Sjmmv return ((tpr_t) NULL); 175258289Sjmmv} 176258289Sjmmv 177258289Sjmmvvoid 178258289Sjmmvtprintf_close(sess) 179258289Sjmmv tpr_t sess; 180258289Sjmmv{ 181258289Sjmmv 182258289Sjmmv if (sess) 183258289Sjmmv SESSRELE((struct session *) sess); 184258289Sjmmv} 185258289Sjmmv 186258289Sjmmv/* 187258289Sjmmv * tprintf prints on the controlling terminal associated 188258289Sjmmv * with the given session. 189258289Sjmmv */ 190258289Sjmmvvoid 191258289Sjmmv#ifdef __STDC__ 192258289Sjmmvtprintf(tpr_t tpr, const char *fmt, ...) 193258289Sjmmv#else 194258289Sjmmvtprintf(tpr, fmt, va_alist) 195258289Sjmmv tpr_t tpr; 196258289Sjmmv char *fmt; 197258289Sjmmv#endif 198258289Sjmmv{ 199258289Sjmmv register struct session *sess = (struct session *)tpr; 200258289Sjmmv struct tty *tp = NULL; 201258289Sjmmv int flags = TOLOG; 202258289Sjmmv va_list ap; 203258289Sjmmv 204240116Smarcel logpri(LOG_INFO); 205258289Sjmmv if (sess && sess->s_ttyvp && ttycheckoutq(sess->s_ttyp, 0)) { 206258289Sjmmv flags |= TOTTY; 207240116Smarcel tp = sess->s_ttyp; 208240116Smarcel } 209240116Smarcel va_start(ap, fmt); 210240116Smarcel kprintf(fmt, flags, tp, ap); 211240116Smarcel va_end(ap); 212240116Smarcel logwakeup(); 213240116Smarcel} 214240116Smarcel 215240116Smarcel/* 216240116Smarcel * Ttyprintf displays a message on a tty; it should be used only by 217240116Smarcel * the tty driver, or anything that knows the underlying tty will not 218240116Smarcel * be revoke(2)'d away. Other callers should use tprintf. 219240116Smarcel */ 220240116Smarcelvoid 221240116Smarcel#ifdef __STDC__ 222240116Smarcelttyprintf(struct tty *tp, const char *fmt, ...) 223240116Smarcel#else 224240116Smarcelttyprintf(tp, fmt, va_alist) 225240116Smarcel struct tty *tp; 226240116Smarcel char *fmt; 227240116Smarcel#endif 228240116Smarcel{ 229240116Smarcel va_list ap; 230240116Smarcel 231240116Smarcel va_start(ap, fmt); 232240116Smarcel kprintf(fmt, TOTTY, tp, ap); 233240116Smarcel va_end(ap); 234240116Smarcel} 235240116Smarcel 236240116Smarcelextern int log_open; 237240116Smarcel 238240116Smarcel/* 239240116Smarcel * Log writes to the log buffer, and guarantees not to sleep (so can be 240240116Smarcel * called by interrupt routines). If there is no process reading the 241240116Smarcel * log yet, it writes to the console also. 242240116Smarcel */ 243240116Smarcelvoid 244240116Smarcel#ifdef __STDC__ 245240116Smarcellog(int level, const char *fmt, ...) 246240116Smarcel#else 247240116Smarcellog(level, fmt, va_alist) 248240116Smarcel int level; 249240116Smarcel char *fmt; 250240116Smarcel#endif 251240116Smarcel{ 252240116Smarcel register int s; 253240116Smarcel va_list ap; 254240116Smarcel 255240116Smarcel s = splhigh(); 256240116Smarcel logpri(level); 257240116Smarcel va_start(ap, fmt); 258240116Smarcel kprintf(fmt, TOLOG, NULL, ap); 259240116Smarcel splx(s); 260240116Smarcel va_end(ap); 261240116Smarcel if (!log_open) { 262240116Smarcel va_start(ap, fmt); 263240116Smarcel kprintf(fmt, TOCONS, NULL, ap); 264240116Smarcel va_end(ap); 265240116Smarcel } 266240116Smarcel logwakeup(); 267240116Smarcel} 268240116Smarcel 269240116Smarcelvoid 270240116Smarcellogpri(level) 271240116Smarcel int level; 272240116Smarcel{ 273240116Smarcel register char *p; 274240116Smarcel 275240116Smarcel putchar('<', TOLOG, NULL); 276240116Smarcel for (p = ksprintn((u_long)level, 10, NULL); *p;) 277240116Smarcel putchar(*p--, TOLOG, NULL); 278240116Smarcel putchar('>', TOLOG, NULL); 279240116Smarcel} 280240116Smarcel 281240116Smarcelvoid 282240116Smarcel#ifdef __STDC__ 283240116Smarceladdlog(const char *fmt, ...) 284240116Smarcel#else 285240116Smarceladdlog(fmt, va_alist) 286240116Smarcel char *fmt; 287240116Smarcel#endif 288240116Smarcel{ 289240116Smarcel register int s; 290240116Smarcel va_list ap; 291240116Smarcel 292240116Smarcel s = splhigh(); 293240116Smarcel va_start(ap, fmt); 294240116Smarcel kprintf(fmt, TOLOG, NULL, ap); 295240116Smarcel splx(s); 296240116Smarcel va_end(ap); 297240116Smarcel if (!log_open) { 298240116Smarcel va_start(ap, fmt); 299240116Smarcel kprintf(fmt, TOCONS, NULL, ap); 300240116Smarcel va_end(ap); 301240116Smarcel } 302240116Smarcel logwakeup(); 303240116Smarcel} 304240116Smarcel 305240116Smarcelvoid 306240116Smarcel#ifdef __STDC__ 307240116Smarcelprintf(const char *fmt, ...) 308240116Smarcel#else 309240116Smarcelprintf(fmt, va_alist) 310240116Smarcel char *fmt; 311240116Smarcel#endif 312240116Smarcel{ 313240116Smarcel va_list ap; 314240116Smarcel register int savintr; 315240116Smarcel 316240116Smarcel savintr = consintr; /* disable interrupts */ 317240116Smarcel consintr = 0; 318240116Smarcel va_start(ap, fmt); 319240116Smarcel kprintf(fmt, TOCONS | TOLOG, NULL, ap); 320240116Smarcel va_end(ap); 321240116Smarcel if (!panicstr) 322240116Smarcel logwakeup(); 323240116Smarcel consintr = savintr; /* reenable interrupts */ 324240116Smarcel} 325240116Smarcel 326240116Smarcel/* 327240116Smarcel * Scaled down version of printf(3). 328240116Smarcel * 329240116Smarcel * Two additional formats: 330240116Smarcel * 331240116Smarcel * The format %b is supported to decode error registers. 332240116Smarcel * Its usage is: 333240116Smarcel * 334240116Smarcel * printf("reg=%b\n", regval, "<base><arg>*"); 335240116Smarcel * 336240116Smarcel * where <base> is the output base expressed as a control character, e.g. 337240116Smarcel * \10 gives octal; \20 gives hex. Each arg is a sequence of characters, 338240116Smarcel * the first of which gives the bit number to be inspected (origin 1), and 339240116Smarcel * the next characters (up to a control character, i.e. a character <= 32), 340240116Smarcel * give the name of the register. Thus: 341240116Smarcel * 342240116Smarcel * kprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n"); 343240116Smarcel * 344240116Smarcel * would produce output: 345240116Smarcel * 346240116Smarcel * reg=3<BITTWO,BITONE> 347240116Smarcel * 348240116Smarcel * The format %r passes an additional format string and argument list 349240116Smarcel * recursively. Its usage is: 350240116Smarcel * 351240116Smarcel * fn(char *fmt, ...) 352240116Smarcel * { 353240116Smarcel * va_list ap; 354240116Smarcel * va_start(ap, fmt); 355240116Smarcel * printf("prefix: %r: suffix\n", fmt, ap); 356240116Smarcel * va_end(ap); 357240116Smarcel * } 358240116Smarcel * 359240116Smarcel * Space or zero padding and a field width are supported for the numeric 360240116Smarcel * formats only. 361240116Smarcel */ 362240116Smarcelvoid 363240116Smarcelkprintf(fmt, flags, tp, ap) 364240116Smarcel register const char *fmt; 365240116Smarcel int flags; 366240116Smarcel struct tty *tp; 367240116Smarcel va_list ap; 368240116Smarcel{ 369240116Smarcel register char *p, *q; 370240116Smarcel register int ch, n; 371240116Smarcel u_long ul; 372240116Smarcel int base, lflag, tmp, width; 373240116Smarcel char padc; 374240116Smarcel 375240116Smarcel if (fmt == NULL) 376240116Smarcel fmt = "(fmt null)\n"; 377240116Smarcel for (;;) { 378240116Smarcel padc = ' '; 379240116Smarcel width = 0; 380240116Smarcel while ((ch = *(u_char *)fmt++) != '%') { 381240116Smarcel if (ch == '\0') 382240116Smarcel return; 383240116Smarcel putchar(ch, flags, tp); 384240116Smarcel } 385240116Smarcel lflag = 0; 386240116Smarcelreswitch: switch (ch = *(u_char *)fmt++) { 387240116Smarcel case '0': 388240116Smarcel padc = '0'; 389240116Smarcel goto reswitch; 390240116Smarcel case '1': case '2': case '3': case '4': 391240116Smarcel case '5': case '6': case '7': case '8': case '9': 392240116Smarcel for (width = 0;; ++fmt) { 393240116Smarcel width = width * 10 + ch - '0'; 394240116Smarcel ch = *fmt; 395240116Smarcel if (ch < '0' || ch > '9') 396240116Smarcel break; 397240116Smarcel } 398240116Smarcel goto reswitch; 399240116Smarcel case 'l': 400240116Smarcel lflag = 1; 401240116Smarcel goto reswitch; 402240116Smarcel case 'b': 403240116Smarcel ul = va_arg(ap, int); 404240116Smarcel p = va_arg(ap, char *); 405240116Smarcel for (q = ksprintn(ul, *p++, NULL); *q;) 406240116Smarcel putchar(*q--, flags, tp); 407240116Smarcel 408240116Smarcel if (!ul) 409240116Smarcel break; 410240116Smarcel 411240116Smarcel for (tmp = 0; *p;) { 412272049Srodrigc n = *p++; 413272049Srodrigc if (ul & (1 << (n - 1))) { 414240116Smarcel putchar(tmp ? ',' : '<', flags, tp); 415240116Smarcel for (; (n = *p) > ' '; ++p) 416240116Smarcel putchar(n, flags, tp); 417240116Smarcel tmp = 1; 418240116Smarcel } else 419240116Smarcel for (; *p > ' '; ++p) 420240116Smarcel continue; 421240116Smarcel } 422240116Smarcel if (tmp) 423240116Smarcel putchar('>', flags, tp); 424240116Smarcel break; 425240116Smarcel case 'c': 426240116Smarcel putchar(va_arg(ap, int), flags, tp); 427240116Smarcel break; 428240116Smarcel case 'r': 429240116Smarcel p = va_arg(ap, char *); 430240116Smarcel kprintf(p, flags, tp, va_arg(ap, va_list)); 431240116Smarcel break; 432240116Smarcel case 's': 433240116Smarcel p = va_arg(ap, char *); 434240116Smarcel if (p == NULL) 435240116Smarcel p = "(null)"; 436240116Smarcel while (*p) 437240116Smarcel putchar(*p++, flags, tp); 438240116Smarcel break; 439240116Smarcel case 'd': 440240116Smarcel ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 441240116Smarcel if ((long)ul < 0) { 442240116Smarcel putchar('-', flags, tp); 443240116Smarcel ul = -(long)ul; 444240116Smarcel } 445272049Srodrigc base = 10; 446272049Srodrigc goto number; 447240116Smarcel case 'o': 448240116Smarcel ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 449240116Smarcel base = 8; 450240116Smarcel goto number; 451240116Smarcel case 'p': 452240116Smarcel ul = (u_long)va_arg(ap, void *); 453240116Smarcel base = 16; 454240116Smarcel putchar('0', flags, tp); 455240116Smarcel putchar('x', flags, tp); 456240116Smarcel goto number; 457240116Smarcel case 'u': 458240116Smarcel ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 459240116Smarcel base = 10; 460240116Smarcel goto number; 461240116Smarcel case 'x': 462240116Smarcel ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 463240116Smarcel base = 16; 464258289Sjmmvnumber: p = ksprintn(ul, base, &tmp); 465240116Smarcel if (width && (width -= tmp) > 0) 466240116Smarcel while (width--) 467240116Smarcel putchar(padc, flags, tp); 468240116Smarcel while (*p) 469240116Smarcel putchar(*p--, flags, tp); 470240116Smarcel break; 471240116Smarcel default: 472240116Smarcel putchar('%', flags, tp); 473240116Smarcel if (lflag) 474240116Smarcel putchar('l', flags, tp); 475240116Smarcel /* FALLTHROUGH */ 476240116Smarcel case '%': 477240116Smarcel putchar(ch, flags, tp); 478240116Smarcel } 479240116Smarcel } 480240116Smarcel} 481240116Smarcel 482240116Smarcel/* 483240116Smarcel * Print a character on console or users terminal. If destination is 484240116Smarcel * the console then the last MSGBUFS characters are saved in msgbuf for 485240116Smarcel * inspection later. 486240116Smarcel */ 487240116Smarcelstatic void 488240116Smarcelputchar(c, flags, tp) 489240116Smarcel register int c; 490240116Smarcel int flags; 491240116Smarcel struct tty *tp; 492240116Smarcel{ 493240116Smarcel register struct msgbuf *mbp; 494240116Smarcel 495240116Smarcel if (panicstr) 496240116Smarcel constty = NULL; 497240116Smarcel if ((flags & TOCONS) && tp == NULL && constty) { 498240116Smarcel tp = constty; 499258289Sjmmv flags |= TOTTY; 500258289Sjmmv } 501258289Sjmmv if ((flags & TOTTY) && tp && tputchar(c, tp) < 0 && 502258289Sjmmv (flags & TOCONS) && tp == constty) 503258289Sjmmv constty = NULL; 504258289Sjmmv if ((flags & TOLOG) && 505258289Sjmmv c != '\0' && c != '\r' && c != 0177 && msgbufmapped) { 506258289Sjmmv mbp = msgbufp; 507258289Sjmmv if (mbp->msg_magic != MSG_MAGIC || 508258289Sjmmv mbp->msg_bufx >= MSG_BSIZE || 509240116Smarcel mbp->msg_bufr >= MSG_BSIZE) { 510240116Smarcel bzero(mbp, sizeof(struct msgbuf)); 511240116Smarcel mbp->msg_magic = MSG_MAGIC; 512240116Smarcel } 513240116Smarcel mbp->msg_bufc[mbp->msg_bufx++] = c; 514240116Smarcel if (mbp->msg_bufx < 0 || mbp->msg_bufx >= MSG_BSIZE) 515240116Smarcel mbp->msg_bufx = 0; 516240116Smarcel /* If the buffer is full, keep the most recent data. */ 517240116Smarcel if (mbp->msg_bufr == mbp->msg_bufx) { 518240116Smarcel if (++mbp->msg_bufr >= MSG_BSIZE) 519240116Smarcel mbp->msg_bufr = 0; 520240116Smarcel } 521240116Smarcel } 522240116Smarcel if ((flags & TOCONS) && constty == NULL && c != '\0') 523240116Smarcel (*v_putc)(c); 524240116Smarcel} 525258289Sjmmv 526258289Sjmmv/* 527258289Sjmmv * Scaled down version of sprintf(3). 528258289Sjmmv */ 529258289Sjmmv#ifdef __STDC__ 530258289Sjmmvint 531258289Sjmmvsprintf(char *buf, const char *cfmt, ...) 532258289Sjmmv#else 533258289Sjmmvint 534258289Sjmmvsprintf(buf, cfmt, va_alist) 535258289Sjmmv char *buf, *cfmt; 536258289Sjmmv#endif 537258289Sjmmv{ 538258289Sjmmv register const char *fmt = cfmt; 539258289Sjmmv register char *p, *bp; 540258289Sjmmv register int ch, base; 541258289Sjmmv u_long ul; 542258289Sjmmv int lflag; 543258289Sjmmv va_list ap; 544258289Sjmmv 545258289Sjmmv va_start(ap, cfmt); 546258289Sjmmv for (bp = buf; ; ) { 547258289Sjmmv while ((ch = *(u_char *)fmt++) != '%') 548258289Sjmmv if ((*bp++ = ch) == '\0') 549258289Sjmmv return ((bp - buf) - 1); 550258289Sjmmv 551258289Sjmmv lflag = 0; 552258289Sjmmvreswitch: switch (ch = *(u_char *)fmt++) { 553258289Sjmmv case 'l': 554258289Sjmmv lflag = 1; 555258289Sjmmv goto reswitch; 556258289Sjmmv case 'c': 557258289Sjmmv *bp++ = va_arg(ap, int); 558258289Sjmmv break; 559258289Sjmmv case 's': 560258289Sjmmv p = va_arg(ap, char *); 561258289Sjmmv while (*p) 562258289Sjmmv *bp++ = *p++; 563258289Sjmmv break; 564258289Sjmmv case 'd': 565258289Sjmmv ul = lflag ? va_arg(ap, long) : va_arg(ap, int); 566258289Sjmmv if ((long)ul < 0) { 567258289Sjmmv *bp++ = '-'; 568258289Sjmmv ul = -(long)ul; 569258289Sjmmv } 570258289Sjmmv base = 10; 571258289Sjmmv goto number; 572258289Sjmmv break; 573258289Sjmmv case 'o': 574258289Sjmmv ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 575258289Sjmmv base = 8; 576258289Sjmmv goto number; 577258289Sjmmv break; 578258289Sjmmv case 'p': 579258289Sjmmv ul = (u_long)va_arg(ap, void *); 580258289Sjmmv base = 16; 581258289Sjmmv *bp++ = '0'; 582258289Sjmmv *bp++ = 'x'; 583258289Sjmmv goto number; 584258289Sjmmv case 'u': 585258289Sjmmv ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 586258289Sjmmv base = 10; 587258289Sjmmv goto number; 588258289Sjmmv break; 589258289Sjmmv case 'x': 590258289Sjmmv ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int); 591258289Sjmmv base = 16; 592258289Sjmmvnumber: for (p = ksprintn(ul, base, NULL); *p;) 593258289Sjmmv *bp++ = *p--; 594258289Sjmmv break; 595258289Sjmmv default: 596258289Sjmmv *bp++ = '%'; 597258289Sjmmv if (lflag) 598258289Sjmmv *bp++ = 'l'; 599258289Sjmmv /* FALLTHROUGH */ 600258289Sjmmv case '%': 601258289Sjmmv *bp++ = ch; 602258289Sjmmv } 603258289Sjmmv } 604258289Sjmmv va_end(ap); 605258289Sjmmv} 606258289Sjmmv 607258289Sjmmv/* 608258289Sjmmv * Put a number (base <= 16) in a buffer in reverse order; return an 609258289Sjmmv * optional length and a pointer to the NULL terminated (preceded?) 610258289Sjmmv * buffer. 611258289Sjmmv */ 612258289Sjmmvstatic char * 613258289Sjmmvksprintn(ul, base, lenp) 614258289Sjmmv register u_long ul; 615258289Sjmmv register int base, *lenp; 616258289Sjmmv{ /* A long in base 8, plus NULL. */ 617258289Sjmmv static char buf[sizeof(long) * NBBY / 3 + 2]; 618258289Sjmmv register char *p; 619258289Sjmmv 620258289Sjmmv p = buf; 621258289Sjmmv do { 622258289Sjmmv *++p = "0123456789abcdef"[ul % base]; 623258289Sjmmv } while (ul /= base); 624258289Sjmmv if (lenp) 625258289Sjmmv *lenp = p - buf; 626258289Sjmmv return (p); 627258289Sjmmv} 628258289Sjmmv