1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *   $Header: /upc/share/CVS/netcdf-3/ncgen/escapes.c,v 1.5 2010/04/04 19:39:44 dmh Exp $
5 *********************************************************************/
6
7#include "includes.h"
8#include "ConvertUTF.h"
9
10#define HEXCHARS "0123456789abcdefABCDEF"
11#define OCTCHARS "01234567"
12
13/* Forward*/
14static void initcodify(void);
15static char* ccodify(const char*);
16static char* f77codify(const char*);
17static char* jcodify(const char*);
18
19#if 0
20/*
21 * Replace escaped chars in CDL representation of name such as
22 * 'abc\:def\ gh\\i' with unescaped version, such as 'abc:def gh\i'.
23 */
24/* ?? This seems redundant over expand_escapes*/
25void
26deescapify(char* name)
27{
28    const char *cp = name;
29    char *sp;
30    size_t len = strlen(name);
31    char *newname;
32
33    if(strchr(name, '\\') == NULL)
34 return;
35
36    newname = (char *) emalloc(len + 1);
37    cp = name;
38    sp = newname;
39    while(*cp != '\0') { /* delete '\' chars, except change '\\' to '\' */
40 switch (*cp) {
41 case '\\':
42     if(*(cp+1) == '\\') {
43 *sp++ = '\\';
44 cp++;
45     }
46     break;
47 default:
48     *sp++ = *cp;
49     break;
50 }
51 cp++;
52    }
53    *sp = '\0';
54    /* ASSERT(strlen(newname) <= strlen(name)); */
55    strncpy(namenewnamelen+1); /* watch out for trailing null*/
56    efree(newname);
57    return;
58}
59#endif /*0*/
60
61/*
62Given a character c, fill s with the character suitably escaped.
63E.g. c = '\t' => s="\t"
64Caller must ensure enough space.
65Watch out for embedded NULs.
66Currently passes unicode thru unchanged.
67Returns s as its result.
68*/
69
70char*
71escapifychar(unsigned int c, char* s0, int quote)
72{
73    char* s = s0;
74    if(c == '\\') {
75 *s++ = '\\'; *s++='\\';
76    } else if(c == quote) {
77 *s++ = '\\'; *s++=(char)quote;
78    } else if(c >= ' ' && c != '\177') {
79 *s++ = (char)c;
80    } else if((c & 0x80) != 0) {/* Unicode */
81 *s++ = (char)c;
82    } else {
83        switch (c) {
84 case '\b': strcpy(s,"\\b"); s+=2; break;
85 case '\f': strcpy(s,"\\f"); s+=2; break;
86 case '\n': strcpy(s,"\\n"); s+=2; break;
87 case '\r': strcpy(s,"\\r"); s+=2; break;
88 case '\t': strcpy(s,"\\t"); s+=2; break;
89 case '\v': strcpy(s,"\\v"); s+=2; break;
90 default: {
91     unsigned int oct1 = (c & 007);
92     unsigned int oct2 = ((c >> 3) & 007);
93     unsigned int oct3 = ((c >> 6) & 003);
94     *s++ = '\\';
95     *s++ = oct3 + '0';
96     *s++ = oct2 + '0';
97     *s++ = oct1 + '0';
98 } break;
99 }
100    }
101    *s = '\0';
102    return s0;
103}
104
105/* Return a pool string that is s0 with all characters*/
106/* ecaped that require it.  The resulting string is not*/
107/* surrounded by quotes.*/
108/* Since the string might actually contain nulls, specify the length.*/
109
110char*
111escapify(char* s0, int quote, size_t len)
112{
113    int i;
114    char* result;
115    result = poolalloc(1+4*len); /* overkill to support maximal expansion*/
116    result[0] = '\0';
117    for(i=0;i<len;i++) {
118 char tmp[8];
119 escapifychar((unsigned int)s0[i],tmp,quote);
120        strcat(result,tmp);
121    }
122    return result;
123}
124
125char*
126escapifyname(char* s0)
127{
128    return escapify(s0,'"',strlen(s0));
129}
130
131void
132cquotestring(Bytebufferdatabuf, char quote)
133{
134    char* escaped = escapify(bbContents(databuf),'"',bbLength(databuf));
135    bbClear(databuf);
136    bbAppend(databuf,quote);
137    bbCat(databuf,escaped);
138    bbAppend(databuf,quote);
139}
140
141/*
142 * Replace special chars in name so it can be used in C and Fortran
143 * variable names without causing syntax errors.  Here we just replace
144 * each "-" in a name with "_MINUS_", each "." with "_PERIOD_", etc.
145 * For bytes with high bit set, from UTF-8 encoding of Unicode, just
146 * replace with "_xHH", where each H is the appropriate hex digit.
147 * However, if the utf flag is set, then just pass utf characters as is.
148 * If a name begins with a number N, such as "4LFTX", replace with
149 * "DIGIT_N_", such as "DIGIT_4_LFTX".
150 * Note that apparently, FORTRAN will not allow a leading underscore,
151 * so remove if we are doing fortran.
152 *
153 * It is required that codify be idempotent:
154 * i.e. codify(codify(s)) == codify(s)
155 *
156 * Returned name is pool alloc'd so is transient
157 */
158
159static int init = 0;
160static char* repls[256]; /* replacement string for each char */
161static int lens[256]; /* lengths of replacement strings */
162static struct {
163 char c;
164 char *s;
165ctable[] = {
166 {' ', "_SPACE_"},
167 {'!', "_EXCLAMATION_"},
168 {'"', "_QUOTATION_"},
169 {'#', "_HASH_"},
170 {'$', "_DOLLAR_"},
171 {'%', "_PERCENT_"},
172 {'&', "_AMPERSAND_"},
173 {'\'', "_APOSTROPHE_"},
174 {'(', "_LEFTPAREN_"},
175 {')', "_RIGHTPAREN_"},
176 {'*', "_ASTERISK_"},
177 {'+', "_PLUS_"},
178 {',', "_COMMA_"},
179 {'-', "_MINUS_"},
180 {'.', "_PERIOD_"},
181 {':', "_COLON_"},
182 {';', "_SEMICOLON_"},
183 {'<', "_LESSTHAN_"},
184 {'=', "_EQUALS_"},
185 {'>', "_GREATERTHAN_"},
186 {'?', "_QUESTION_"},
187 {'@', "_ATSIGN_"},
188 {'[', "_LEFTBRACKET_"},
189 {'\\', "_BACKSLASH_"},
190 {']', "_RIGHTBRACKET_"},
191 {'^', "_CIRCUMFLEX_"},
192 {'`', "_BACKQUOTE_"},
193 {'{', "_LEFTCURLY_"},
194 {'|', "_VERTICALBAR_"},
195 {'}', "_RIGHTCURLY_"},
196 {'~', "_TILDE_"},
197  {'/', "_SLASH_"},
198};
199static int idtlen;
200static int hexlen;
201static Bytebuffernewname;
202
203static void
204initcodify(void)
205{
206    int nctable = (sizeof(ctable))/(sizeof(ctable[0]));
207    int i;
208    char *rp;
209
210    newname = bbNew();
211    idtlen = strlen("DIGIT_n_"); /* initial digit template */
212    hexlen = strlen("_XHH"); /* template for hex of non-ASCII bytes */
213    for(i = 0; i < 128; i++) {
214        rp = emalloc(2);
215        rp[0] = i;
216        rp[1] = '\0';
217        repls[i] = rp;
218    }
219    for(i=0; i < nctablei++) {
220        size_t j = ctable[i].c;
221        efree(repls[j]);
222        repls[j] = ctable[i].s;
223    }
224    for(i = 128; i < 256; i++) {
225        rp = emalloc(hexlen+1);
226        snprintf(rphexlen+1, "_X%2.2X", i); /* need to include null*/
227        rp[hexlen] = '\0';
228        repls[i] = rp;
229    }
230    for(i = 0; i < 256; i++) {
231        lens[i] = strlen(repls[i]);
232    }
233    init = 1;               /* only do this initialization once */
234}
235
236/*
237Convert a name to a
238form suitable for use in a
239language file.
240Conversion depends on l_flag.
241*/
242char*
243codify(const char *name0)
244{
245    /* If the name is rooted, then elide
246       the leading '/'.
247    */
248    if(name0[0] == '/')
249 name0++;
250    switch (l_flag) {
251    case L_BINARY:
252 return pooldup(name0);
253    case L_C:
254        return ccodify(name0);
255    case L_F77:
256        return f77codify(name0);
257    case L_JAVA:
258        return jcodify(name0);
259    default:
260        assert(0); /*no such language*/
261    }
262    return NULL;
263}
264
265static char*
266ccodify(const char *name0)
267{
268    const unsigned char *cp;
269    unsigned int c;
270    char* name;
271
272    if(init == 0) initcodify();
273    bbClear(newname);
274    cp = (const unsigned char*) name0;
275    if('0' <= *cp && *cp <= '9') { /* handle initial digit, if any */
276 char tmp[16];
277 snprintf(tmp,sizeof(tmp),"DIGIT_%c_", *cp);
278 bbCat(newname,tmp);
279 cp++;
280    }
281    while((c=*cp++)) { /* copy name to newname, replacing special chars */
282 ASSERT(c <= 256);
283 bbCat(newname,repls[c]);
284    }
285    /* Remove leading _, if any */
286    name = bbContents(newname);
287    if(bbGet(newname,0) == '_') name++;
288    return pooldup(name);
289}
290
291char*
292cescapifychar(unsigned int c, int quote)
293{
294    char* s = poolalloc(4+1);
295    escapifychar(c,s,quote);
296    return s;
297}
298
299/**************************************************/
300/* CML String Escapes */
301/**************************************************/
302
303/*
304Given a character c, fill s with the character suitably escaped
305for use with xml.
306Caller must ensure enough space
307Currently does not handle unicode
308Returns s as it result.
309*/
310
311static char hexdigits[] = "0123456789ABCDEF";
312
313static char printescapable[] = "\"&<>";
314static char* printescape[] = {"quot", "amp", "lt", "gt"};
315
316static void
317xescapifychar(unsigned int c, int quoteBytebuffers)
318{
319    if(c >= ' ' && c < '\177') {
320 char* p;
321 char** q;
322 for(p=printescapable,q=printescape;*p;p++,q++) {if(c==*p) break;}
323 if(*p) {
324     bbAppend(s,'&');
325     bbCat(s,*q);
326     bbAppend(s,';');
327 } else
328     bbAppend(s,(char)c);
329    } else {
330 /* Do hex escape */
331     unsigned int hex1 = (c & 0x0f);
332     unsigned int hex2 = ((c >> 4) & 0x0f);
333     bbCat(s,"&#");
334     bbAppend(s,hexdigits[hex2]);
335     bbAppend(s,hexdigits[hex1]);
336     bbAppend(s,';');
337    }
338}
339
340/* Return a pool string that is s0 with all characters
341   ecaped that require it.  The resulting string is not
342   surrounded by quotes.
343   Since the string might actually contain nulls, specify the length.
344*/
345
346char*
347xescapify(char* s0, int quote, size_t len)
348{
349    int i;
350    char* result;
351    Bytebufferescaped = bbNew();
352    for(i=0;i<len;i++) {
353 xescapifychar((unsigned int)s0[i],quote,escaped);
354    }
355    result = pooldup(bbContents(escaped));
356    bbFree(escaped);
357    return result;
358}
359
360/**************************************************/
361/* Java String Escapes */
362/**************************************************/
363
364/*
365Given a utf16 character c,
366fill s with the characters needed
367to suitably escape c for use with Java.
368*/
369
370static void
371jescapifychar(UTF16 c, int quoteBytebuffers)
372{
373    /* Separate out ascii from UTF16 */
374    if(c <= '\177') {
375 /* Separate printables from controls */
376        if(c >= ' ' && c < '\177') {
377     if (c == quote) {
378 bbAppend(s,'\\');
379     }
380     bbAppend(s,(char)c);
381 } else switch (c) {
382     case '\t': bbCat(s,"\\t"); break;
383     case '\b': bbCat(s,"\\b"); break;
384     case '\n': bbCat(s,"\\n"); break;
385     case '\r': bbCat(s,"\\r"); break;
386     case '\f': bbCat(s,"\\f"); break;
387     default:
388 { /* Do hex escape */
389 int hex1 = (c & 0x0f);
390 int hex2 = ((c >> 4) & 0x0f);
391 int hex3 = ((c >> 8) & 0x0f);
392 int hex4 = ((c >> 12) & 0x0f);
393 bbAppend(s,'\\');
394 bbAppend(s,'u');
395 bbAppend(s,hexdigits[hex4]);
396 bbAppend(s,hexdigits[hex3]);
397 bbAppend(s,hexdigits[hex2]);
398 bbAppend(s,hexdigits[hex1]);
399 } break;
400 }
401    } else { /* Do \uxxxx escapes */
402 /* Do hex escape */
403 int hex1 = (c & 0x0f);
404 int hex2 = ((c >> 4) & 0x0f);
405 int hex3 = ((c >> 8) & 0x0f);
406 int hex4 = ((c >> 12) & 0x0f);
407 bbAppend(s,'\\');
408 bbAppend(s,'u');
409 bbAppend(s,hexdigits[hex4]);
410 bbAppend(s,hexdigits[hex3]);
411 bbAppend(s,hexdigits[hex2]);
412 bbAppend(s,hexdigits[hex1]);
413    }
414}
415
416/* Return a pool string that is s0 with all characters
417   ecaped that require it.  The resulting string is not
418   surrounded by quotes.
419   Since the string might actually contain nulls, specify the length.
420*/
421
422char*
423jescapify(char* s0, int quote, size_t len)
424{
425    int i;
426    char* result;
427    UTF8s8;
428    UTF16s16; /* for storing the utf16 string */
429    UTF16tmp16; /* for storing the utf16 string */
430    ConversionResult status;
431    Bytebufferescaped = bbNew();
432    size_t len16;
433
434    s16 = emalloc((1+len)*sizeof(UTF16));
435    s8 = (UTF8*)s0;
436    tmp16 = s16;
437    status = ConvertUTF8toUTF16((const UTF8**)&s8,s8+len,&tmp16,tmp16+len,lenientConversion);
438    if(status != conversionOK) {
439 derror("Cannot convert UTF8 string to UTF16: %s",s0);
440 return NULL;
441    }
442    /* Get the length of the utf16 string */
443    len16 = (tmp16 - s16);
444    for(i=0;i<len16;i++) {
445 jescapifychar(s16[i],quote,escaped);
446    }
447    efree(s16);
448    result = pooldup(bbContents(escaped));
449    bbFree(escaped);
450    return result;
451}
452
453char*
454jescapifyname(char* s0)
455{
456    return jescapify(s0,'"',strlen(s0));
457}
458
459/*
460Convert a java name that might possibly
461contain utf8 characters to one that is
462acceptable to the Java compiler.
463Basically this means convert the printables
464using ccodify (above) equivalent and then escape
465all the utf chars.
466*/
467static char*
468jcodify (const char *name)
469{
470    return ccodify(name);
471}
472
473/**************************************************/
474/* FORTRAN does escapes differently than e.g. C */
475
476char*
477f77escapifychar(unsigned int c, char* s0)
478{
479    char* s = s0;
480    s0[0] = '\0';
481    if(c == '\'') {
482 *s++ = '\''; *s++='\'';
483    } else if(c >= ' ' && c < '\177') {
484 *s++ = (char)c;
485    } else {
486 char tmp[32];
487 nprintf(tmp,sizeof(tmp),"//char(%u)",c);
488 strcat(s,tmp);
489 s += strlen(tmp);
490    }
491    *s = '\0';
492    return s0;
493}
494
495void
496f77quotestring(Bytebufferdatabuf)
497{
498    int i;
499    int lastcharescaped;
500    unsigned int slen = bbLength(databuf);
501    unsigned char* s;
502
503    /* Handle the empty string case */
504    if(slen == 0) {
505 bbCat(databuf,"char(0)");
506 return;
507    }
508
509    s = (unsigned char*)emalloc(slen+1);
510    memcpy((void*)s,bbContents(databuf),slen);
511    s[slen] = '\0';
512    bbClear(databuf);
513
514    lastcharescaped = 0;
515    for(i=0;i<slen;i++) {
516 char tmp[32];
517 unsigned int c = s[i];
518 int thischarescaped = (c < ' ' || c >= '\177');
519 if(i > 0) {
520            if(!lastcharescaped && thischarescapedbbAppend(databuf,'\'');
521     else if(lastcharescaped && !thischarescapedbbCat(databuf,"//'");
522 } else if(!thischarescaped)
523     bbAppend(databuf,'\'');
524 f77escapifychar(c,tmp);
525 if(i == 0 && thischarescaped)
526            bbCat(databuf,tmp+2);
527 else
528            bbCat(databuf,tmp);
529 lastcharescaped = thischarescaped;
530    }
531    if(!lastcharescapedbbAppend(databuf,'\'');
532}
533
534static char*
535f77codify(const char* s0)
536{
537    Bytebufferbuf = bbNew();
538    char* name;
539    bbCat(buf,s0);
540    f77quotestring(buf);
541    name = bbDup(buf);
542    bbFree(buf);
543    return name;
544}
545
546/**************************************************/
547/* Escape Fqn segment names by replacing
548   '/' and '.' by alternate representation.
549*/
550
551char*
552fqnescape(const char* s)
553{
554    const char* p;
555    char* q;
556    int c;
557    int l = strlen(s);
558
559/*
5601234567
561_SLASH_
562_DOT__
563*/
564    char* newname = poolalloc(l*7+1);
565    *newname = '\0';
566    for(q=newname,p=s;(c=*p++);) {
567#if 0
568        if(c == '/' || c == '.') {
569     /* Do hex escape */
570     int hex1 = (c & 0x0f);
571     int hex2 = ((c >> 4) & 0x0f);
572     *q++ = 'X';
573            *q++ = hexdigits[hex1];
574            *q++ = hexdigits[hex2];
575        } else
576     *q++ = c;
577#else
578        if(c == '/') {
579     strcat(q,"_SLASH_");
580     q += 7;
581        } else if(c == '.') {
582     strcat(q,"_DOT_");
583     q += 5;
584 } else {
585     *q++ = c;
586     *q = '\0';
587 }
588#endif
589    }
590    return newname;
591}
592
593/**************************************************/
594
595/*
596 * Given a pointer to a string of the form
597 * 'xdd', return the corresponding hex byte
598 */
599
600int
601unescapehex(const char* s)
602{
603    int b;
604    int c1 = s[0];
605    int c2 = s[1];
606    if(strchr(HEXCHARS,c1) == NULL
607       || strchr(HEXCHARS,c2) == NULL)
608 return -1;
609    b = 0;
610    if(c1 < 'a') c1 = (c1 - 'A') + 'a';/* lowercase */
611    if(c1 <= '9') b = (c1 - '0') << 4;
612    else b = ((c1 - 'a')+10) << 4;
613    if(c2 < 'a') c2 |= (c2 - 'A') + 'a';/* lowercase */
614    if(c2 <= '9') b = (c2 - '0');
615    else b |= ((c2 - 'a')+10);
616    return b;
617}
618
619/*
620 * Given a pointer to a string of the form
621 * 'ddd', return the corresponding
622 * unsigned octal byte
623 */
624
625int
626unescapeoct(const char* s)
627{
628    int b;
629    int c1 = s[0];
630    int c2 = s[1];
631    int c3 = s[2];
632    if(strchr(OCTCHARS,c1) == NULL
633       || strchr(OCTCHARS,c2) == NULL
634       || strchr(OCTCHARS,c3) == NULL)
635 return -1;
636    b = (c1 - '0') << 6;
637    b |= (c2 - '0') << 3;
638    b |= (c3 - '0');
639    return b;
640}
641
642/*
643 * "Un-escapes" valid escape sequences in yystring (read by lex) into the
644 * appropriate unescaped characters.  For example, the two character
645 * sequence "\t" in yystring would be converted into a single tab character.
646 * On return, termstring is nul terminated.
647 * Watch out for embedded nuls and utf-8 characters.
648 * Return # of characters written.
649 * Note that the escape handling for identifiers is different
650 * than for string constants
651 */
652
653int
654unescape(
655     char *s, /* fill with contents of yytext, with escapes removed.
656                 s and yytext may be same*/
657     const char *yytext,
658     int yyleng,
659     int isident)
660{
661    const char *t, *tend;
662    char* p;
663    int b;
664    /* expand "\" escapes, e.g. "\t" to tab character  */
665    t = yytext;
666    tend = t + yyleng;
667    p = s;
668    while(*t && t < tend) {
669 if (*t == '\\') {
670     t++;
671     switch (*t) {
672       case 'a':
673 *p++ = ('\007'); t++; /* will use '\a' when STDC */
674 break;
675       case 'b':
676 *p++ = ('\b'); t++;
677 break;
678       case 'f':
679 *p++ = ('\f'); t++;
680 break;
681       case 'n':
682 *p++ = ('\n'); t++;
683 break;
684       case 'r':
685 *p++ = ('\r'); t++;
686 break;
687       case 't':
688 *p++ = ('\t'); t++;
689 break;
690       case 'v':
691 *p++ = ('\v'); t++;
692 break;
693       case '\\':
694 *p++ = ('\\'); t++;
695 break;
696       case '?':
697 *p++ = ('\177'); t++;
698 break;
699       case '\'':
700 *p++ = ('\''); t++;
701 break;
702       case '\"':
703 *p++ = ('\"'); t++;
704 break;
705       /* Hex or oct constants not allowed in identifiers */
706       case 'x':
707 if(!isident) {
708     /* t now points to hex */
709     b = unescapehex(t);
710     t += 2;
711 } else
712     b = *t++;
713         *p++ = ((char)b);
714 break;
715       case '0': case '1': case '2': case '3':
716       case '4': case '5': case '6': case '7':
717 if(!isident) {
718     /* t now points to octal */
719     b = unescapeoct(t);
720     if(b < 0) {
721         derror("Bad octal constant: %s",yytext);
722         b = 0;
723     }
724     t += 3;
725 } else
726     b = *t++;
727  *p++ = ((char)b);
728 break;
729       default:
730 *p++ = (*t); t++;
731 break;
732     }
733 } else {
734     *p++ = (*t); t++;
735 }
736    }
737    *p = '\0';
738    return (p - s);
739}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed