Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
fmtesc.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Glenn Fowler
13 * AT&T Research
14 *
15 * return string with expanded escape chars
16 */
17
18#include <ast/ast.h>
19#include <cgraph/agxbuf.h>
20#include <cgraph/gv_ctype.h>
21#include <stdbool.h>
22#include <stdlib.h>
23#include <string.h>
24
26char *fmtquote(const char *as, const char *qb, const char *qe) {
27 const size_t n = strlen(as);
28 const unsigned char *s = (const unsigned char *) as;
29 const unsigned char *e = s + n;
30 bool escaped = false;
31 bool spaced = false;
32 bool shell = false;
33
34 agxbuf b = {0};
35 if (qb) {
36 if (qb[0] == '$' && qb[1] == '\'' && qb[2] == 0)
37 shell = true;
38 agxbput(&b, qb);
39 }
40
41 char last = '\0';
42#define PUT(ch) \
43 do { \
44 last = (ch); \
45 agxbputc(&b, (ch)); \
46 } while (0)
47
48 while (s < e) {
49 int c = *s++;
50 if (gv_iscntrl(c) || !gv_isprint(c) || c == '\\') {
51 escaped = true;
52 PUT('\\');
53 switch (c) {
54 case CC_bel:
55 c = 'a';
56 break;
57 case '\b':
58 c = 'b';
59 break;
60 case '\f':
61 c = 'f';
62 break;
63 case '\n':
64 c = 'n';
65 break;
66 case '\r':
67 c = 'r';
68 break;
69 case '\t':
70 c = 't';
71 break;
72 case CC_vt:
73 c = 'v';
74 break;
75 case CC_esc:
76 c = 'E';
77 break;
78 case '\\':
79 break;
80 default:
81 PUT((char)('0' + ((c >> 6) & 07)));
82 PUT((char)('0' + ((c >> 3) & 07)));
83 c = '0' + (c & 07);
84 break;
85 }
86 } else if (qe && strchr(qe, c)) {
87 escaped = true;
88 PUT('\\');
89 } else if (!spaced &&
90 !escaped &&
91 (gv_isspace(c) ||
92 (shell &&
93 (strchr("\";~&|()<>[]*?", c) ||
94 (c == '#' && (last == '\0' || gv_isspace(last))
95 )
96 )
97 )
98 )
99 )
100 spaced = true;
101 PUT((char)c);
102 }
103#undef PUT
104 if (qb) {
105 if (!escaped) {
106 const size_t move_by = (size_t)(shell + !spaced);
107 if (move_by > 0) {
108 char *content = agxbdisown(&b);
109 agxbput(&b, content + move_by);
110 free(content);
111 }
112 }
113 if (qe && (escaped || spaced))
114 agxbput(&b, qe);
115 }
116 return agxbdisown(&b);
117}
118
119/*
120 * escape the usual suspects and quote chars in qs
121 */
122
123char *fmtesq(const char *as, const char *qs)
124{
125 return fmtquote(as, NULL, qs);
126}
127
128/*
129 * escape the usual suspects
130 */
131
132char *fmtesc(const char *as)
133{
134 return fmtquote(as, NULL, NULL);
135}
static agxbuf last
last message
Definition agerror.c:29
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:299
#define CC_bel
Definition ast.h:29
#define CC_vt
Definition ast.h:31
#define CC_esc
Definition ast.h:30
char * fmtesq(const char *as, const char *qs)
Definition fmtesc.c:123
char * fmtesc(const char *as)
Definition fmtesc.c:132
#define PUT(ch)
char * fmtquote(const char *as, const char *qb, const char *qe)
quote string as with qb...qe
Definition fmtesc.c:26
void free(void *)
node NULL
Definition grammar.y:149
replacements for ctype.h functions
static bool gv_iscntrl(int c)
Definition gv_ctype.h:33
static bool gv_isprint(int c)
Definition gv_ctype.h:47
static bool gv_isspace(int c)
Definition gv_ctype.h:55
Definition grammar.c:93