source: trunk/dll/literal.c@ 871

Last change on this file since 871 was 871, checked in by Steven Levine, 18 years ago

Correct hex edit buffer sizing to avoid data loss
Detect and report overflows in fixup()

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