9base

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

fmtquote.c (3609B)


      1 /*
      2  * The authors of this software are Rob Pike and Ken Thompson.
      3  *              Copyright (c) 2002 by Lucent Technologies.
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose without fee is hereby granted, provided that this entire notice
      6  * is included in all copies of any software which is or includes a copy
      7  * or modification of this software and in all copies of the supporting
      8  * documentation for such software.
      9  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
     10  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
     11  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
     12  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
     13  */
     14 #include <u.h>
     15 #include <libc.h>
     16 #include "fmt.h"
     17 #include "fmtdef.h"
     18 
     19 extern int (*doquote)(int);
     20 
     21 /*
     22  * How many bytes of output UTF will be produced by quoting (if necessary) this string?
     23  * How many runes? How much of the input will be consumed?
     24  * The parameter q is filled in by _quotesetup.
     25  * The string may be UTF or Runes (s or r).
     26  * Return count does not include NUL.
     27  * Terminate the scan at the first of:
     28  *	NUL in input
     29  *	count exceeded in input
     30  *	count exceeded on output
     31  * *ninp is set to number of input bytes accepted.
     32  * nin may be <0 initially, to avoid checking input by count.
     33  */
     34 void
     35 __quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp)
     36 {
     37 	int c;
     38 
     39 	q->quoted = 0;
     40 	q->nbytesout = 0;
     41 	q->nrunesout = 0;
     42 	q->nbytesin = 0;
     43 	q->nrunesin = 0;
     44 	if(sharp || nin==0 || *s=='\0'){
     45 		if(nout < 2)
     46 			return;
     47 		q->quoted = 1;
     48 		q->nbytesout = 2;
     49 		q->nrunesout = 2;
     50 	}
     51 	for(; nin!=0; nin-=1){
     52 		c = *s;
     53 
     54 		if(c == '\0')
     55 			break;
     56 		if(q->nrunesout+1 > nout)
     57 			break;
     58 
     59 		if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
     60 			if(!q->quoted){
     61 				if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
     62 					break;
     63 				q->nrunesout += 2;	/* include quotes */
     64 				q->nbytesout += 2;	/* include quotes */
     65 				q->quoted = 1;
     66 			}
     67 			if(c == '\'')	{
     68 				q->nbytesout++;
     69 				q->nrunesout++;	/* quotes reproduce as two characters */
     70 			}
     71 		}
     72 
     73 		/* advance input */
     74 		s++;
     75 		q->nbytesin++;
     76 		q->nrunesin++;
     77 
     78 		/* advance output */
     79 		q->nbytesout++;
     80 		q->nrunesout++;
     81 	}
     82 }
     83 
     84 static int
     85 qstrfmt(char *sin, Quoteinfo *q, Fmt *f)
     86 {
     87 	int r;
     88 	char *t, *s, *m, *me;
     89 	ulong fl;
     90 	int nc, w;
     91 
     92 	m = sin;
     93 	me = m + q->nbytesin;
     94 
     95 	w = f->width;
     96 	fl = f->flags;
     97 	if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
     98 		return -1;
     99 	t = f->to;
    100 	s = f->stop;
    101 	FMTCHAR(f, t, s, '\'');
    102 	for(nc = q->nrunesin; nc > 0; nc--){
    103 		r = *(uchar*)m++;
    104 		FMTCHAR(f, t, s, r);
    105 		if(r == '\'')
    106 			FMTCHAR(f, t, s, r);
    107 	}
    108 
    109 	FMTCHAR(f, t, s, '\'');
    110 	f->nfmt += t - (char *)f->to;
    111 	f->to = t;
    112 	if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
    113 		return -1;
    114 	return 0;
    115 }
    116 
    117 int
    118 __quotestrfmt(int runesin, Fmt *f)
    119 {
    120 	int outlen;
    121 	char *s;
    122 	Quoteinfo q;
    123 
    124 	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */
    125 	s = va_arg(f->args, char *);
    126 	if(!s)
    127 		return __fmtcpy(f, "<nil>", 5, 5);
    128 
    129 	if(f->flush)
    130 		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
    131 	else
    132 		outlen = (char*)f->stop - (char*)f->to;
    133 
    134 	__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp);
    135 
    136 	if(!q.quoted)
    137 		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
    138 	return qstrfmt(s, &q, f);
    139 }
    140 
    141 int
    142 quotestrfmt(Fmt *f)
    143 {
    144 	return __quotestrfmt(0, f);
    145 }
    146 
    147 void
    148 quotefmtinstall(void)
    149 {
    150 	fmtinstall('q', quotestrfmt);
    151 }
    152 
    153 int
    154 __needsquotes(char *s, int *quotelenp)
    155 {
    156 	Quoteinfo q;
    157 
    158 	__quotesetup(s, -1, 0x7FFFFFFF, &q, 0);
    159 	*quotelenp = q.nbytesout;
    160 
    161 	return q.quoted;
    162 }