/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ /* * Modified April-89 by Tom (squeeze...) Hageman * - some efficiency improvements * - added %x %X %O %r (remote fmt, arg) directives. * - padding with '0' only for numeric types. * - %n directive does not eat an argument; takes last used number instead * [25-Jan-93] * - %N (show numeric argument) */ #include "jove.h" RCS("$Id: fmt.c,v 14.30.0.10 1994/04/22 18:24:23 tom Exp tom $") #include "ctype.h" #include "io.h" #ifndef TINY DEF_INT( "prompt-with-prefix-arg", ShowExp, V_BOOL ) ZERO; _IF(ndef TINY)_IF(def PRIVATE) #endif char mesgbuf[MESG_SIZE]; private char *PPchar __(( unsigned int _(c) )); private char * PPchar(c) register unsigned int c; { static char CTLtemplate[] = "C-x"; #ifdef FUNCKEYS if (c >= 0200) { static char FKtemplate[] = "^:xx"; if ((c &= 0177) >= NFKEYS || (c = FKeyMap[c]) == 0) c = '?' | ('?' << 8); /* i.e. '??' */ *(short *) &FKtemplate[2] = c; return FKtemplate; } else /* the next `if' */ #endif if (isctrl(c)) { if (c == ESC) return "ESC"; CTLtemplate[2] = c ^ '@'; return CTLtemplate; } else if (c == ' ') return "SPC"; CTLtemplate[2] = c; return &CTLtemplate[2]; } private struct { File *sp; int base; int width; char zeropad; char leftadj; } curiop; private void puts __(( const char *_(str) )); private void puts(str) const char *str; { register File *sp = curiop.sp; register const char *s; register int w; if ((s = str) == NULL) #if pyr s = NullStr; #else s = "(null)"; #endif if ((w = curiop.width) > 0) { w -= strlen(s); if (!curiop.leftadj) while (--w >= 0) putc(' ', sp); } while (*s) putc(*s++, sp); while (--w >= 0) putc(' ', sp); } private void putld __(( long _(d) )); private void putld(d) register long d; { static const char Digits[] = "0123456789abcdef"; char buf[100]; register char *s = &buf[sizeof buf]; register int sign = 0; register int w = curiop.width; if (d < 0) { d = -d; --w; sign++; } *--s = '\0'; do { --w; *--s = Digits[d % curiop.base]; } while (d /= curiop.base); if (curiop.zeropad) { while (--w >= 0) *--s = '0'; } if (sign) *--s = '-'; puts(s); } private void doformat __(( File *_(sp), const char *_(fmt), va_list _(ap) )); private void doformat(sp, fmt, ap) File *sp; register const char *fmt; va_register va_list ap; { register int c; register long value; curiop.sp = sp; curiop.base = 10; while (c = *fmt++) { if (c != '%') { putc(c, sp); continue; } curiop.zeropad = curiop.leftadj = curiop.width = 0; c = *fmt++; if (c == '-') { curiop.leftadj++; c = *fmt++; } if (c == '0') { curiop.zeropad++; c = *fmt++; } while (isdigit(c)) { curiop.width = curiop.width * 10 + (c - '0'); c = *fmt++; } if (c == '*') { curiop.width = va_arg(ap, int); c = *fmt++; } reswitch: /* At this point, fmt points at one past the format letter. */ /* {JOVE-specific formats are marked with !!} */ switch (c) { case '%': putc(c, sp); continue; case 'X': /* curiop.base = 16; */ curiop.base -= 8 - 16; /* fall into... */ case 'O': /* curiop.base = 8; */ curiop.base -= 10 - 8; /* fall into... */ case 'D': value = va_arg(ap, long); break; case 'b': /* !insert current buffer name! */ puts(va_arg(ap, Buffer *)->b_name); continue; case 'c': { static char ch[2] ZERO; ch[0] = va_arg(ap, int); puts(ch); continue; } case 'x': curiop.base -= 8 - 16; /* fall into... */ case 'o': curiop.base -= 10 - 8; /* fall into... */ case 'd': value = va_arg(ap, int); break; case 'f': /* !insert current command name! */ puts(LastCmd->Name); continue; case 'l': c = toupper(*fmt++); goto reswitch; case 'n': /* !pluralis if last numeric printed not 1! */ if (value != 1) { c = 's'; putc(c, sp); } continue; case 'N': /* !insert numeric argument (if any)! */ #ifndef TINY if (exp_p && True(ShowExp)) { puts(((c = exp) < 0) ? (c = -c, "-") : "+"); if (exp_p == YES) { value = c; break; } } #endif continue; case 'p': /* !insert symbolic keystroke! */ puts(PPchar(va_arg(ap, int))); continue; #ifndef BAD_VARARGS case 'r': /* !switch to remote arglist! */ /* [TRH] * remote -- take format + args from somewhere else * remainder of current format is ignored. * usage: "%r", fmt, ap * (undocumented but rather handy Unix 7th Ed. feature) */ fmt = va_arg(ap, char *); ap = va_arg(ap, va_list); continue; #endif case 's': puts(va_arg(ap, char *)); continue; default: { static char BadFmt[] = "<%x?>"; BadFmt[2] = c; puts(BadFmt); continue; } } /* we only get here with numeric conversions */ putld(value); curiop.base = 10; } } int format(buf, len, fmt, ap) char *buf; const char *fmt; va_list ap; { File strbuf; register File *sp = &strbuf; sp->f_ptr /*- = sp->f_base -*/ = buf; /*- sp->f_fd = -1; -*/ /* Not legit for files */ sp->f_cnt = len - 1; /* [TRH] assure zero-termination */ sp->f_flags = F_STRING; /*- sp->f_bufsize = len; -*/ doformat(sp, fmt, ap); *sp->f_ptr = '\0'; return (sp->f_ptr - buf); } /* VARARGS1 */ char * DEFVARG(sprint, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { va_register va_list ap; static char line[sizeof mesgbuf]; va_begin(ap, fmt); format(line, sizeof line, fmt, ap); va_end(ap); return line; } /* VARARGS1 */ DEFVARG(printf, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { va_register va_list ap; va_begin(ap, fmt); doformat(stdout, fmt, ap); va_end(ap); } /* VARARGS2 */ DEFVARG(fprintf, (File *fp, const char *fmt, ...), (fp, fmt, va_alist) File *fp; const char *fmt;) { va_register va_list ap; va_begin(ap, fmt); doformat(fp, fmt, ap); va_end(ap); } /* VARARGS2 */ DEFVARG(sprintf, (char *str, const char *fmt, ...), (str, fmt, va_alist) char *str; const char *fmt;) { va_register va_list ap; register int n; va_begin(ap, fmt); n = format(str, LBSIZE, fmt, ap); va_end(ap); return n; } /* VARARGS1 */ void DEFVARG(s_mess, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { va_register va_list ap; register char *mp; if (InJoverc) return; mp = mesgbuf; va_begin(ap, fmt); format(mp, sizeof mesgbuf, fmt, ap); va_end(ap); message(mp); } /* VARARGS1 */ void DEFVARG(f_mess, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { va_register va_list ap; va_begin(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); DrawMesg(NO); updmesg(); /* Still needs updating (for convenience) */ } /* VARARGS1 */ void DEFVARG(add_mess, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { va_register va_list ap; register char *mp; if (InJoverc) return; for (mp = mesgbuf; *mp++; ) ; --mp; va_begin(ap, fmt); format(mp, (int)(&mesgbuf[sizeof mesgbuf] - mp), fmt, ap); va_end(ap); updmesg(); } /*====================================================================== * $Log: fmt.c,v $ * Revision 14.30.0.10 1994/04/22 18:24:23 tom * (doformat,sprint,printf,fprintf,sprintf,s_mess,f_mess,add_mess): * use `va_register va_list'. * * Revision 14.30 1993/02/06 00:48:31 tom * cleanup whitespace; some random optimizations; add %N directive. * * Revision 14.26 1992/08/26 23:56:53 tom * add RCS directives. * */