github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/src/lib9/fmt/fmtquote.c (about)

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