Blob


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"
19 extern int (*doquote)(int);
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;
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;
54 if(c == '\0')
55 break;
56 if(q->nrunesout+1 > nout)
57 break;
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 }
73 /* advance input */
74 s++;
75 q->nbytesin++;
76 q->nrunesin++;
78 /* advance output */
79 q->nbytesout++;
80 q->nrunesout++;
81 }
82 }
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;
92 m = sin;
93 me = m + q->nbytesin;
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);
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;
117 int
118 __quotestrfmt(int runesin, Fmt *f)
120 int outlen;
121 char *s;
122 Quoteinfo q;
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);
129 if(f->flush)
130 outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
131 else
132 outlen = (char*)f->stop - (char*)f->to;
134 __quotesetup(s, -1, outlen, &q, f->flags&FmtSharp);
136 if(!q.quoted)
137 return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
138 return qstrfmt(s, &q, f);
141 int
142 quotestrfmt(Fmt *f)
144 return __quotestrfmt(0, f);
147 void
148 quotefmtinstall(void)
150 fmtinstall('q', quotestrfmt);
153 int
154 __needsquotes(char *s, int *quotelenp)
156 Quoteinfo q;
158 __quotesetup(s, -1, 0x7FFFFFFF, &q, 0);
159 *quotelenp = q.nbytesout;
161 return q.quoted;