source: trunk/dll/literal.c@ 1200

Last change on this file since 1200 was 1183, checked in by John Small, 17 years ago

Ticket 187: Draft 2: Move remaining function declarations

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.9 KB
Line 
1
2/***********************************************************************
3
4 $Id: literal.c 1183 2008-09-10 21:56:13Z jbs $
5
6 string quoting utilities
7 wildcarding utilities
8
9 Copyright (c) 1993-98 M. Kimes
10 Copyright (c) 2004, 2007 Steven H.Levine
11
12 Archive containers
13
14 01 Aug 04 SHL Rework fixup to avoid overflows
15 16 Jun 06 SHL liternal: comments
16 22 Jul 06 SHL Check more run time errors
17 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
18 16 Nov 07 SHL Report fixup buffer overflow
19 15 Mar 08 KOMH Fix wildcard for multiple dots
20
21***********************************************************************/
22
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26
27#define INCL_OS2
28#define INCL_WIN
29#define INCL_LONGLONG // dircnrs.h
30
31#include "fm3dll.h"
32#include "errutil.h" // Dos_Error...
33#include "literal.h"
34#include "wrappers.h" // xmalloc
35#include "fortify.h"
36
37static PSZ pszSrcFile = __FILE__;
38
39static INT index(const CHAR * s, const CHAR c);
40
41/* Get index of char in string
42 * @parm s string to search
43 * @parm c char to search for
44 * @return 0 relative index of c in s or -1
45 */
46
47static INT index(const CHAR * s, const CHAR c)
48{
49 CHAR *p;
50
51 p = strchr(s, c);
52 if (p == NULL || !*p)
53 return -1;
54 return (INT) (p - s);
55}
56
57/* literal()
58 * Translate a string with \ escape tokens to binary equivalent
59 * Translates in place
60 *
61 * 1. \x1b translates to CHAR(0x1b)
62 * 2. \27 translates to CHAR(27)
63 * 3. \" translates to "
64 * 4. \' translates to '
65 * 5. \\ translates to \
66 * 6. \r translates to carriage return
67 * 7. \n translates to linefeed
68 * 8. \b translates to backspace
69 * 9. \t translates to tab
70 * 10. \a translates to bell
71 * 11. \f translates to formfeed
72 *
73 * Synopsis
74 * *s = "this\x20is\32a test of \\MSC\\CSM\7"
75 * literal(s);
76 *
77 * ( s now equals "this is a test of \MSC\CSM")
78 *
79 * Return converted character count like strlen()
80 * Count does not include terminating nul
81 */
82
83#define HEX "0123456789ABCDEF"
84#define DEC "0123456789"
85
86UINT literal(PSZ pszBuf)
87{
88 INT wpos;
89 INT iBuf;
90 UINT cBufBytes;
91 INT iBufSave;
92 PSZ pszOut;
93 PSZ pszWork;
94 CHAR wchar;
95
96 if (!pszBuf || !*pszBuf)
97 return 0;
98 cBufBytes = strlen(pszBuf) + 1;
99 pszWork = pszOut = xmalloc(cBufBytes + 1, pszSrcFile, __LINE__);
100 if (!pszWork)
101 return 0;
102
103 iBuf = 0; /* set index to first character */
104 while (pszBuf[iBuf]) {
105 switch (pszBuf[iBuf]) {
106 case '\\':
107 switch (pszBuf[iBuf + 1]) {
108 case 'x': /* hexadecimal */
109 wchar = 0;
110 iBuf += 2; /* get past "\x" */
111 if (index(HEX, (CHAR) toupper(pszBuf[iBuf])) != -1) {
112 iBufSave = iBuf;
113 while (((wpos = index(HEX, (CHAR) toupper(pszBuf[iBuf]))) != -1) &&
114 iBuf < iBufSave + 2) {
115 wchar = (CHAR) (wchar << 4) + (CHAR) wpos;
116 iBuf++;
117 }
118 }
119 else
120 wchar = 'x'; /* just an x */
121 iBuf--;
122 *pszOut++ = wchar;
123 break;
124
125 case '\\': /* we want a "\" */
126 iBuf++;
127 *pszOut++ = '\\';
128 break;
129
130 case 't': /* tab CHAR */
131 iBuf++;
132 *pszOut++ = '\t';
133 break;
134
135 case 'n': /* new line */
136 iBuf++;
137 *pszOut++ = '\n';
138 break;
139
140 case 'r': /* carr return */
141 iBuf++;
142 *pszOut++ = '\r';
143 break;
144
145 case 'b': /* back space */
146 iBuf++;
147 *pszOut++ = '\b';
148 break;
149
150 case 'f': /* formfeed */
151 iBuf++;
152 *pszOut++ = '\x0c';
153 break;
154
155 case 'a': /* bell */
156 iBuf++;
157 *pszOut++ = '\07';
158 break;
159
160 case '\'': /* single quote */
161 iBuf++;
162 *pszOut++ = '\'';
163 break;
164
165 case '\"': /* double quote */
166
167 iBuf++;
168 *pszOut++ = '\"';
169 break;
170
171 default: /* decimal */
172 iBuf++; /* get past "\" */
173 wchar = 0;
174 if (index(DEC, pszBuf[iBuf]) != -1) {
175 iBufSave = iBuf;
176 do { /* cvt to binary */
177 wchar = (CHAR) (wchar * 10 + (pszBuf[iBuf++] - 48));
178 } while (index(DEC, pszBuf[iBuf]) != -1 && iBuf < iBufSave + 3);
179 iBuf--;
180 }
181 else
182 wchar = pszBuf[iBuf];
183 *pszOut++ = wchar;
184 break;
185 } // switch
186 break;
187
188 default:
189 *pszOut++ = pszBuf[iBuf];
190 break;
191 } // switch
192 iBuf++;
193 } // while
194 *pszOut = 0; /* Always terminate, even if not string */
195
196 cBufBytes = pszOut - pszWork; /* Calc string length excluding terminator */
197 memcpy(pszBuf, pszWork, cBufBytes + 1); /* Overwrite including terminator */
198 free(pszWork);
199
200 return cBufBytes; /* Return string length */
201}
202
203/** Check wildcard match
204 * @parm pszBuf Buffer to check
205 * @parm pszWildCard wildcard to match
206 * @parm fNotFileSpec TRUE if generic match else filespec match
207 * @return TRUE if matched else FALSE
208 */
209
210BOOL wildcard(const PSZ pszBuf, const PSZ pszWildCard,
211 const BOOL fNotFileSpec)
212{
213 PSZ fstr = pszBuf;
214 PSZ fcard = pszWildCard;
215
216 while (*fstr && *fcard) {
217 switch (*fcard) {
218 case '*' :
219 {
220 PSZ fstr1;
221
222 // find next non-wild character in wildcard
223 while (*fcard && ( *fcard == '*' || *fcard == '?'))
224 fcard++;
225
226 // if last char of wildcard is *, it matches
227 if (!*fcard)
228 return TRUE;
229
230 fstr1 = fstr;
231 while (*fstr1) {
232 // skip until partition, match, or eos
233 while (*fstr1 && toupper( *fstr1 ) != toupper( *fcard ) &&
234 (fNotFileSpec || ( *fstr1 != '/' && *fstr1 != '\\')))
235 fstr1++;
236
237 if (!*fstr1 || ( !fNotFileSpec && ( *fstr1 == '/' || *fstr1 == '\\')))
238 break;
239
240 if (wildcard( fstr1, fcard, fNotFileSpec ) == TRUE)
241 return TRUE;
242
243 fstr1++;
244 }
245
246 fstr = fstr1;
247 break;
248 }
249
250 case '?' : // character substitution
251 fcard++;
252
253 if (fNotFileSpec || ( *fstr != '.' && *fstr != '/' && *fstr != '\\'))
254 fstr++; // skip (match) next character
255 break;
256
257 default :
258 if (fNotFileSpec || (*fstr != '/' && *fstr != '\\') ||
259 (*fcard != '/' && *fcard != '\\')) {
260 if (toupper( *fstr ) != toupper( *fcard))
261 return FALSE;
262 }
263
264 fcard++;
265 fstr++;
266 break;
267 }
268 }
269
270 if (!*fstr) {
271 // remove trailing * and ?
272 while (*fcard && ( *fcard == '?' || *fcard == '*'))
273 fcard++;
274
275 if (!fNotFileSpec) {
276 // remove trailing .
277 while (*fcard && *fcard == '.')
278 fcard++;
279 }
280 }
281
282 return (*fstr == *fcard);
283}
284
285// fixup - quote literal character array
286
287PSZ fixup(const PCH pachIn, PSZ pszOutBuf, const UINT cBufBytes,
288 const UINT cInBytes)
289{
290 PCH pchIn = pachIn;
291 PCH pchOut = pszOutBuf;
292
293 // input is a character array, not a string - may not be null terminated
294 // cBufBytes is buffer size
295 if (pachIn) {
296 // 16 Nov 07 SHL fixme to optimize counting and speed
297 // Ensure room for null and possible \ escape
298 while (pchIn - pachIn < cInBytes) {
299 if (pchOut - pszOutBuf + 4 >= cBufBytes) {
300 *pchOut = 0;
301 Runtime_Error(pszSrcFile, __LINE__, "buffer too small for %s", pszOutBuf);
302 break;
303 }
304
305 if (!isprint(*pchIn)) {
306 if (*pchIn == '\r') {
307 *pchOut++ = '\\';
308 *pchOut++ = 'r';
309 }
310 else if (*pchIn == '\n') {
311 *pchOut++ = '\\';
312 *pchOut++ = 'n';
313 }
314 else if (*pchIn == '\b') {
315 *pchOut++ = '\\';
316 *pchOut++ = 'b';
317 }
318 else {
319 sprintf(pchOut, "\\x%02x", (UCHAR)*pchIn);
320 pchOut += 4;
321 }
322 pchIn++;
323 }
324 else if (*pchIn == '\\') {
325 *pchOut++ = '\\';
326 *pchOut++ = '\\';
327 pchIn++;
328 }
329 else
330 *pchOut++ = *pchIn++;
331 } // while
332
333 } // if pachIn
334 *pchOut = 0;
335 return pszOutBuf;
336}
337
338#pragma alloc_text(LITERAL,literal,index,fixup,wildcard)
339
Note: See TracBrowser for help on using the repository browser.