Logo Search packages:      
Sourcecode: 9base version File versions  Download package

dofmt.c

/*
 * The authors of this software are Rob Pike and Ken Thompson.
 *              Copyright (c) 2002 by Lucent Technologies.
 * Permission to use, copy, modify, and distribute this software for any
 * purpose without fee is hereby granted, provided that this entire notice
 * is included in all copies of any software which is or includes a copy
 * or modification of this software and in all copies of the supporting
 * documentation for such software.
 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
 * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
 */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"

/* format the output into f->to and return the number of characters fmted  */
int
dofmt(Fmt *f, char *fmt)
{
      Rune rune, *rt, *rs;
      int r;
      char *t, *s;
      int n, nfmt;

      nfmt = f->nfmt;
      for(;;){
            if(f->runes){
                  rt = (Rune*)f->to;
                  rs = (Rune*)f->stop;
                  while((r = *(uchar*)fmt) && r != '%'){
                        if(r < Runeself)
                              fmt++;
                        else{
                              fmt += chartorune(&rune, fmt);
                              r = rune;
                        }
                        FMTRCHAR(f, rt, rs, r);
                  }
                  fmt++;
                  f->nfmt += rt - (Rune *)f->to;
                  f->to = rt;
                  if(!r)
                        return f->nfmt - nfmt;
                  f->stop = rs;
            }else{
                  t = (char*)f->to;
                  s = (char*)f->stop;
                  while((r = *(uchar*)fmt) && r != '%'){
                        if(r < Runeself){
                              FMTCHAR(f, t, s, r);
                              fmt++;
                        }else{
                              n = chartorune(&rune, fmt);
                              if(t + n > s){
                                    t = (char*)__fmtflush(f, t, n);
                                    if(t != nil)
                                          s = (char*)f->stop;
                                    else
                                          return -1;
                              }
                              while(n--)
                                    *t++ = *fmt++;
                        }
                  }
                  fmt++;
                  f->nfmt += t - (char *)f->to;
                  f->to = t;
                  if(!r)
                        return f->nfmt - nfmt;
                  f->stop = s;
            }

            fmt = (char*)__fmtdispatch(f, fmt, 0);
            if(fmt == nil)
                  return -1;
      }
}

void *
__fmtflush(Fmt *f, void *t, int len)
{
      if(f->runes)
            f->nfmt += (Rune*)t - (Rune*)f->to;
      else
            f->nfmt += (char*)t - (char *)f->to;
      f->to = t;
      if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
            f->stop = f->to;
            return nil;
      }
      return f->to;
}

/*
 * put a formatted block of memory sz bytes long of n runes into the output buffer,
 * left/right justified in a field of at least f->width charactes
 */
int
__fmtpad(Fmt *f, int n)
{
      char *t, *s;
      int i;

      t = (char*)f->to;
      s = (char*)f->stop;
      for(i = 0; i < n; i++)
            FMTCHAR(f, t, s, ' ');
      f->nfmt += t - (char *)f->to;
      f->to = t;
      return 0;
}

int
__rfmtpad(Fmt *f, int n)
{
      Rune *t, *s;
      int i;

      t = (Rune*)f->to;
      s = (Rune*)f->stop;
      for(i = 0; i < n; i++)
            FMTRCHAR(f, t, s, ' ');
      f->nfmt += t - (Rune *)f->to;
      f->to = t;
      return 0;
}

int
__fmtcpy(Fmt *f, const void *vm, int n, int sz)
{
      Rune *rt, *rs, r;
      char *t, *s, *m, *me;
      ulong fl;
      int nc, w;

      m = (char*)vm;
      me = m + sz;
      w = f->width;
      fl = f->flags;
      if((fl & FmtPrec) && n > f->prec)
            n = f->prec;
      if(f->runes){
            if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
                  return -1;
            rt = (Rune*)f->to;
            rs = (Rune*)f->stop;
            for(nc = n; nc > 0; nc--){
                  r = *(uchar*)m;
                  if(r < Runeself)
                        m++;
                  else if((me - m) >= UTFmax || fullrune(m, me-m))
                        m += chartorune(&r, m);
                  else
                        break;
                  FMTRCHAR(f, rt, rs, r);
            }
            f->nfmt += rt - (Rune *)f->to;
            f->to = rt;
            if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
                  return -1;
      }else{
            if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
                  return -1;
            t = (char*)f->to;
            s = (char*)f->stop;
            for(nc = n; nc > 0; nc--){
                  r = *(uchar*)m;
                  if(r < Runeself)
                        m++;
                  else if((me - m) >= UTFmax || fullrune(m, me-m))
                        m += chartorune(&r, m);
                  else
                        break;
                  FMTRUNE(f, t, s, r);
            }
            f->nfmt += t - (char *)f->to;
            f->to = t;
            if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
                  return -1;
      }
      return 0;
}

