BRL-CAD
escape.c
Go to the documentation of this file.
1 /* E S C A P E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2011-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <string.h>
24 
25 #include "bu/log.h"
26 #include "bu/malloc.h"
27 #include "bu/str.h"
28 #include "bu/vls.h"
29 
30 static int
31 expand_expression(const char *expression, struct bu_vls *vp)
32 {
33  const char *ep = expression;
34  const char *cp;
35 
36  if (!expression)
37  return 0;
38 
39  /* skip circumflex */
40  if (ep[0] == '^')
41  ep++;
42 
43  bu_vls_extend(vp, 255); /* max ascii */
44  for (cp = ep; *cp != '\0'; cp++) {
45  bu_vls_strncat(vp, cp, 1);
46  }
47 
48  return (expression[0] == '^');
49 }
50 
51 
52 char *
53 bu_str_escape(const char *input, const char *expression, char *output, size_t size)
54 {
55  const char *c = NULL;
56  const char *esc = NULL;
57  struct bu_vls v = BU_VLS_INIT_ZERO;
58  char *chars = NULL;
59  char *incpy = NULL;
60  int negative = 0;
61  size_t need = 0;
62  size_t i = 0;
63 
64  if (UNLIKELY(!input))
65  return bu_strdup("");
66 
67  /* expand the expression to the list of chars it represents */
68  negative = expand_expression(expression, &v);
69  chars = bu_vls_strgrab(&v);
70 
71  /* first pass, calculate space requirement. this is done so we
72  * don't partially fill the output buffer before bombing because
73  * there might be a bomb-hook registered (and it's faster).
74  */
75  need = strlen(input);
76  for (c = input; *c != '\0'; c++) {
77  if (negative) {
78  for (esc = chars; *esc != '\0'; esc++) {
79  if (*c == *esc) {
80  break;
81  }
82  }
83  if (*esc == '\0') {
84  need++;
85  }
86  } else {
87  for (esc = chars; *esc != '\0'; esc++) {
88  if (*c == *esc) {
89  need++;
90  break;
91  }
92  }
93  }
94  }
95 
96  /* allocate dynamic space if output is NULL */
97  if (!output) {
98  size = need + 1;
99  output = (char *)bu_calloc(size, 1, "bu_str_escape");
100  } else {
101  /* copy input buffer if same or overlapping output buffer */
102  if (input == output
103  || (input < output && input+strlen(input)+1 > output)
104  || (input > output && output+need+1 > input))
105  {
106  incpy = bu_strdup(input);
107  }
108  }
109 
110  /* make sure we have enough space to work */
111  if (UNLIKELY(size < need + 1))
112  bu_bomb("INTERNAL ERROR: bu_str_escape() output buffer size is inadequate\n");
113 
114  /* second pass, scan through all input characters looking for
115  * characters to escape. write to the output buffer.
116  */
117  for (c = incpy ? incpy : input; *c != '\0'; c++) {
118  if (negative) {
119  for (esc = chars; *esc != '\0'; esc++) {
120  if (*c == *esc) {
121  break;
122  }
123  }
124  if (*esc == '\0') {
125  output[i++] = '\\';
126  }
127  } else {
128  for (esc = chars; *esc != '\0'; esc++) {
129  if (*c == *esc) {
130  output[i++] = '\\';
131  break;
132  }
133  }
134  }
135  output[i++] = *c;
136  }
137  /* always null-terminate */
138  output[i] = '\0';
139 
140  if (incpy)
141  bu_free(incpy, "bu_str_escape strdup");
142  bu_free(chars, "free strgrab");
143 
144  return output;
145 }
146 
147 
148 char *
149 bu_str_unescape(const char *input, char *output, size_t size)
150 {
151  const char *c = NULL;
152  char *incpy = NULL;
153  size_t need = 0;
154  size_t i = 0;
155 
156  if (UNLIKELY(!input))
157  return bu_strdup("");
158 
159  /* first pass, calculate space requirement. this is done so we
160  * don't partially fill the output buffer before bombing because
161  * there might be a bomb-hook registered (and it's faster).
162  */
163  need = strlen(input);
164  for (c = input; *c != '\0'; c++) {
165  if (*c == '\\') {
166  need--;
167 
168  /* skip the next char */
169  c++;
170  if (*c == '\0')
171  break;
172  }
173  }
174 
175  /* allocate dynamic space if output is NULL */
176  if (!output) {
177  size = need + 1;
178  output = (char *)bu_calloc(size, 1, "bu_str_unescape");
179  } else {
180  /* copy input buffer output buffer starts within the input
181  * buffer (output is "in front" of the input). it's okay if
182  * output is behind or equal because output is always going to
183  * be shorter or equal to input buffer.
184  */
185  if (input < output && input+strlen(input)+1 > output) {
186  incpy = bu_strdup(input);
187  }
188  }
189 
190  /* make sure we have enough space to work */
191  if (UNLIKELY(size < need + 1))
192  bu_bomb("INTERNAL ERROR: bu_str_unescape() output buffer size is inadequate\n");
193 
194  /* second pass, scan through all input characters looking for
195  * characters to unescape. write to the output buffer.
196  */
197  for (c = incpy ? incpy : input; *c != '\0'; c++) {
198  if (*c == '\\') {
199  c++; /* skip */
200  }
201  /* make sure last char wasn't a backslash */
202  if (*c != '\0')
203  output[i++] = *c;
204  else
205  break;
206  }
207  /* always null-terminate */
208  output[i] = '\0';
209 
210  if (incpy)
211  bu_free(incpy, "bu_str_unescape strdup");
212 
213  return output;
214 }
215 
216 
217 /*
218  * Local Variables:
219  * tab-width: 8
220  * mode: C
221  * indent-tabs-mode: t
222  * c-file-style: "stroustrup"
223  * End:
224  * ex: shiftwidth=4 tabstop=8
225  */
void bu_vls_strncat(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:390
Header file for the BRL-CAD common definitions.
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
char * bu_vls_strgrab(struct bu_vls *vp)
Definition: vls.c:290
char * bu_str_unescape(const char *input, char *output, size_t size)
Definition: escape.c:149
char * bu_str_escape(const char *input, const char *expression, char *output, size_t size)
Definition: escape.c:53
void bu_vls_extend(struct bu_vls *vp, size_t extra)
Definition: vls.c:136
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
Definition: vls.h:56
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
#define bu_strdup(s)
Definition: str.h:71
#define UNLIKELY(expression)
Definition: common.h:282