9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

fmtquote.c (5023B)


      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 /*
      9  * How many bytes of output UTF will be produced by quoting (if necessary) this string?
     10  * How many runes? How much of the input will be consumed?
     11  * The parameter q is filled in by __quotesetup.
     12  * The string may be UTF or Runes (s or r).
     13  * Return count does not include NUL.
     14  * Terminate the scan at the first of:
     15  *	NUL in input
     16  *	count exceeded in input
     17  *	count exceeded on output
     18  * *ninp is set to number of input bytes accepted.
     19  * nin may be <0 initially, to avoid checking input by count.
     20  */
     21 void
     22 __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
     23 {
     24 	int w;
     25 	Rune c;
     26 
     27 	q->quoted = 0;
     28 	q->nbytesout = 0;
     29 	q->nrunesout = 0;
     30 	q->nbytesin = 0;
     31 	q->nrunesin = 0;
     32 	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
     33 		if(nout < 2)
     34 			return;
     35 		q->quoted = 1;
     36 		q->nbytesout = 2;
     37 		q->nrunesout = 2;
     38 	}
     39 	for(; nin!=0; nin--){
     40 		if(s)
     41 			w = chartorune(&c, s);
     42 		else{
     43 			c = *r;
     44 			w = runelen(c);
     45 		}
     46 
     47 		if(c == '\0')
     48 			break;
     49 		if(runesout){
     50 			if(q->nrunesout+1 > nout)
     51 				break;
     52 		}else{
     53 			if(q->nbytesout+w > nout)
     54 				break;
     55 		}
     56 
     57 		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
     58 			if(!q->quoted){
     59 				if(runesout){
     60 					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
     61 						break;
     62 				}else{
     63 					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
     64 						break;
     65 				}
     66 				q->nrunesout += 2;	/* include quotes */
     67 				q->nbytesout += 2;	/* include quotes */
     68 				q->quoted = 1;
     69 			}
     70 			if(c == '\'')	{
     71 				if(runesout){
     72 					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
     73 						break;
     74 				}else{
     75 					if(1+q->nbytesout+w > nout)	/* no room for quotes */
     76 						break;
     77 				}
     78 				q->nbytesout++;
     79 				q->nrunesout++;	/* quotes reproduce as two characters */
     80 			}
     81 		}
     82 
     83 		/* advance input */
     84 		if(s)
     85 			s += w;
     86 		else
     87 			r++;
     88 		q->nbytesin += w;
     89 		q->nrunesin++;
     90 
     91 		/* advance output */
     92 		q->nbytesout += w;
     93 		q->nrunesout++;
     94 
     95 #ifndef PLAN9PORT
     96 		/* ANSI requires precision in bytes, not Runes. */
     97 		nin-= w-1;	/* and then n-- in the loop */
     98 #endif
     99 	}
    100 }
    101 
    102 static int
    103 qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
    104 {
    105 	Rune r, *rm, *rme;
    106 	char *t, *s, *m, *me;
    107 	Rune *rt, *rs;
    108 	ulong fl;
    109 	int nc, w;
    110 
    111 	m = sin;
    112 	me = m + q->nbytesin;
    113 	rm = rin;
    114 	rme = rm + q->nrunesin;
    115 
    116 	fl = f->flags;
    117 	w = 0;
    118 	if(fl & FmtWidth)
    119 		w = f->width;
    120 	if(f->runes){
    121 		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
    122 			return -1;
    123 	}else{
    124 		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
    125 			return -1;
    126 	}
    127 	t = (char*)f->to;
    128 	s = (char*)f->stop;
    129 	rt = (Rune*)f->to;
    130 	rs = (Rune*)f->stop;
    131 	if(f->runes)
    132 		FMTRCHAR(f, rt, rs, '\'');
    133 	else
    134 		FMTRUNE(f, t, s, '\'');
    135 	for(nc = q->nrunesin; nc > 0; nc--){
    136 		if(sin){
    137 			r = *(uchar*)m;
    138 			if(r < Runeself)
    139 				m++;
    140 			else if((me - m) >= UTFmax || fullrune(m, me-m))
    141 				m += chartorune(&r, m);
    142 			else
    143 				break;
    144 		}else{
    145 			if(rm >= rme)
    146 				break;
    147 			r = *(uchar*)rm++;
    148 		}
    149 		if(f->runes){
    150 			FMTRCHAR(f, rt, rs, r);
    151 			if(r == '\'')
    152 				FMTRCHAR(f, rt, rs, r);
    153 		}else{
    154 			FMTRUNE(f, t, s, r);
    155 			if(r == '\'')
    156 				FMTRUNE(f, t, s, r);
    157 		}
    158 	}
    159 
    160 	if(f->runes){
    161 		FMTRCHAR(f, rt, rs, '\'');
    162 		USED(rs);
    163 		f->nfmt += rt - (Rune *)f->to;
    164 		f->to = rt;
    165 		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
    166 			return -1;
    167 	}else{
    168 		FMTRUNE(f, t, s, '\'');
    169 		USED(s);
    170 		f->nfmt += t - (char *)f->to;
    171 		f->to = t;
    172 		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
    173 			return -1;
    174 	}
    175 	return 0;
    176 }
    177 
    178 int
    179 __quotestrfmt(int runesin, Fmt *f)
    180 {
    181 	int nin, outlen;
    182 	Rune *r;
    183 	char *s;
    184 	Quoteinfo q;
    185 
    186 	nin = -1;
    187 	if(f->flags&FmtPrec)
    188 		nin = f->prec;
    189 	if(runesin){
    190 		r = va_arg(f->args, Rune *);
    191 		s = nil;
    192 	}else{
    193 		s = va_arg(f->args, char *);
    194 		r = nil;
    195 	}
    196 	if(!s && !r)
    197 		return __fmtcpy(f, (void*)"<nil>", 5, 5);
    198 
    199 	if(f->flush)
    200 		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
    201 	else if(f->runes)
    202 		outlen = (Rune*)f->stop - (Rune*)f->to;
    203 	else
    204 		outlen = (char*)f->stop - (char*)f->to;
    205 
    206 	__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
    207 /*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
    208 
    209 	if(runesin){
    210 		if(!q.quoted)
    211 			return __fmtrcpy(f, r, q.nrunesin);
    212 		return qstrfmt(nil, r, &q, f);
    213 	}
    214 
    215 	if(!q.quoted)
    216 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
    217 	return qstrfmt(s, nil, &q, f);
    218 }
    219 
    220 int
    221 quotestrfmt(Fmt *f)
    222 {
    223 	return __quotestrfmt(0, f);
    224 }
    225 
    226 int
    227 quoterunestrfmt(Fmt *f)
    228 {
    229 	return __quotestrfmt(1, f);
    230 }
    231 
    232 void
    233 quotefmtinstall(void)
    234 {
    235 	fmtinstall('q', quotestrfmt);
    236 	fmtinstall('Q', quoterunestrfmt);
    237 }
    238 
    239 int
    240 __needsquotes(char *s, int *quotelenp)
    241 {
    242 	Quoteinfo q;
    243 
    244 	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
    245 	*quotelenp = q.nbytesout;
    246 
    247 	return q.quoted;
    248 }
    249 
    250 int
    251 __runeneedsquotes(Rune *r, int *quotelenp)
    252 {
    253 	Quoteinfo q;
    254 
    255 	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
    256 	*quotelenp = q.nrunesout;
    257 
    258 	return q.quoted;
    259 }