fmt.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       fmt.c (3575B)
       ---
            1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
            2 #include <stdarg.h>
            3 #include <string.h>
            4 #include "plan9.h"
            5 #include "fmt.h"
            6 #include "fmtdef.h"
            7 
            8 enum
            9 {
           10         Maxfmt = 64
           11 };
           12 
           13 typedef struct Convfmt Convfmt;
           14 struct Convfmt
           15 {
           16         int        c;
           17         volatile        Fmts        fmt;        /* for spin lock in fmtfmt; avoids race due to write order */
           18 };
           19 
           20 static struct
           21 {
           22         /* lock by calling __fmtlock, __fmtunlock */
           23         int        nfmt;
           24         Convfmt        fmt[Maxfmt];
           25 } fmtalloc;
           26 
           27 static Convfmt knownfmt[] = {
           28         ' ',        __flagfmt,
           29         '#',        __flagfmt,
           30         '%',        __percentfmt,
           31         '\'',        __flagfmt,
           32         '+',        __flagfmt,
           33         ',',        __flagfmt,
           34         '-',        __flagfmt,
           35         'C',        __runefmt,        /* Plan 9 addition */
           36         'E',        __efgfmt,
           37 #ifndef PLAN9PORT
           38         'F',        __efgfmt,        /* ANSI only */
           39 #endif
           40         'G',        __efgfmt,
           41 #ifndef PLAN9PORT
           42         'L',        __flagfmt,        /* ANSI only */
           43 #endif
           44         'S',        __runesfmt,        /* Plan 9 addition */
           45         'X',        __ifmt,
           46         'b',        __ifmt,                /* Plan 9 addition */
           47         'c',        __charfmt,
           48         'd',        __ifmt,
           49         'e',        __efgfmt,
           50         'f',        __efgfmt,
           51         'g',        __efgfmt,
           52         'h',        __flagfmt,
           53 #ifndef PLAN9PORT
           54         'i',        __ifmt,                /* ANSI only */
           55 #endif
           56         'l',        __flagfmt,
           57         'n',        __countfmt,
           58         'o',        __ifmt,
           59         'p',        __ifmt,
           60         'r',        __errfmt,
           61         's',        __strfmt,
           62 #ifdef PLAN9PORT
           63         'u',        __flagfmt,
           64 #else
           65         'u',        __ifmt,
           66 #endif
           67         'x',        __ifmt,
           68         0,        nil,
           69 };
           70 
           71 
           72 int        (*fmtdoquote)(int);
           73 
           74 /*
           75  * __fmtlock() must be set
           76  */
           77 static int
           78 __fmtinstall(int c, Fmts f)
           79 {
           80         Convfmt *p, *ep;
           81 
           82         if(c<=0 || c>=65536)
           83                 return -1;
           84         if(!f)
           85                 f = __badfmt;
           86 
           87         ep = &fmtalloc.fmt[fmtalloc.nfmt];
           88         for(p=fmtalloc.fmt; p<ep; p++)
           89                 if(p->c == c)
           90                         break;
           91 
           92         if(p == &fmtalloc.fmt[Maxfmt])
           93                 return -1;
           94 
           95         p->fmt = f;
           96         if(p == ep){        /* installing a new format character */
           97                 fmtalloc.nfmt++;
           98                 p->c = c;
           99         }
          100 
          101         return 0;
          102 }
          103 
          104 int
          105 fmtinstall(int c, int (*f)(Fmt*))
          106 {
          107         int ret;
          108 
          109         __fmtlock();
          110         ret = __fmtinstall(c, f);
          111         __fmtunlock();
          112         return ret;
          113 }
          114 
          115 static Fmts
          116 fmtfmt(int c)
          117 {
          118         Convfmt *p, *ep;
          119 
          120         ep = &fmtalloc.fmt[fmtalloc.nfmt];
          121         for(p=fmtalloc.fmt; p<ep; p++)
          122                 if(p->c == c){
          123                         while(p->fmt == nil)        /* loop until value is updated */
          124                                 ;
          125                         return p->fmt;
          126                 }
          127 
          128         /* is this a predefined format char? */
          129         __fmtlock();
          130         for(p=knownfmt; p->c; p++)
          131                 if(p->c == c){
          132                         __fmtinstall(p->c, p->fmt);
          133                         __fmtunlock();
          134                         return p->fmt;
          135                 }
          136         __fmtunlock();
          137 
          138         return __badfmt;
          139 }
          140 
          141 void*
          142 __fmtdispatch(Fmt *f, void *fmt, int isrunes)
          143 {
          144         Rune rune, r;
          145         int i, n;
          146 
          147         f->flags = 0;
          148         f->width = f->prec = 0;
          149 
          150         for(;;){
          151                 if(isrunes){
          152                         r = *(Rune*)fmt;
          153                         fmt = (Rune*)fmt + 1;
          154                 }else{
          155                         fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
          156                         r = rune;
          157                 }
          158                 f->r = r;
          159                 switch(r){
          160                 case '\0':
          161                         return nil;
          162                 case '.':
          163                         f->flags |= FmtWidth|FmtPrec;
          164                         continue;
          165                 case '0':
          166                         if(!(f->flags & FmtWidth)){
          167                                 f->flags |= FmtZero;
          168                                 continue;
          169                         }
          170                         /* fall through */
          171                 case '1': case '2': case '3': case '4':
          172                 case '5': case '6': case '7': case '8': case '9':
          173                         i = 0;
          174                         while(r >= '0' && r <= '9'){
          175                                 i = i * 10 + r - '0';
          176                                 if(isrunes){
          177                                         r = *(Rune*)fmt;
          178                                         fmt = (Rune*)fmt + 1;
          179                                 }else{
          180                                         r = *(char*)fmt;
          181                                         fmt = (char*)fmt + 1;
          182                                 }
          183                         }
          184                         if(isrunes)
          185                                 fmt = (Rune*)fmt - 1;
          186                         else
          187                                 fmt = (char*)fmt - 1;
          188                 numflag:
          189                         if(f->flags & FmtWidth){
          190                                 f->flags |= FmtPrec;
          191                                 f->prec = i;
          192                         }else{
          193                                 f->flags |= FmtWidth;
          194                                 f->width = i;
          195                         }
          196                         continue;
          197                 case '*':
          198                         i = va_arg(f->args, int);
          199                         if(i < 0){
          200                                 /*
          201                                  * negative precision =>
          202                                  * ignore the precision.
          203                                  */
          204                                 if(f->flags & FmtPrec){
          205                                         f->flags &= ~FmtPrec;
          206                                         f->prec = 0;
          207                                         continue;
          208                                 }
          209                                 i = -i;
          210                                 f->flags |= FmtLeft;
          211                         }
          212                         goto numflag;
          213                 }
          214                 n = (*fmtfmt(r))(f);
          215                 if(n < 0)
          216                         return nil;
          217                 if(n == 0)
          218                         return fmt;
          219         }
          220 }