The Go Programming Language

Text file src/lib9/fmt/fmtquote.c

     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(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, 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 += 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 += 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 = (Rune*)f->stop - (Rune*)f->to;
   218		else
   219			outlen = (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	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.