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

fmt.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"

enum
{
      Maxfmt = 64
};

typedef struct Convfmt Convfmt;
struct Convfmt
{
      int   c;
      volatile    Fmts  fmt;  /* for spin lock in fmtfmt; avoids race due to write order */
};

struct
{
      /* lock by calling __fmtlock, __fmtunlock */
      int   nfmt;
      Convfmt     fmt[Maxfmt];
} fmtalloc;

static Convfmt knownfmt[] = {
      ' ',  __flagfmt,
      '#',  __flagfmt,
      '%',  __percentfmt,
      '+',  __flagfmt,
      ',',  __flagfmt,
      '-',  __flagfmt,
      'C',  __runefmt,  /* Plan 9 addition */
      'E',  __efgfmt,
#ifndef PLAN9PORT
      'F',  __efgfmt,   /* ANSI only */
#endif
      'G',  __efgfmt,
#ifndef PLAN9PORT
      'L',  __flagfmt,  /* ANSI only */
#endif
      'S',  __runesfmt, /* Plan 9 addition */
      'X',  __ifmt,
      'b',  __ifmt,           /* Plan 9 addition */
      'c',  __charfmt,
      'd',  __ifmt,
      'e',  __efgfmt,
      'f',  __efgfmt,
      'g',  __efgfmt,
      'h',  __flagfmt,
#ifndef PLAN9PORT
      'i',  __ifmt,           /* ANSI only */
#endif
      'l',  __flagfmt,
      'n',  __countfmt,
      'o',  __ifmt,
      'p',  __ifmt,
      'r',  __errfmt,
      's',  __strfmt,
#ifdef PLAN9PORT
      'u',  __flagfmt,
#else
      'u',  __ifmt,
#endif
      'x',  __ifmt,
      0,    nil,
};


int   (*fmtdoquote)(int);

/*
 * __fmtlock() must be set
 */
static int
__fmtinstall(int c, Fmts f)
{
      Convfmt *p, *ep;

      if(c<=0 || c>=65536)
            return -1;
      if(!f)
            f = __badfmt;

      ep = &fmtalloc.fmt[fmtalloc.nfmt];
      for(p=fmtalloc.fmt; p<ep; p++)
            if(p->c == c)
                  break;

      if(p == &fmtalloc.fmt[Maxfmt])
            return -1;

      p->fmt = f;
      if(p == ep){      /* installing a new format character */
            fmtalloc.nfmt++;
            p->c = c;
      }

      return 0;
}

int
fmtinstall(int c, int (*f)(Fmt*))
{
      int ret;

      __fmtlock();
      ret = __fmtinstall(c, f);
      __fmtunlock();
      return ret;
}

static Fmts
fmtfmt(int c)
{
      Convfmt *p, *ep;

      ep = &fmtalloc.fmt[fmtalloc.nfmt];
      for(p=fmtalloc.fmt; p<ep; p++)
            if(p->c == c){
                  while(p->fmt == nil)    /* loop until value is updated */
                        ;
                  return p->fmt;
            }

      /* is this a predefined format char? */
      __fmtlock();
      for(p=knownfmt; p->c; p++)
            if(p->c == c){
                  __fmtinstall(p->c, p->fmt);
                  __fmtunlock();
                  return p->fmt;
            }
      __fmtunlock();

      return __badfmt;
}

void*
__fmtdispatch(Fmt *f, void *fmt, int isrunes)
{
      Rune rune, r;
      int i, n;

      f->flags = 0;
      f->width = f->prec = 0;

      for(;;){
            if(isrunes){
                  r = *(Rune*)fmt;
                  fmt = (Rune*)fmt + 1;
            }else{
                  fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
                  r = rune;
            }
            f->r = r;
            switch(r){
            case '\0':
                  return nil;
            case '.':
                  f->flags |= FmtWidth|FmtPrec;
                  continue;
            case '0':
                  if(!(f->flags & FmtWidth)){
                        f->flags |= FmtZero;
                        continue;
                  }
                  /* fall through */
            case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                  i = 0;
                  while(r >= '0' && r <= '9'){
                        i = i * 10 + r - '0';
                        if(isrunes){
                              r = *(Rune*)fmt;
                              fmt = (Rune*)fmt + 1;
                        }else{
                              r = *(char*)fmt;
                              fmt = (char*)fmt + 1;
                        }
                  }
                  if(isrunes)
                        fmt = (Rune*)fmt - 1;
                  else
                        fmt = (char*)fmt - 1;
            numflag:
                  if(f->flags & FmtWidth){
                        f->flags |= FmtPrec;
                        f->prec = i;
                  }else{
                        f->flags |= FmtWidth;
                        f->width = i;
                  }
                  continue;
            case '*':
                  i = va_arg(f->args, int);
                  if(i < 0){
                        /*
                         * negative precision =>
                         * ignore the precision.
                         */
                        if(f->flags & FmtPrec){
                              f->flags &= ~FmtPrec;
                              f->prec = 0;
                              continue;
                        }
                        i = -i;
                        f->flags |= FmtLeft;
                  }
                  goto numflag;
            }
            n = (*fmtfmt(r))(f);
            if(n < 0)
                  return nil;
            if(n == 0)
                  return fmt;
      }
}

Generated by  Doxygen 1.6.0   Back to index