int
__fmtrcpy(Fmt *f, const void *vm, int n)
{
      Rune r, *m, *me, *rt, *rs;
      char *t, *s;
      ulong fl;
      int w;

      m = (Rune*)vm;
      w = f->width;
      fl = f->flags;
      if((fl & FmtPrec) && n > f->prec)
            n = f->prec;
      if(f->runes){
            if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
                  return -1;
            rt = (Rune*)f->to;
            rs = (Rune*)f->stop;
            for(me = m + n; m < me; m++)
                  FMTRCHAR(f, rt, rs, *m);
            f->nfmt += rt - (Rune *)f->to;
            f->to = rt;
            if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
                  return -1;
      }else{
            if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
                  return -1;
            t = (char*)f->to;
            s = (char*)f->stop;
            for(me = m + n; m < me; m++){
                  r = *m;
                  FMTRUNE(f, t, s, r);
            }
            f->nfmt += t - (char *)f->to;
            f->to = t;
            if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
                  return -1;
      }
      return 0;
}

/* fmt out one character */
int
__charfmt(Fmt *f)
{
      char x[1];

      x[0] = va_arg(f->args, int);
      f->prec = 1;
      return __fmtcpy(f, (const char*)x, 1, 1);
}

/* fmt out one rune */
int
__runefmt(Fmt *f)
{
      Rune x[1];

      x[0] = va_arg(f->args, int);
      return __fmtrcpy(f, (const void*)x, 1);
}

/* public helper routine: fmt out a null terminated string already in hand */
int
fmtstrcpy(Fmt *f, char *s)
{
      int i, j;
      Rune r;

      if(!s)
            return __fmtcpy(f, "<nil>", 5, 5);
      /* if precision is specified, make sure we don't wander off the end */
      if(f->flags & FmtPrec){
            i = 0;
            for(j=0; j<f->prec && s[i]; j++)
                  i += chartorune(&r, s+i);
            return __fmtcpy(f, s, j, i);
      }
      return __fmtcpy(f, s, utflen(s), strlen(s));
}

/* fmt out a null terminated utf string */
int
__strfmt(Fmt *f)
{
      char *s;

      s = va_arg(f->args, char *);
      return fmtstrcpy(f, s);
}

/* public helper routine: fmt out a null terminated rune string already in hand */
int
fmtrunestrcpy(Fmt *f, Rune *s)
{
      Rune *e;
      int n, p;

      if(!s)
            return __fmtcpy(f, "<nil>", 5, 5);
      /* if precision is specified, make sure we don't wander off the end */
      if(f->flags & FmtPrec){
            p = f->prec;
            for(n = 0; n < p; n++)
                  if(s[n] == 0)
                        break;
      }else{
            for(e = s; *e; e++)
                  ;
            n = e - s;
      }
      return __fmtrcpy(f, s, n);
}

/* fmt out a null terminated rune string */
int
__runesfmt(Fmt *f)
{
      Rune *s;

      s = va_arg(f->args, Rune *);
      return fmtrunestrcpy(f, s);
}

/* fmt a % */
int
__percentfmt(Fmt *f)
{
      Rune x[1];

      x[0] = f->r;
      f->prec = 1;
      return __fmtrcpy(f, (const void*)x, 1);
}

