source: trunk/dll/literal.c@ 1844

Last change on this file since 1844 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
RevLine 
[117]1
2/***********************************************************************
3
4 $Id: literal.c 1673 2012-12-30 18:51:01Z gyoung $
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
[999]19 15 Mar 08 KOMH Fix wildcard for multiple dots
[1416]20 24 Apr 09 SHL Rework wildcard for clarity
[117]21
22***********************************************************************/
23
[907]24#include <stdlib.h>
25#include <string.h>
26#include <ctype.h>
27
[2]28#define INCL_OS2
29#define INCL_WIN
[907]30#define INCL_LONGLONG // dircnrs.h
[2]31
[1183]32#include "fm3dll.h"
[907]33#include "errutil.h" // Dos_Error...
[1160]34#include "literal.h"
[1183]35#include "wrappers.h" // xmalloc
[1039]36#include "fortify.h"
[1438]37#include "init.h" // Strings
[2]38
[351]39static PSZ pszSrcFile = __FILE__;
40
[551]41static INT index(const CHAR * s, const CHAR c);
[117]42
[1673]43/**
44 * Get index of char in string
[117]45 * @parm s string to search
46 * @parm c char to search for
47 * @return 0 relative index of c in s or -1
48 */
[2]49
[551]50static INT index(const CHAR * s, const CHAR c)
[117]51{
[551]52 CHAR *p;
[2]53
[551]54 p = strchr(s, c);
55 if (p == NULL || !*p)
56 return -1;
57 return (INT) (p - s);
[2]58}
59
[1673]60/**
61 * literal()
[409]62 * Translate a string with \ escape tokens to binary equivalent
[117]63 * Translates in place
64 *
[2]65 * 1. \x1b translates to CHAR(0x1b)
66 * 2. \27 translates to CHAR(27)
67 * 3. \" translates to "
68 * 4. \' translates to '
69 * 5. \\ translates to \
70 * 6. \r translates to carriage return
71 * 7. \n translates to linefeed
72 * 8. \b translates to backspace
73 * 9. \t translates to tab
74 * 10. \a translates to bell
75 * 11. \f translates to formfeed
76 *
77 * Synopsis
78 * *s = "this\x20is\32a test of \\MSC\\CSM\7"
79 * literal(s);
80 *
81 * ( s now equals "this is a test of \MSC\CSM")
[298]82 *
[409]83 * Return converted character count like strlen()
84 * Count does not include terminating nul
[2]85 */
86
87#define HEX "0123456789ABCDEF"
88#define DEC "0123456789"
89
[117]90UINT literal(PSZ pszBuf)
91{
[551]92 INT wpos;
93 INT iBuf;
94 UINT cBufBytes;
95 INT iBufSave;
96 PSZ pszOut;
97 PSZ pszWork;
98 CHAR wchar;
[2]99
[551]100 if (!pszBuf || !*pszBuf)
[2]101 return 0;
[117]102 cBufBytes = strlen(pszBuf) + 1;
[551]103 pszWork = pszOut = xmalloc(cBufBytes + 1, pszSrcFile, __LINE__);
[959]104 if (!pszWork)
105 return 0;
[2]106
[1673]107 iBuf = 0; // set index to first character
[551]108 while (pszBuf[iBuf]) {
109 switch (pszBuf[iBuf]) {
110 case '\\':
111 switch (pszBuf[iBuf + 1]) {
[1673]112 case 'x': // hexadecimal
[871]113 wchar = 0;
[1673]114 iBuf += 2; // get past "\x"
[871]115 if (index(HEX, (CHAR) toupper(pszBuf[iBuf])) != -1) {
116 iBufSave = iBuf;
117 while (((wpos = index(HEX, (CHAR) toupper(pszBuf[iBuf]))) != -1) &&
118 iBuf < iBufSave + 2) {
119 wchar = (CHAR) (wchar << 4) + (CHAR) wpos;
120 iBuf++;
121 }
122 }
123 else
[1673]124 wchar = 'x'; // just an x
[871]125 iBuf--;
126 *pszOut++ = wchar;
127 break;
[2]128
[1673]129 case '\\': // we want a "\"
[871]130 iBuf++;
131 *pszOut++ = '\\';
132 break;
[2]133
[1673]134 case 't': // tab CHAR
[871]135 iBuf++;
136 *pszOut++ = '\t';
137 break;
[2]138
[1673]139 case 'n': // new line
[871]140 iBuf++;
141 *pszOut++ = '\n';
142 break;
[2]143
[1673]144 case 'r': // carr return
[871]145 iBuf++;
146 *pszOut++ = '\r';
147 break;
[2]148
[1673]149 case 'b': // back space
[871]150 iBuf++;
151 *pszOut++ = '\b';
152 break;
[2]153
[1673]154 case 'f': // formfeed
[871]155 iBuf++;
156 *pszOut++ = '\x0c';
157 break;
[2]158
[1673]159 case 'a': // bell
[871]160 iBuf++;
161 *pszOut++ = '\07';
162 break;
[2]163
[1673]164 case '\'': // single quote
[871]165 iBuf++;
166 *pszOut++ = '\'';
167 break;
[2]168
[1673]169 case '\"': // double quote
[2]170
[871]171 iBuf++;
172 *pszOut++ = '\"';
173 break;
[757]174
[1673]175 default: // decimal
176 iBuf++; // get past "\"
[871]177 wchar = 0;
178 if (index(DEC, pszBuf[iBuf]) != -1) {
179 iBufSave = iBuf;
[1673]180 do { // cvt to binary
[871]181 wchar = (CHAR) (wchar * 10 + (pszBuf[iBuf++] - 48));
182 } while (index(DEC, pszBuf[iBuf]) != -1 && iBuf < iBufSave + 3);
183 iBuf--;
184 }
185 else
186 wchar = pszBuf[iBuf];
187 *pszOut++ = wchar;
188 break;
[757]189 } // switch
[551]190 break;
191
192 default:
193 *pszOut++ = pszBuf[iBuf];
194 break;
[757]195 } // switch
[551]196 iBuf++;
[757]197 } // while
[1673]198 *pszOut = 0; // Always terminate, even if not string
[2]199
[1673]200 cBufBytes = pszOut - pszWork; // Calc string length excluding terminator
201 memcpy(pszBuf, pszWork, cBufBytes + 1); // Overwrite including terminator
[1039]202 free(pszWork);
[2]203
[1673]204 return cBufBytes; // Return string length
[2]205}
206
[999]207/** Check wildcard match
[117]208 * @parm pszBuf Buffer to check
209 * @parm pszWildCard wildcard to match
[1416]210 * @parm fIgnorePathSep TRUE if match ignores path separators
[117]211 * @return TRUE if matched else FALSE
[1416]212 * @fixme need to rework to scan from right to left if not ignoring path separators
[117]213 */
[2]214
[1416]215BOOL wildcard(const PSZ pszBufIn, const PSZ pszWildCardIn,
216 const BOOL fIgnorePathSep)
[999]217{
[1416]218 PSZ pszBuf = pszBufIn;
219 PSZ pszWild = pszWildCardIn;
[999]220
[1416]221 while (*pszBuf && *pszWild) {
222 switch (*pszWild) {
[999]223 case '*' :
224 {
[1416]225 PSZ pszLook;
[999]226
227 // find next non-wild character in wildcard
[1416]228 while (*pszWild && ( *pszWild == '*' || *pszWild == '?'))
229 pszWild++;
[999]230
[1416]231 // if last char of wildcard is *, got match
232 if (!*pszWild)
[999]233 return TRUE;
234
[1416]235 pszLook = pszBuf;
236 while (*pszLook) {
237 // scan until match, eos or path separator (maybe)
238 while (*pszLook && toupper(*pszLook) != toupper(*pszWild) &&
239 (fIgnorePathSep || ( *pszLook != '/' && *pszLook != '\\')))
240 pszLook++;
[999]241
[1416]242 // If eos or path separator (maybe), stop scan
243 if (!*pszLook || (!fIgnorePathSep && (*pszLook == '/' || *pszLook == '\\')))
[999]244 break;
245
[1416]246 // Not ignoring path separators, match next path component
247 if (wildcard(pszLook, pszWild, fIgnorePathSep) == TRUE)
[999]248 return TRUE;
249
[1416]250 pszLook++;
251 } // while
[999]252
[1416]253 pszBuf = pszLook;
[999]254 break;
255 }
256
257 case '?' : // character substitution
[1416]258 pszWild++;
[999]259
[1416]260 if (fIgnorePathSep || (*pszBuf != '.' && *pszBuf != '/' && *pszBuf != '\\'))
261 pszBuf++; // skip (match) next character
[999]262 break;
263
264 default :
[1416]265 if (fIgnorePathSep || (*pszBuf != '/' && *pszBuf != '\\') ||
266 (*pszWild != '/' && *pszWild != '\\')) {
267 if (toupper( *pszBuf ) != toupper( *pszWild))
[999]268 return FALSE;
269 }
270
[1416]271 pszWild++;
272 pszBuf++;
[999]273 break;
[1416]274 } // switch
275 } // while
[999]276
[1416]277 if (!*pszBuf) {
278 // Skip trailing * and ?
279 while (*pszWild && (*pszWild == '?' || *pszWild == '*'))
280 pszWild++;
[999]281
[1416]282 if (!fIgnorePathSep) {
[999]283 // remove trailing .
[1416]284 while (*pszWild && *pszWild == '.')
285 pszWild++;
[999]286 }
287 }
288
[1416]289 return (*pszBuf == *pszWild);
[999]290}
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 {
[1438]326 sprintf(pchOut, "%sx%02x", PCSZ_BACKSLASH, (UCHAR)*pchIn);
[871]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.