Graphviz 14.1.2~dev.20260123.1158
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 "config.h"
19
20#include <ast/ast.h>
21#include <stdbool.h>
22#include <stdlib.h>
23#include <string.h>
24#include <util/agxbuf.h>
25#include <util/gv_ctype.h>
26
28char *fmtquote(const char *as, const char *qb, const char *qe) {
29 const size_t n = strlen(as);
30 const unsigned char *s = (const unsigned char *) as;
31 const unsigned char *e = s + n;
32 bool escaped = false;
33 bool spaced = false;
34 bool shell = false;
35
36 agxbuf b = {0};
37 if (qb) {
38 if (qb[0] == '$' && qb[1] == '\'' && qb[2] == 0)
39 shell = true;
40 agxbput(&b, qb);
41 }
42
43 char last = '\0';
44#define PUT(ch) \
45 do { \
46 last = (ch); \
47 agxbputc(&b, (ch)); \
48 } while (0)
49
50 while (s < e) {
51 int c = *s++;
52 if (gv_iscntrl(c) || !gv_isprint(c) || c == '\\') {
53 escaped = true;
54 PUT('\\');
55 switch (c) {
56 case CC_bel:
57 c = 'a';
58 break;
59 case '\b':
60 c = 'b';
61 break;
62 case '\f':
63 c = 'f';
64 break;
65 case '\n':
66 c = 'n';
67 break;
68 case '\r':
69 c = 'r';
70 break;
71 case '\t':
72 c = 't';
73 break;
74 case CC_vt:
75 c = 'v';
76 break;
77 case CC_esc:
78 c = 'E';
79 break;
80 case '\\':
81 break;
82 default:
83 PUT((char)('0' + ((c >> 6) & 07)));
84 PUT((char)('0' + ((c >> 3) & 07)));
85 c = '0' + (c & 07);
86 break;
87 }
88 } else if (qe && strchr(qe, c)) {
89 escaped = true;
90 PUT('\\');
91 } else if (!spaced &&
92 !escaped &&
93 (gv_isspace(c) ||
94 (shell &&
95 (strchr("\";~&|()<>[]*?", c) ||
96 (c == '#' && (last == '\0' || gv_isspace(last))
97 )
98 )
99 )
100 )
101 )
102 spaced = true;
103 PUT((char)c);
104 }
105#undef PUT
106 if (qb) {
107 if (!escaped) {
108 const size_t move_by = (size_t)(shell + !spaced);
109 if (move_by > 0) {
110 char *content = agxbdisown(&b);
111 agxbput(&b, content + move_by);
112 free(content);
113 }
114 }
115 if (qe && (escaped || spaced))
116 agxbput(&b, qe);
117 }
118 return agxbdisown(&b);
119}
120
121/*
122 * escape the usual suspects and quote chars in qs
123 */
124
125char *fmtesq(const char *as, const char *qs)
126{
127 return fmtquote(as, NULL, qs);
128}
129
130/*
131 * escape the usual suspects
132 */
133
134char *fmtesc(const char *as)
135{
136 return fmtquote(as, NULL, NULL);
137}
static agxbuf last
last message
Definition agerror.c:31
Dynamically expanding string buffers.
static char * agxbdisown(agxbuf *xb)
Definition agxbuf.h:345
#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:125
char * fmtesc(const char *as)
Definition fmtesc.c:134
#define PUT(ch)
char * fmtquote(const char *as, const char *qb, const char *qe)
quote string as with qb...qe
Definition fmtesc.c:28
void free(void *)
node NULL
Definition grammar.y:181
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
agxbput(xb, staging)
Definition grammar.c:90