| [117] | 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
 | 
|---|
| [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
 | 
|---|
| [117] | 20 | 
 | 
|---|
 | 21 | ***********************************************************************/
 | 
|---|
 | 22 | 
 | 
|---|
| [907] | 23 | #include <stdlib.h>
 | 
|---|
 | 24 | #include <string.h>
 | 
|---|
 | 25 | #include <ctype.h>
 | 
|---|
 | 26 | 
 | 
|---|
| [2] | 27 | #define INCL_OS2
 | 
|---|
 | 28 | #define INCL_WIN
 | 
|---|
| [907] | 29 | #define INCL_LONGLONG                   // dircnrs.h
 | 
|---|
| [2] | 30 | 
 | 
|---|
| [1183] | 31 | #include "fm3dll.h"
 | 
|---|
| [907] | 32 | #include "errutil.h"                    // Dos_Error...
 | 
|---|
| [1160] | 33 | #include "literal.h"
 | 
|---|
| [1183] | 34 | #include "wrappers.h"                   // xmalloc
 | 
|---|
| [1039] | 35 | #include "fortify.h"
 | 
|---|
| [2] | 36 | 
 | 
|---|
| [351] | 37 | static PSZ pszSrcFile = __FILE__;
 | 
|---|
 | 38 | 
 | 
|---|
| [551] | 39 | static INT index(const CHAR * s, const CHAR c);
 | 
|---|
| [117] | 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 |  */
 | 
|---|
| [2] | 46 | 
 | 
|---|
| [551] | 47 | static INT index(const CHAR * s, const CHAR c)
 | 
|---|
| [117] | 48 | {
 | 
|---|
| [551] | 49 |   CHAR *p;
 | 
|---|
| [2] | 50 | 
 | 
|---|
| [551] | 51 |   p = strchr(s, c);
 | 
|---|
 | 52 |   if (p == NULL || !*p)
 | 
|---|
 | 53 |     return -1;
 | 
|---|
 | 54 |   return (INT) (p - s);
 | 
|---|
| [2] | 55 | }
 | 
|---|
 | 56 | 
 | 
|---|
| [409] | 57 | /* literal()
 | 
|---|
 | 58 |  * Translate a string with \ escape tokens to binary equivalent
 | 
|---|
| [117] | 59 |  * Translates in place
 | 
|---|
 | 60 |  *
 | 
|---|
| [2] | 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")
 | 
|---|
| [298] | 78 |  *
 | 
|---|
| [409] | 79 |  * Return converted character count like strlen()
 | 
|---|
 | 80 |  * Count does not include terminating nul
 | 
|---|
| [2] | 81 |  */
 | 
|---|
 | 82 | 
 | 
|---|
 | 83 | #define HEX "0123456789ABCDEF"
 | 
|---|
 | 84 | #define DEC "0123456789"
 | 
|---|
 | 85 | 
 | 
|---|
| [117] | 86 | UINT literal(PSZ pszBuf)
 | 
|---|
 | 87 | {
 | 
|---|
| [551] | 88 |   INT wpos;
 | 
|---|
 | 89 |   INT iBuf;
 | 
|---|
 | 90 |   UINT cBufBytes;
 | 
|---|
 | 91 |   INT iBufSave;
 | 
|---|
 | 92 |   PSZ pszOut;
 | 
|---|
 | 93 |   PSZ pszWork;
 | 
|---|
 | 94 |   CHAR wchar;
 | 
|---|
| [2] | 95 | 
 | 
|---|
| [551] | 96 |   if (!pszBuf || !*pszBuf)
 | 
|---|
| [2] | 97 |     return 0;
 | 
|---|
| [117] | 98 |   cBufBytes = strlen(pszBuf) + 1;
 | 
|---|
| [551] | 99 |   pszWork = pszOut = xmalloc(cBufBytes + 1, pszSrcFile, __LINE__);
 | 
|---|
| [959] | 100 |   if (!pszWork)
 | 
|---|
 | 101 |     return 0;
 | 
|---|
| [2] | 102 | 
 | 
|---|
| [757] | 103 |   iBuf = 0;                                /* set index to first character */
 | 
|---|
| [551] | 104 |   while (pszBuf[iBuf]) {
 | 
|---|
 | 105 |     switch (pszBuf[iBuf]) {
 | 
|---|
 | 106 |     case '\\':
 | 
|---|
 | 107 |       switch (pszBuf[iBuf + 1]) {
 | 
|---|
| [757] | 108 |       case 'x':                        /* hexadecimal */
 | 
|---|
| [871] | 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;
 | 
|---|
| [2] | 124 | 
 | 
|---|
| [757] | 125 |       case '\\':                        /* we want a "\" */
 | 
|---|
| [871] | 126 |         iBuf++;
 | 
|---|
 | 127 |         *pszOut++ = '\\';
 | 
|---|
 | 128 |         break;
 | 
|---|
| [2] | 129 | 
 | 
|---|
| [757] | 130 |       case 't':                        /* tab CHAR */
 | 
|---|
| [871] | 131 |         iBuf++;
 | 
|---|
 | 132 |         *pszOut++ = '\t';
 | 
|---|
 | 133 |         break;
 | 
|---|
| [2] | 134 | 
 | 
|---|
| [757] | 135 |       case 'n':                        /* new line */
 | 
|---|
| [871] | 136 |         iBuf++;
 | 
|---|
 | 137 |         *pszOut++ = '\n';
 | 
|---|
 | 138 |         break;
 | 
|---|
| [2] | 139 | 
 | 
|---|
| [757] | 140 |       case 'r':                        /* carr return */
 | 
|---|
| [871] | 141 |         iBuf++;
 | 
|---|
 | 142 |         *pszOut++ = '\r';
 | 
|---|
 | 143 |         break;
 | 
|---|
| [2] | 144 | 
 | 
|---|
| [757] | 145 |       case 'b':                        /* back space */
 | 
|---|
| [871] | 146 |         iBuf++;
 | 
|---|
 | 147 |         *pszOut++ = '\b';
 | 
|---|
 | 148 |         break;
 | 
|---|
| [2] | 149 | 
 | 
|---|
| [757] | 150 |       case 'f':                        /* formfeed */
 | 
|---|
| [871] | 151 |         iBuf++;
 | 
|---|
 | 152 |         *pszOut++ = '\x0c';
 | 
|---|
 | 153 |         break;
 | 
|---|
| [2] | 154 | 
 | 
|---|
| [757] | 155 |       case 'a':                        /* bell */
 | 
|---|
| [871] | 156 |         iBuf++;
 | 
|---|
 | 157 |         *pszOut++ = '\07';
 | 
|---|
 | 158 |         break;
 | 
|---|
| [2] | 159 | 
 | 
|---|
| [757] | 160 |       case '\'':                        /* single quote */
 | 
|---|
| [871] | 161 |         iBuf++;
 | 
|---|
 | 162 |         *pszOut++ = '\'';
 | 
|---|
 | 163 |         break;
 | 
|---|
| [2] | 164 | 
 | 
|---|
| [757] | 165 |       case '\"':                        /* double quote */
 | 
|---|
| [2] | 166 | 
 | 
|---|
| [871] | 167 |         iBuf++;
 | 
|---|
 | 168 |         *pszOut++ = '\"';
 | 
|---|
 | 169 |         break;
 | 
|---|
| [757] | 170 | 
 | 
|---|
 | 171 |       default:                                /* decimal */
 | 
|---|
| [871] | 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;
 | 
|---|
| [757] | 185 |       }                                        // switch
 | 
|---|
| [551] | 186 |       break;
 | 
|---|
 | 187 | 
 | 
|---|
 | 188 |     default:
 | 
|---|
 | 189 |       *pszOut++ = pszBuf[iBuf];
 | 
|---|
 | 190 |       break;
 | 
|---|
| [757] | 191 |     }                                        // switch
 | 
|---|
| [551] | 192 |     iBuf++;
 | 
|---|
| [757] | 193 |   }                                        // while
 | 
|---|
 | 194 |   *pszOut = 0;                                /* Always terminate, even if not string */
 | 
|---|
| [2] | 195 | 
 | 
|---|
| [757] | 196 |   cBufBytes = pszOut - pszWork;                /* Calc string length excluding terminator */
 | 
|---|
 | 197 |   memcpy(pszBuf, pszWork, cBufBytes + 1);        /* Overwrite including terminator */
 | 
|---|
| [1039] | 198 |   free(pszWork);
 | 
|---|
| [2] | 199 | 
 | 
|---|
| [757] | 200 |   return cBufBytes;                        /* Return string length */
 | 
|---|
| [2] | 201 | }
 | 
|---|
 | 202 | 
 | 
|---|
| [999] | 203 | /** Check wildcard match
 | 
|---|
| [117] | 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 |  */
 | 
|---|
| [2] | 209 | 
 | 
|---|
| [551] | 210 | BOOL wildcard(const PSZ pszBuf, const PSZ pszWildCard,
 | 
|---|
| [999] | 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 | 
 | 
|---|
| [117] | 285 | // fixup - quote literal character array
 | 
|---|
| [2] | 286 | 
 | 
|---|
| [551] | 287 | PSZ fixup(const PCH pachIn, PSZ pszOutBuf, const UINT cBufBytes,
 | 
|---|
| [871] | 288 |           const UINT cInBytes)
 | 
|---|
| [117] | 289 | {
 | 
|---|
| [551] | 290 |   PCH pchIn = pachIn;
 | 
|---|
 | 291 |   PCH pchOut = pszOutBuf;
 | 
|---|
| [2] | 292 | 
 | 
|---|
| [117] | 293 |   // input is a character array, not a string - may not be null terminated
 | 
|---|
 | 294 |   // cBufBytes is buffer size
 | 
|---|
 | 295 |   if (pachIn) {
 | 
|---|
| [871] | 296 |     // 16 Nov 07 SHL fixme to optimize counting and speed
 | 
|---|
| [117] | 297 |     // Ensure room for null and possible \ escape
 | 
|---|
| [871] | 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 | 
 | 
|---|
| [551] | 305 |       if (!isprint(*pchIn)) {
 | 
|---|
| [871] | 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++;
 | 
|---|
| [2] | 323 |       }
 | 
|---|
| [551] | 324 |       else if (*pchIn == '\\') {
 | 
|---|
| [871] | 325 |         *pchOut++ = '\\';
 | 
|---|
 | 326 |         *pchOut++ = '\\';
 | 
|---|
 | 327 |         pchIn++;
 | 
|---|
| [2] | 328 |       }
 | 
|---|
| [117] | 329 |       else
 | 
|---|
| [871] | 330 |         *pchOut++ = *pchIn++;
 | 
|---|
 | 331 |     } // while
 | 
|---|
 | 332 | 
 | 
|---|
 | 333 |   } // if pachIn
 | 
|---|
| [117] | 334 |   *pchOut = 0;
 | 
|---|
 | 335 |   return pszOutBuf;
 | 
|---|
| [2] | 336 | }
 | 
|---|
| [795] | 337 | 
 | 
|---|
| [834] | 338 | #pragma alloc_text(LITERAL,literal,index,fixup,wildcard)
 | 
|---|
| [795] | 339 | 
 | 
|---|