localefmt.c (2018B)
1 /* Copyright ©2010 Kris Maglione <maglione.k at Gmail> 2 * Copyright ©2002 by Lucent Technologies. 3 * See LICENSE file for license details. 4 */ 5 #include "fmtdef.h" 6 7 static bool 8 pad(Fmt *f, int len) { 9 if(f->flags & FmtWidth) { 10 if(f->runes) 11 return __rfmtpad(f, f->width - len) >= 0; 12 return __fmtpad(f, f->width - len) >= 0; 13 } 14 return true; 15 } 16 17 int 18 localefmt(Fmt *f) { 19 mbstate_t state; 20 Rune *rp, *rend; 21 char *sp, *send, *str, *end; 22 Rune r; 23 wchar_t w; 24 int res, count, rlen; 25 26 str = va_arg(f->args, char*); 27 28 if(utf8locale()) { 29 /* We handle precision in bytes, fmtstrcpy in characters */ 30 if(f->flags & FmtPrec) 31 f->prec = utfnlen(str, f->prec); 32 return fmtstrcpy(f, str); 33 } 34 35 end = 0; 36 if(f->flags & FmtPrec) 37 end = str + f->prec; 38 39 if(!(f->flags & FmtLeft) && !pad(f, localelen(str, end))) 40 return -1; 41 42 sp = f->to; 43 send = f->stop; 44 rp = (Rune*)f->to; 45 rend = (Rune*)f->stop; 46 47 count = 0; 48 for(state = (mbstate_t){0}; ; str += res) { 49 switch((res = mbrtowc(&w, str, end ? end - str : MB_LEN_MAX, &state))) { 50 case 0: 51 case -2: 52 break; 53 case -1: 54 w = Runesync; 55 res = 1; 56 /* Fallthrough. */ 57 default: 58 count++; 59 if(w > Runemax) 60 w = Runesync; 61 r = w; 62 // print("%d %C\n", res, r); 63 if(f->runes) { 64 if(rp >= rend) { 65 // print("flush\n"); 66 rp = (Rune*)__fmtflush(f, rp, sizeof *rp); 67 rend = (Rune*)f->stop; 68 if(rp == nil) 69 return -1; 70 } 71 *rp++ = r; 72 }else { 73 if(sp + UTFmax > send && sp + (rlen = runelen(r)) > send) { 74 // print("flush %d\n", rlen); 75 sp = __fmtflush(f, sp, rlen); 76 send = f->stop; 77 if(sp == nil) 78 return -1; 79 } 80 if(r < Runeself) 81 *sp++ = (char)r; 82 else 83 sp += runetochar(sp, &r); 84 } 85 continue; 86 } 87 if(f->runes) { 88 f->nfmt += rp - (Rune*)f->to; 89 f->to = (char*)rp; 90 }else { 91 f->nfmt += sp - (char*)f->to; 92 f->to = sp; 93 } 94 break; 95 } 96 97 if((f->flags & FmtLeft) && !pad(f, count)) 98 return -1; 99 100 return 0; 101 } 102 103 void 104 localefmtinstall(void) { 105 fmtinstall('L', localefmt); 106 } 107