dofmt.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
       ---
       dofmt.c (11231B)
       ---
            1 /* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
            2 /* Copyright (c) 2004 Google Inc.; see LICENSE */
            3 
            4 #include <stdarg.h>
            5 #include <string.h>
            6 #include "plan9.h"
            7 #include "fmt.h"
            8 #include "fmtdef.h"
            9 
           10 /* format the output into f->to and return the number of characters fmted  */
           11 int
           12 dofmt(Fmt *f, char *fmt)
           13 {
           14         Rune rune, *rt, *rs;
           15         int r;
           16         char *t, *s;
           17         int n, nfmt;
           18 
           19         nfmt = f->nfmt;
           20         for(;;){
           21                 if(f->runes){
           22                         rt = (Rune*)f->to;
           23                         rs = (Rune*)f->stop;
           24                         while((r = *(uchar*)fmt) && r != '%'){
           25                                 if(r < Runeself)
           26                                         fmt++;
           27                                 else{
           28                                         fmt += chartorune(&rune, fmt);
           29                                         r = rune;
           30                                 }
           31                                 FMTRCHAR(f, rt, rs, r);
           32                         }
           33                         fmt++;
           34                         f->nfmt += rt - (Rune *)f->to;
           35                         f->to = rt;
           36                         if(!r)
           37                                 return f->nfmt - nfmt;
           38                         f->stop = rs;
           39                 }else{
           40                         t = (char*)f->to;
           41                         s = (char*)f->stop;
           42                         while((r = *(uchar*)fmt) && r != '%'){
           43                                 if(r < Runeself){
           44                                         FMTCHAR(f, t, s, r);
           45                                         fmt++;
           46                                 }else{
           47                                         n = chartorune(&rune, fmt);
           48                                         if(t + n > s){
           49                                                 t = (char*)__fmtflush(f, t, n);
           50                                                 if(t != nil)
           51                                                         s = (char*)f->stop;
           52                                                 else
           53                                                         return -1;
           54                                         }
           55                                         while(n--)
           56                                                 *t++ = *fmt++;
           57                                 }
           58                         }
           59                         fmt++;
           60                         f->nfmt += t - (char *)f->to;
           61                         f->to = t;
           62                         if(!r)
           63                                 return f->nfmt - nfmt;
           64                         f->stop = s;
           65                 }
           66 
           67                 fmt = (char*)__fmtdispatch(f, fmt, 0);
           68                 if(fmt == nil)
           69                         return -1;
           70         }
           71 }
           72 
           73 void *
           74 __fmtflush(Fmt *f, void *t, int len)
           75 {
           76         if(f->runes)
           77                 f->nfmt += (Rune*)t - (Rune*)f->to;
           78         else
           79                 f->nfmt += (char*)t - (char *)f->to;
           80         f->to = t;
           81         if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
           82                 f->stop = f->to;
           83                 return nil;
           84         }
           85         return f->to;
           86 }
           87 
           88 /*
           89  * put a formatted block of memory sz bytes long of n runes into the output buffer,
           90  * left/right justified in a field of at least f->width characters (if FmtWidth is set)
           91  */
           92 int
           93 __fmtpad(Fmt *f, int n)
           94 {
           95         char *t, *s;
           96         int i;
           97 
           98         t = (char*)f->to;
           99         s = (char*)f->stop;
          100         for(i = 0; i < n; i++)
          101                 FMTCHAR(f, t, s, ' ');
          102         f->nfmt += t - (char *)f->to;
          103         f->to = t;
          104         return 0;
          105 }
          106 
          107 int
          108 __rfmtpad(Fmt *f, int n)
          109 {
          110         Rune *t, *s;
          111         int i;
          112 
          113         t = (Rune*)f->to;
          114         s = (Rune*)f->stop;
          115         for(i = 0; i < n; i++)
          116                 FMTRCHAR(f, t, s, ' ');
          117         f->nfmt += t - (Rune *)f->to;
          118         f->to = t;
          119         return 0;
          120 }
          121 
          122 int
          123 __fmtcpy(Fmt *f, const void *vm, int n, int sz)
          124 {
          125         Rune *rt, *rs, r;
          126         char *t, *s, *m, *me;
          127         ulong fl;
          128         int nc, w;
          129 
          130         m = (char*)vm;
          131         me = m + sz;
          132         fl = f->flags;
          133         w = 0;
          134         if(fl & FmtWidth)
          135                 w = f->width;
          136         if((fl & FmtPrec) && n > f->prec)
          137                 n = f->prec;
          138         if(f->runes){
          139                 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
          140                         return -1;
          141                 rt = (Rune*)f->to;
          142                 rs = (Rune*)f->stop;
          143                 for(nc = n; nc > 0; nc--){
          144                         r = *(uchar*)m;
          145                         if(r < Runeself)
          146                                 m++;
          147                         else if((me - m) >= UTFmax || fullrune(m, me-m))
          148                                 m += chartorune(&r, m);
          149                         else
          150                                 break;
          151                         FMTRCHAR(f, rt, rs, r);
          152                 }
          153                 f->nfmt += rt - (Rune *)f->to;
          154                 f->to = rt;
          155                 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
          156                         return -1;
          157         }else{
          158                 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
          159                         return -1;
          160                 t = (char*)f->to;
          161                 s = (char*)f->stop;
          162                 for(nc = n; nc > 0; nc--){
          163                         r = *(uchar*)m;
          164                         if(r < Runeself)
          165                                 m++;
          166                         else if((me - m) >= UTFmax || fullrune(m, me-m))
          167                                 m += chartorune(&r, m);
          168                         else
          169                                 break;
          170                         FMTRUNE(f, t, s, r);
          171                 }
          172                 f->nfmt += t - (char *)f->to;
          173                 f->to = t;
          174                 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
          175                         return -1;
          176         }
          177         return 0;
          178 }
          179 
          180 int
          181 __fmtrcpy(Fmt *f, const void *vm, int n)
          182 {
          183         Rune r, *m, *me, *rt, *rs;
          184         char *t, *s;
          185         ulong fl;
          186         int w;
          187 
          188         m = (Rune*)vm;
          189         fl = f->flags;
          190         w = 0;
          191         if(fl & FmtWidth)
          192                 w = f->width;
          193         if((fl & FmtPrec) && n > f->prec)
          194                 n = f->prec;
          195         if(f->runes){
          196                 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
          197                         return -1;
          198                 rt = (Rune*)f->to;
          199                 rs = (Rune*)f->stop;
          200                 for(me = m + n; m < me; m++)
          201                         FMTRCHAR(f, rt, rs, *m);
          202                 f->nfmt += rt - (Rune *)f->to;
          203                 f->to = rt;
          204                 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
          205                         return -1;
          206         }else{
          207                 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
          208                         return -1;
          209                 t = (char*)f->to;
          210                 s = (char*)f->stop;
          211                 for(me = m + n; m < me; m++){
          212                         r = *m;
          213                         FMTRUNE(f, t, s, r);
          214                 }
          215                 f->nfmt += t - (char *)f->to;
          216                 f->to = t;
          217                 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
          218                         return -1;
          219         }
          220         return 0;
          221 }
          222 
          223 /* fmt out one character */
          224 int
          225 __charfmt(Fmt *f)
          226 {
          227         char x[1];
          228 
          229         x[0] = va_arg(f->args, int);
          230         f->prec = 1;
          231         return __fmtcpy(f, (const char*)x, 1, 1);
          232 }
          233 
          234 /* fmt out one rune */
          235 int
          236 __runefmt(Fmt *f)
          237 {
          238         Rune x[1];
          239 
          240         x[0] = va_arg(f->args, int);
          241         return __fmtrcpy(f, (const void*)x, 1);
          242 }
          243 
          244 /* public helper routine: fmt out a null terminated string already in hand */
          245 int
          246 fmtstrcpy(Fmt *f, char *s)
          247 {
          248         int i, j;
          249 
          250         if(!s)
          251                 return __fmtcpy(f, "<nil>", 5, 5);
          252         /* if precision is specified, make sure we don't wander off the end */
          253         if(f->flags & FmtPrec){
          254 #ifdef PLAN9PORT
          255                 Rune r;
          256                 i = 0;
          257                 for(j=0; j<f->prec && s[i]; j++)
          258                         i += chartorune(&r, s+i);
          259 #else
          260                 /* ANSI requires precision in bytes, not Runes */
          261                 for(i=0; i<f->prec; i++)
          262                         if(s[i] == 0)
          263                                 break;
          264                 j = utfnlen(s, i);        /* won't print partial at end */
          265 #endif
          266                 return __fmtcpy(f, s, j, i);
          267         }
          268         return __fmtcpy(f, s, utflen(s), strlen(s));
          269 }
          270 
          271 /* fmt out a null terminated utf string */
          272 int
          273 __strfmt(Fmt *f)
          274 {
          275         char *s;
          276 
          277         s = va_arg(f->args, char *);
          278         return fmtstrcpy(f, s);
          279 }
          280 
          281 /* public helper routine: fmt out a null terminated rune string already in hand */
          282 int
          283 fmtrunestrcpy(Fmt *f, Rune *s)
          284 {
          285         Rune *e;
          286         int n, p;
          287 
          288         if(!s)
          289                 return __fmtcpy(f, "<nil>", 5, 5);
          290         /* if precision is specified, make sure we don't wander off the end */
          291         if(f->flags & FmtPrec){
          292                 p = f->prec;
          293                 for(n = 0; n < p; n++)
          294                         if(s[n] == 0)
          295                                 break;
          296         }else{
          297                 for(e = s; *e; e++)
          298                         ;
          299                 n = e - s;
          300         }
          301         return __fmtrcpy(f, s, n);
          302 }
          303 
          304 /* fmt out a null terminated rune string */
          305 int
          306 __runesfmt(Fmt *f)
          307 {
          308         Rune *s;
          309 
          310         s = va_arg(f->args, Rune *);
          311         return fmtrunestrcpy(f, s);
          312 }
          313 
          314 /* fmt a % */
          315 int
          316 __percentfmt(Fmt *f)
          317 {
          318         Rune x[1];
          319 
          320         x[0] = f->r;
          321         f->prec = 1;
          322         return __fmtrcpy(f, (const void*)x, 1);
          323 }
          324 
          325 /* fmt an integer */
          326 int
          327 __ifmt(Fmt *f)
          328 {
          329         char buf[140], *p, *conv;
          330         /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
          331         uvlong vu;
          332         ulong u;
          333         int neg, base, i, n, fl, w, isv;
          334         int ndig, len, excess, bytelen;
          335         char *grouping;
          336         char *thousands;
          337 
          338         neg = 0;
          339         fl = f->flags;
          340         isv = 0;
          341         vu = 0;
          342         u = 0;
          343 #ifndef PLAN9PORT
          344         /*
          345          * Unsigned verbs for ANSI C
          346          */
          347         switch(f->r){
          348         case 'o':
          349         case 'p':
          350         case 'u':
          351         case 'x':
          352         case 'X':
          353                 fl |= FmtUnsigned;
          354                 fl &= ~(FmtSign|FmtSpace);
          355                 break;
          356         }
          357 #endif
          358         if(f->r == 'p'){
          359                 u = (ulong)va_arg(f->args, void*);
          360                 f->r = 'x';
          361                 fl |= FmtUnsigned;
          362         }else if(fl & FmtVLong){
          363                 isv = 1;
          364                 if(fl & FmtUnsigned)
          365                         vu = va_arg(f->args, uvlong);
          366                 else
          367                         vu = va_arg(f->args, vlong);
          368         }else if(fl & FmtLong){
          369                 if(fl & FmtUnsigned)
          370                         u = va_arg(f->args, ulong);
          371                 else
          372                         u = va_arg(f->args, long);
          373         }else if(fl & FmtByte){
          374                 if(fl & FmtUnsigned)
          375                         u = (uchar)va_arg(f->args, int);
          376                 else
          377                         u = (char)va_arg(f->args, int);
          378         }else if(fl & FmtShort){
          379                 if(fl & FmtUnsigned)
          380                         u = (ushort)va_arg(f->args, int);
          381                 else
          382                         u = (short)va_arg(f->args, int);
          383         }else{
          384                 if(fl & FmtUnsigned)
          385                         u = va_arg(f->args, uint);
          386                 else
          387                         u = va_arg(f->args, int);
          388         }
          389         conv = "0123456789abcdef";
          390         grouping = "\4";        /* for hex, octal etc. (undefined by spec but nice) */
          391         thousands = f->thousands;
          392         switch(f->r){
          393         case 'd':
          394         case 'i':
          395         case 'u':
          396                 base = 10;
          397                 grouping = f->grouping;
          398                 break;
          399         case 'X':
          400                 conv = "0123456789ABCDEF";
          401                 /* fall through */
          402         case 'x':
          403                 base = 16;
          404                 thousands = ":";
          405                 break;
          406         case 'b':
          407                 base = 2;
          408                 thousands = ":";
          409                 break;
          410         case 'o':
          411                 base = 8;
          412                 break;
          413         default:
          414                 return -1;
          415         }
          416         if(!(fl & FmtUnsigned)){
          417                 if(isv && (vlong)vu < 0){
          418                         vu = -(vlong)vu;
          419                         neg = 1;
          420                 }else if(!isv && (long)u < 0){
          421                         u = -(long)u;
          422                         neg = 1;
          423                 }
          424         }
          425         p = buf + sizeof buf - 1;
          426         n = 0;        /* in runes */
          427         excess = 0;        /* number of bytes > number runes */
          428         ndig = 0;
          429         len = utflen(thousands);
          430         bytelen = strlen(thousands);
          431         if(isv){
          432                 while(vu){
          433                         i = vu % base;
          434                         vu /= base;
          435                         if((fl & FmtComma) && n % 4 == 3){
          436                                 *p-- = ',';
          437                                 n++;
          438                         }
          439                         if((fl & FmtApost) && __needsep(&ndig, &grouping)){
          440                                 n += len;
          441                                 excess += bytelen - len;
          442                                 p -= bytelen;
          443                                 memmove(p+1, thousands, bytelen);
          444                         }
          445                         *p-- = conv[i];
          446                         n++;
          447                 }
          448         }else{
          449                 while(u){
          450                         i = u % base;
          451                         u /= base;
          452                         if((fl & FmtComma) && n % 4 == 3){
          453                                 *p-- = ',';
          454                                 n++;
          455                         }
          456                         if((fl & FmtApost) && __needsep(&ndig, &grouping)){
          457                                 n += len;
          458                                 excess += bytelen - len;
          459                                 p -= bytelen;
          460                                 memmove(p+1, thousands, bytelen);
          461                         }
          462                         *p-- = conv[i];
          463                         n++;
          464                 }
          465         }
          466         if(n == 0){
          467                 /*
          468                  * "The result of converting a zero value with
          469                  * a precision of zero is no characters."  - ANSI
          470                  *
          471                  * "For o conversion, # increases the precision, if and only if
          472                  * necessary, to force the first digit of the result to be a zero
          473                  * (if the value and precision are both 0, a single 0 is printed)." - ANSI
          474                  */
          475                 if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
          476                         *p-- = '0';
          477                         n = 1;
          478                         if(fl & FmtApost)
          479                                 __needsep(&ndig, &grouping);
          480                 }
          481                 
          482                 /*
          483                  * Zero values don't get 0x.
          484                  */
          485                 if(f->r == 'x' || f->r == 'X')
          486                         fl &= ~FmtSharp;
          487         }
          488         for(w = f->prec; n < w && p > buf+3; n++){
          489                 if((fl & FmtApost) && __needsep(&ndig, &grouping)){
          490                         n += len;
          491                         excess += bytelen - len;
          492                         p -= bytelen;
          493                         memmove(p+1, thousands, bytelen);
          494                 }
          495                 *p-- = '0';
          496         }
          497         if(neg || (fl & (FmtSign|FmtSpace)))
          498                 n++;
          499         if(fl & FmtSharp){
          500                 if(base == 16)
          501                         n += 2;
          502                 else if(base == 8){
          503                         if(p[1] == '0')
          504                                 fl &= ~FmtSharp;
          505                         else
          506                                 n++;
          507                 }
          508         }
          509         if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
          510                 w = 0;
          511                 if(fl & FmtWidth)
          512                         w = f->width;
          513                 for(; n < w && p > buf+3; n++){
          514                         if((fl & FmtApost) && __needsep(&ndig, &grouping)){
          515                                 n += len;
          516                                 excess += bytelen - len;
          517                                 p -= bytelen;
          518                                 memmove(p+1, thousands, bytelen);
          519                         }
          520                         *p-- = '0';
          521                 }
          522                 f->flags &= ~FmtWidth;
          523         }
          524         if(fl & FmtSharp){
          525                 if(base == 16)
          526                         *p-- = f->r;
          527                 if(base == 16 || base == 8)
          528                         *p-- = '0';
          529         }
          530         if(neg)
          531                 *p-- = '-';
          532         else if(fl & FmtSign)
          533                 *p-- = '+';
          534         else if(fl & FmtSpace)
          535                 *p-- = ' ';
          536         f->flags &= ~FmtPrec;
          537         return __fmtcpy(f, p + 1, n, n + excess);
          538 }
          539 
          540 int
          541 __countfmt(Fmt *f)
          542 {
          543         void *p;
          544         ulong fl;
          545 
          546         fl = f->flags;
          547         p = va_arg(f->args, void*);
          548         if(fl & FmtVLong){
          549                 *(vlong*)p = f->nfmt;
          550         }else if(fl & FmtLong){
          551                 *(long*)p = f->nfmt;
          552         }else if(fl & FmtByte){
          553                 *(char*)p = f->nfmt;
          554         }else if(fl & FmtShort){
          555                 *(short*)p = f->nfmt;
          556         }else{
          557                 *(int*)p = f->nfmt;
          558         }
          559         return 0;
          560 }
          561 
          562 int
          563 __flagfmt(Fmt *f)
          564 {
          565         switch(f->r){
          566         case ',':
          567                 f->flags |= FmtComma;
          568                 break;
          569         case '-':
          570                 f->flags |= FmtLeft;
          571                 break;
          572         case '+':
          573                 f->flags |= FmtSign;
          574                 break;
          575         case '#':
          576                 f->flags |= FmtSharp;
          577                 break;
          578         case '\'':
          579                 f->flags |= FmtApost;
          580                 break;
          581         case ' ':
          582                 f->flags |= FmtSpace;
          583                 break;
          584         case 'u':
          585                 f->flags |= FmtUnsigned;
          586                 break;
          587         case 'h':
          588                 if(f->flags & FmtShort)
          589                         f->flags |= FmtByte;
          590                 f->flags |= FmtShort;
          591                 break;
          592         case 'L':
          593                 f->flags |= FmtLDouble;
          594                 break;
          595         case 'l':
          596                 if(f->flags & FmtLong)
          597                         f->flags |= FmtVLong;
          598                 f->flags |= FmtLong;
          599                 break;
          600         }
          601         return 1;
          602 }
          603 
          604 /* default error format */
          605 int
          606 __badfmt(Fmt *f)
          607 {
          608         char x[2+UTFmax];
          609         int n;
          610 
          611         x[0] = '%';
          612         n = 1 + runetochar(x+1, &f->r);
          613         x[n++] = '%';
          614         f->prec = n;
          615         __fmtcpy(f, (const void*)x, n, n);
          616         return 0;
          617 }