fmtquote.c 5.5 KB

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