fmtquote.c 5.3 KB

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