home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1990,1991,1992 Chris and John Downey */
- #ifndef lint
- static char *sccsid = "@(#)flexbuf.c 2.2 (Chris & John Downey) 8/27/92";
- #endif
-
- /***
-
- * program name:
- xvi
- * function:
- PD version of UNIX "vi" editor, with extensions.
- * module name:
- flexbuf.c
- * module function:
- Routines for Flexbufs (variable-length FIFO queues).
-
- Some of the access routines are implemented as macros in xvi.h.
- * history:
- STEVIE - ST Editor for VI Enthusiasts, Version 3.10
- Originally by Tim Thompson (twitch!tjt)
- Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
- Heavily modified by Chris & John Downey
-
- ***/
-
- #include "xvi.h"
-
- #define FLEXEXTRA 64
-
- /*
- * Append a single character to a Flexbuf. Return FALSE if we've run
- * out of space.
- *
- * Note that the f->fxb_chars array is not necessarily null-terminated.
- */
- bool_t
- flexaddch(f, ch)
- register Flexbuf *f;
- int ch;
- {
- if (flexempty(f))
- f->fxb_rcnt = f->fxb_wcnt = 0;
- if (f->fxb_wcnt >= f->fxb_max) {
- if (f->fxb_max == 0) {
- if ((f->fxb_chars = alloc(FLEXEXTRA)) == NULL) {
- return FALSE;
- } else {
- f->fxb_max = FLEXEXTRA;
- }
- } else {
- unsigned newsize = f->fxb_wcnt + FLEXEXTRA;
-
- if ((f->fxb_chars = realloc(f->fxb_chars, newsize)) == NULL) {
- f->fxb_wcnt = f->fxb_max = 0;
- return FALSE;
- } else {
- f->fxb_max = newsize;
- }
- }
- }
- f->fxb_chars[f->fxb_wcnt++] = ch;
- return TRUE;
- }
-
- /*
- * Return contents of a Flexbuf as a null-terminated string.
- */
- char *
- flexgetstr(f)
- Flexbuf *f;
- {
- if (!flexempty(f) && flexaddch(f, '\0')) {
- --f->fxb_wcnt;
- return &f->fxb_chars[f->fxb_rcnt];
- } else {
- return "";
- }
- }
-
- /*
- * Remove the first character from a Flexbuf and return it.
- */
- int
- flexpopch(f)
- Flexbuf *f;
- {
- return flexempty(f) ?
- 0 : (unsigned char) f->fxb_chars[f->fxb_rcnt++];
- }
-
- /*
- * Free storage belonging to a Flexbuf.
- */
- void
- flexdelete(f)
- Flexbuf *f;
- {
- if (f->fxb_max > 0) {
- (void) free(f->fxb_chars);
- f->fxb_wcnt = f->fxb_max = 0;
- }
- }
-
- /*
- * The following routines provide for appending formatted data to a
- * Flexbuf using a subset of the format specifiers accepted by
- * printf(3). The specifiers we understand are currently
- *
- * %c %d %ld %lu %s %u
- *
- * Field width, precision & left justification can also be specified
- * as for printf().
- *
- * The main advantage of this is that we don't have to worry about the
- * end of the destination array being overwritten, as we do with
- * sprintf(3).
- */
-
- static unsigned width;
- static unsigned prec;
- static bool_t ljust;
-
- /*
- * Append a string to a Flexbuf, truncating the string & adding filler
- * characters as specified by the width, prec & ljust variables.
- *
- * The precision specifier gives the maximum field width.
- */
- static bool_t
- strformat(f, p)
- Flexbuf *f;
- register char *p;
- {
- register int c;
-
- if (width != 0 && !ljust) {
- register unsigned len;
-
- len = strlen(p);
- if (prec != 0 && prec < len)
- len = prec;
- while (width > len) {
- if (!flexaddch(f, ' '))
- return FALSE;
- --width;
- }
- }
-
- while ((c = *p++) != '\0') {
- if (!flexaddch(f, c))
- return FALSE;
- if (width != 0)
- --width;
- if (prec != 0) {
- if (--prec == 0) {
- break;
- }
- }
- }
- while (width != 0) {
- if (!flexaddch(f, ' '))
- return FALSE;
- --width;
- }
- return TRUE;
- }
-
- /*
- * Given a binary long integer, convert it to a decimal number &
- * append it to the end of a Flexbuf.
- *
- * The precision specifier gives the minimum number of decimal digits.
- */
- static bool_t
- numformat(f, n, uflag)
- Flexbuf *f;
- long n;
- bool_t uflag;
- {
- register char *s;
- register unsigned len;
-
- if (n == 0) {
- /*
- * Special case.
- */
- s = "0";
- len = 1;
- } else {
- static char dstr[sizeof (long) * 3 + 2];
- register unsigned long un;
- int neg;
-
- * (s = &dstr[sizeof dstr - 1]) = '\0';
-
- if (!uflag && n < 0) {
- neg = 1;
- un = -n;
- } else {
- neg = 0;
- un = n;
- }
-
- while (un > 0 && s > &dstr[1]) {
- *--s = (char)((un % 10) + '0');
- un /= 10;
- }
-
- if (neg)
- *--s = '-';
- len = &dstr[sizeof dstr - 1] - s;
- }
-
- while (width > len && width > prec) {
- if (!flexaddch(f, ' '))
- return FALSE;
- --width;
- }
-
- while (prec > len) {
- if (!flexaddch(f, '0'))
- return FALSE;
- --prec;
- if (width > 0)
- --width;
- }
- prec = 0;
- return strformat(f, s);
- }
-
- /*
- * Main formatting routine.
- */
- bool_t
- vformat
- #ifdef __STDC__
- (Flexbuf *f, register char *format, register va_list argp)
- #else
- (f, format, argp)
- Flexbuf *f;
- register char *format;
- register va_list argp;
- #endif
- {
- register int c;
-
- while ((c = *format++) != '\0') {
- if (c == '%') {
- static char cstr[2];
- bool_t lnflag;
- bool_t zflag;
-
- lnflag = FALSE;
- ljust = FALSE;
- width = 0;
- prec = 0;
- zflag = FALSE;
- if ((c = *format++) == '-') {
- ljust = TRUE;
- c = *format++;
- }
-
- /*
- * Get width specifier.
- */
- if (c == '0') {
- if (ljust)
- /*
- * It doesn't make sense to
- * have a left-justified
- * numeric field with zero
- * padding.
- */
- return FALSE;
- zflag = TRUE;
- c = *format++;
- }
-
- while (c && is_digit(c)) {
- if (width != 0)
- width *= 10;
- width += (c - '0');
- c = *format++;
- }
-
- if (c == '.') {
- /*
- * Get precision specifier.
- */
- while ((c = *format++) != '\0' && is_digit(c)) {
- if (prec != 0)
- prec *= 10;
- prec += (c - '0');
- }
- }
-
- switch (c) {
- case '%':
- cstr[0] = c;
- if (!strformat(f, cstr))
- return FALSE;
- continue;
-
- case 'c':
- cstr[0] = va_arg(argp, int);
- if (!strformat(f, cstr))
- return FALSE;
- continue;
-
- case 'l':
- switch (c = *format++) {
- case 'd':
- case 'u':
- lnflag = TRUE;
- break;
- default:
- /*
- * Syntax error.
- */
- return FALSE;
- }
- /* fall through ... */
-
- case 'd':
- case 'u':
- {
- long n;
-
- if (lnflag)
- {
- n = (c == 'u' ?
- (long) va_arg(argp, unsigned long) :
- va_arg(argp, long));
- } else {
- n = (c == 'u' ?
- (long) va_arg(argp, unsigned int) :
- (long) va_arg(argp, int));
- }
-
- /*
- * For integers, the precision
- * specifier gives the minimum number
- * of decimal digits.
- */
- if (zflag && prec < width) {
- prec = width;
- width = 0;
- }
- if (!numformat(f, n, (c == 'u')))
- return FALSE;
- continue;
- }
-
- case 's':
- {
- char *sp;
-
- if ((sp = va_arg(argp, char *)) == NULL ||
- !strformat(f, sp)) {
- return FALSE;
- }
- continue;
- }
-
- default:
- /*
- * Syntax error.
- */
- return FALSE;
- }
- } else if (!flexaddch(f, c)) {
- return FALSE;
- }
- }
- return TRUE;
- }
-
- /*
- * Front end callable with a variable number of arguments.
- */
- /*VARARGS2*/
- bool_t
- lformat
- #ifdef __STDC__
- (Flexbuf *f, char *format, ...)
- #else
- (f, format, va_alist)
- Flexbuf *f;
- char *format;
- va_dcl
- #endif
- {
- va_list argp;
- bool_t retval;
-
- VA_START(argp, format);
- retval = vformat(f, format, argp);
- va_end(argp);
- return retval;
- }
-