/* fmt an integer */
int
__ifmt(Fmt *f)
{
      char buf[70], *p, *conv;
      uvlong vu;
      ulong u;
      int neg, base, i, n, fl, w, isv;

      neg = 0;
      fl = f->flags;
      isv = 0;
      vu = 0;
      u = 0;
#ifndef PLAN9PORT
      /*
       * Unsigned verbs for ANSI C
       */
      switch(f->r){
      case 'x':
      case 'X':
      case 'o':
      case 'u':
      case 'p':
            fl |= FmtUnsigned;
            fl &= ~(FmtSign|FmtSpace);
            break;
      }
#endif
      if(f->r == 'p'){
            u = (ulong)va_arg(f->args, void*);
            f->r = 'x';
            fl |= FmtUnsigned;
      }else if(fl & FmtVLong){
            isv = 1;
            if(fl & FmtUnsigned)
                  vu = va_arg(f->args, uvlong);
            else
                  vu = va_arg(f->args, vlong);
      }else if(fl & FmtLong){
            if(fl & FmtUnsigned)
                  u = va_arg(f->args, ulong);
            else
                  u = va_arg(f->args, long);
      }else if(fl & FmtByte){
            if(fl & FmtUnsigned)
                  u = (uchar)va_arg(f->args, int);
            else
                  u = (char)va_arg(f->args, int);
      }else if(fl & FmtShort){
            if(fl & FmtUnsigned)
                  u = (ushort)va_arg(f->args, int);
            else
                  u = (short)va_arg(f->args, int);
      }else{
            if(fl & FmtUnsigned)
                  u = va_arg(f->args, uint);
            else
                  u = va_arg(f->args, int);
      }
      conv = "0123456789abcdef";
      switch(f->r){
      case 'd':
      case 'i':
      case 'u':
            base = 10;
            break;
      case 'x':
            base = 16;
            break;
      case 'X':
            base = 16;
            conv = "0123456789ABCDEF";
            break;
      case 'b':
            base = 2;
            break;
      case 'o':
            base = 8;
            break;
      default:
            return -1;
      }
      if(!(fl & FmtUnsigned)){
            if(isv && (vlong)vu < 0){
                  vu = -(vlong)vu;
                  neg = 1;
            }else if(!isv && (long)u < 0){
                  u = -(long)u;
                  neg = 1;
            }
      }
      p = buf + sizeof buf - 1;
      n = 0;
      if(isv){
            while(vu){
                  i = vu % base;
                  vu /= base;
                  if((fl & FmtComma) && n % 4 == 3){
                        *p-- = ',';
                        n++;
                  }
                  *p-- = conv[i];
                  n++;
            }
      }else{
            while(u){
                  i = u % base;
                  u /= base;
                  if((fl & FmtComma) && n % 4 == 3){
                        *p-- = ',';
                        n++;
                  }
                  *p-- = conv[i];
                  n++;
            }
      }
      if(n == 0){
            *p-- = '0';
            n = 1;
      }
      for(w = f->prec; n < w && p > buf+3; n++)
            *p-- = '0';
      if(neg || (fl & (FmtSign|FmtSpace)))
            n++;
      if(fl & FmtSharp){
            if(base == 16)
                  n += 2;
            else if(base == 8){
                  if(p[1] == '0')
                        fl &= ~FmtSharp;
                  else
                        n++;
            }
      }
      if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
            for(w = f->width; n < w && p > buf+3; n++)
                  *p-- = '0';
            f->width = 0;
      }
      if(fl & FmtSharp){
            if(base == 16)
                  *p-- = f->r;
            if(base == 16 || base == 8)
                  *p-- = '0';
      }
      if(neg)
            *p-- = '-';
      else if(fl & FmtSign)
            *p-- = '+';
      else if(fl & FmtSpace)
            *p-- = ' ';
      f->flags &= ~FmtPrec;
      return __fmtcpy(f, p + 1, n, n);
}

int
__countfmt(Fmt *f)
{
      void *p;
      ulong fl;

      fl = f->flags;
      p = va_arg(f->args, void*);
      if(fl & FmtVLong){
            *(vlong*)p = f->nfmt;
      }else if(fl & FmtLong){
            *(long*)p = f->nfmt;
      }else if(fl & FmtByte){
            *(char*)p = f->nfmt;
      }else if(fl & FmtShort){
            *(short*)p = f->nfmt;
      }else{
            *(int*)p = f->nfmt;
      }
      return 0;
}

int
__flagfmt(Fmt *f)
{
      switch(f->r){
      case ',':
            f->flags |= FmtComma;
            break;
      case '-':
            f->flags |= FmtLeft;
            break;
      case '+':
            f->flags |= FmtSign;
            break;
      case '#':
            f->flags |= FmtSharp;
            break;
      case ' ':
            f->flags |= FmtSpace;
            break;
      case 'u':
            f->flags |= FmtUnsigned;
            break;
      case 'h':
            if(f->flags & FmtShort)
                  f->flags |= FmtByte;
            f->flags |= FmtShort;
            break;
      case 'L':
            f->flags |= FmtLDouble;
            break;
      case 'l':
            if(f->flags & FmtLong)
                  f->flags |= FmtVLong;
            f->flags |= FmtLong;
            break;
      }
      return 1;
}

/* default error format */
int
__badfmt(Fmt *f)
{
      char x[3];

      x[0] = '%';
      x[1] = f->r;
      x[2] = '%';
      f->prec = 3;
      __fmtcpy(f, (const void*)x, 3, 3);
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index