| 1 | |
| 2 | /* |
| 3 | * Copyright © 2001 Novell, Inc. All Rights Reserved. |
| 4 | * |
| 5 | * You may distribute under the terms of either the GNU General Public |
| 6 | * License or the Artistic License, as specified in the README file. |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | /* |
| 11 | * FILENAME : NWUtil.c |
| 12 | * DESCRIPTION : Utility functions for NetWare implementation of Perl. |
| 13 | * Author : HYAK |
| 14 | * Date : Januray 2001. |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | |
| 19 | |
| 20 | #include "stdio.h" |
| 21 | #include "string.h" |
| 22 | |
| 23 | #include <nwdsdefs.h> // For "MAX_DN_BYTES" |
| 24 | #include <malloc.h> // For "malloc" and "free" |
| 25 | #include <stdlib.h> // For "getenv" |
| 26 | #include <ctype.h> // For "isspace" |
| 27 | |
| 28 | #include <process.h> |
| 29 | #include <unistd.h> |
| 30 | #include <errno.h> |
| 31 | #include <nwerrno.h> |
| 32 | |
| 33 | #include <nwlocale.h> |
| 34 | #include <nwadv.h> |
| 35 | |
| 36 | #include "nwutil.h" |
| 37 | |
| 38 | |
| 39 | #define TRUE 1 |
| 40 | #define FALSE 0 |
| 41 | |
| 42 | |
| 43 | /** |
| 44 | Global variables used for better token parsing. When these were absent, |
| 45 | token parsing was not correct when there were more number of arguments passed. |
| 46 | These are used in fnCommandLineParser, fnSkipToken and fnScanToken to get/return |
| 47 | the correct and updated pointer to the command line string. |
| 48 | **/ |
| 49 | char *s1 = NULL; // Used in fnScanToken. |
| 50 | char *s2 = NULL; // Used in fnSkipToken. |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
| 55 | /*============================================================================================ |
| 56 | |
| 57 | Function : fnSkipWhite |
| 58 | |
| 59 | Description : This function skips the white space characters in the given string and |
| 60 | returns the resultant value. |
| 61 | |
| 62 | Parameters : s (IN) - Input string. |
| 63 | |
| 64 | Returns : String. |
| 65 | |
| 66 | ==============================================================================================*/ |
| 67 | |
| 68 | char *fnSkipWhite(char *s) |
| 69 | { |
| 70 | while (isspace(*s)) |
| 71 | s++; |
| 72 | return s; |
| 73 | } |
| 74 | |
| 75 | |
| 76 | |
| 77 | /*============================================================================================ |
| 78 | |
| 79 | Function : fnNwGetEnvironmentStr |
| 80 | |
| 81 | Description : This function returns the NetWare environment string if available, |
| 82 | otherwise returns the supplied default value |
| 83 | |
| 84 | Parameters : name (IN) - To hold the NetWare environment value. |
| 85 | defaultvalue (IN) - Default value. |
| 86 | |
| 87 | |
| 88 | Returns : String. |
| 89 | |
| 90 | ==============================================================================================*/ |
| 91 | |
| 92 | char *fnNwGetEnvironmentStr(char *name, char *defaultvalue) |
| 93 | { |
| 94 | char* ret = getenv(name); |
| 95 | if (ret == NULL) |
| 96 | ret = defaultvalue; |
| 97 | return ret; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | |
| 102 | /*============================================================================================ |
| 103 | |
| 104 | Function : fnCommandLineParser |
| 105 | |
| 106 | Description : This function parses the command line into argc/argv style of |
| 107 | Number of params and array of params. |
| 108 | |
| 109 | Parameters : pclp (IN) - CommandLine structure. |
| 110 | commandLine (IN) - CommandLine String. |
| 111 | preserverQuotes (IN) - Indicates whether to preserve/copy the quotes or not. |
| 112 | |
| 113 | Returns : Nothing. |
| 114 | |
| 115 | ==============================================================================================*/ |
| 116 | |
| 117 | void fnCommandLineParser(PCOMMANDLINEPARSER pclp, char * commandLine, BOOL preserveQuotes) |
| 118 | { |
| 119 | char *buffer = NULL; |
| 120 | |
| 121 | int index = 0; |
| 122 | int do_delete = 1; |
| 123 | int i=0, j=0, k=0; |
| 124 | |
| 125 | |
| 126 | // +1 makes room for the terminating NULL |
| 127 | buffer = (char *) malloc((strlen(commandLine) + 1) * sizeof(char)); |
| 128 | if (buffer == NULL) |
| 129 | { |
| 130 | pclp->m_isValid = FALSE; |
| 131 | return; |
| 132 | } |
| 133 | |
| 134 | if (preserveQuotes) |
| 135 | { |
| 136 | // No I/O redirection nor quote processing if preserveQuotes |
| 137 | |
| 138 | char *s = NULL; |
| 139 | char *sSkippedToken = NULL; |
| 140 | |
| 141 | |
| 142 | strcpy(buffer, commandLine); |
| 143 | s = buffer; |
| 144 | s = fnSkipWhite(s); // Skip white spaces. |
| 145 | |
| 146 | s2 = s; // Update the global pointer. |
| 147 | |
| 148 | |
| 149 | pclp->sSkippedToken = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 150 | if(pclp->sSkippedToken == NULL) |
| 151 | { |
| 152 | pclp->m_isValid = FALSE; |
| 153 | return; |
| 154 | } |
| 155 | |
| 156 | while (*s && pclp->m_isValid) |
| 157 | { |
| 158 | /**** |
| 159 | // Commented since only one time malloc and free is enough as is done outside this while loop. |
| 160 | // It is not required to do them everytime the execution comes into this while loop. |
| 161 | // Still retained here. Remove this once things are proved to be working fine to a good confident level, |
| 162 | |
| 163 | if(pclp->sSkippedToken) |
| 164 | { |
| 165 | free(pclp->sSkippedToken); |
| 166 | pclp->sSkippedToken = NULL; |
| 167 | } |
| 168 | |
| 169 | if(pclp->sSkippedToken == NULL) |
| 170 | { |
| 171 | pclp->sSkippedToken = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 172 | if(pclp->sSkippedToken == NULL) |
| 173 | { |
| 174 | pclp->m_isValid = FALSE; |
| 175 | return; |
| 176 | } |
| 177 | } |
| 178 | ****/ |
| 179 | |
| 180 | // Empty the string. |
| 181 | strncpy(pclp->sSkippedToken, "", (MAX_DN_BYTES * sizeof(char))); |
| 182 | |
| 183 | // s is advanced by fnSkipToken |
| 184 | pclp->sSkippedToken = fnSkipToken(s, pclp->sSkippedToken); // Collect the next command-line argument. |
| 185 | |
| 186 | s2 = fnSkipWhite(s2); // s2 is already updated by fnSkipToken. |
| 187 | s = s2; // Update the local pointer too. |
| 188 | |
| 189 | fnAppendArgument(pclp, pclp->sSkippedToken); // Append the argument into an array. |
| 190 | } |
| 191 | |
| 192 | if(pclp->sSkippedToken) |
| 193 | { |
| 194 | free(pclp->sSkippedToken); |
| 195 | pclp->sSkippedToken = NULL; |
| 196 | } |
| 197 | } |
| 198 | else |
| 199 | { |
| 200 | char *s = NULL; |
| 201 | |
| 202 | strcpy(buffer, commandLine); |
| 203 | s = buffer; |
| 204 | s = fnSkipWhite(s); |
| 205 | |
| 206 | s1 = s; // Update the global pointer. |
| 207 | |
| 208 | while (*s && pclp->m_isValid) |
| 209 | { |
| 210 | // s is advanced by fnScanToken |
| 211 | // Check for I/O redirection here, *outside* of |
| 212 | // fnScanToken(), so that quote-protected angle |
| 213 | // brackets do NOT cause redirection. |
| 214 | if (*s == '<') |
| 215 | { |
| 216 | s = fnSkipWhite(s+1); // get stdin redirection |
| 217 | |
| 218 | if(pclp->m_redirInName) |
| 219 | { |
| 220 | free(pclp->m_redirInName); |
| 221 | pclp->m_redirInName = NULL; |
| 222 | } |
| 223 | |
| 224 | if(pclp->m_redirInName == NULL) |
| 225 | { |
| 226 | pclp->m_redirInName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 227 | if(pclp->m_redirInName == NULL) |
| 228 | { |
| 229 | pclp->m_isValid = FALSE; |
| 230 | return; |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | // Collect the next command-line argument. |
| 235 | pclp->m_redirInName = fnScanToken(s, pclp->m_redirInName); |
| 236 | |
| 237 | s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. |
| 238 | s = s1; // Update the local pointer too. |
| 239 | } |
| 240 | else if (*s == '>') |
| 241 | { |
| 242 | s = fnSkipWhite(s+1); //get stdout redirection |
| 243 | |
| 244 | if(pclp->m_redirOutName) |
| 245 | { |
| 246 | free(pclp->m_redirOutName); |
| 247 | pclp->m_redirOutName = NULL; |
| 248 | } |
| 249 | |
| 250 | if(pclp->m_redirOutName == NULL) |
| 251 | { |
| 252 | pclp->m_redirOutName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 253 | if(pclp->m_redirOutName == NULL) |
| 254 | { |
| 255 | pclp->m_isValid = FALSE; |
| 256 | return; |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | // Collect the next command-line argument. |
| 261 | pclp->m_redirOutName = fnScanToken(s, pclp->m_redirOutName); |
| 262 | |
| 263 | s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. |
| 264 | s = s1; // Update the local pointer too. |
| 265 | } |
| 266 | else if (*s == '2' && s[1] == '>') |
| 267 | { |
| 268 | s = fnSkipWhite(s+2); // get stderr redirection |
| 269 | |
| 270 | if(pclp->m_redirErrName) |
| 271 | { |
| 272 | free(pclp->m_redirErrName); |
| 273 | pclp->m_redirErrName = NULL; |
| 274 | } |
| 275 | |
| 276 | if(pclp->m_redirErrName == NULL) |
| 277 | { |
| 278 | pclp->m_redirErrName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 279 | if(pclp->m_redirErrName == NULL) |
| 280 | { |
| 281 | pclp->m_isValid = FALSE; |
| 282 | return; |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | // Collect the next command-line argument. |
| 287 | pclp->m_redirErrName = fnScanToken(s, pclp->m_redirErrName); |
| 288 | |
| 289 | s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. |
| 290 | s = s1; // Update the local pointer too. |
| 291 | } |
| 292 | else if (*s == '&' && s[1] == '>') |
| 293 | { |
| 294 | s = fnSkipWhite(s+2); // get stdout+stderr redirection |
| 295 | |
| 296 | if(pclp->m_redirBothName) |
| 297 | { |
| 298 | free(pclp->m_redirBothName); |
| 299 | pclp->m_redirBothName = NULL; |
| 300 | } |
| 301 | |
| 302 | if(pclp->m_redirBothName == NULL) |
| 303 | { |
| 304 | pclp->m_redirBothName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 305 | if(pclp->m_redirBothName == NULL) |
| 306 | { |
| 307 | pclp->m_isValid = FALSE; |
| 308 | return; |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | // Collect the next command-line argument. |
| 313 | pclp->m_redirBothName = fnScanToken(s, pclp->m_redirBothName); |
| 314 | |
| 315 | s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. |
| 316 | s = s1; // Update the local pointer too. |
| 317 | } |
| 318 | else |
| 319 | { |
| 320 | if(pclp->nextarg) |
| 321 | { |
| 322 | free(pclp->nextarg); |
| 323 | pclp->nextarg = NULL; |
| 324 | } |
| 325 | |
| 326 | if(pclp->nextarg == NULL) |
| 327 | { |
| 328 | pclp->nextarg = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 329 | if(pclp->nextarg == NULL) |
| 330 | { |
| 331 | pclp->m_isValid = FALSE; |
| 332 | return; |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | // Collect the next command-line argument. |
| 337 | pclp->nextarg = fnScanToken(s, pclp->nextarg); |
| 338 | |
| 339 | s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. |
| 340 | s = s1; // Update the local pointer too. |
| 341 | |
| 342 | // Append the next command-line argument into an array. |
| 343 | fnAppendArgument(pclp, pclp->nextarg); |
| 344 | } |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | |
| 349 | // The -{ option, the --noscreen option, the --autodestroy option, if present, |
| 350 | // are processed now and removed from the argument vector. |
| 351 | for(index=0; index < pclp->m_argc; ) |
| 352 | { |
| 353 | // "-q" is replaced by "-{", because of clash with GetOpt - sgp - 7th Nov 2000 |
| 354 | // Copied from NDK build - Jan 5th 2001 |
| 355 | if (strncmp(pclp->m_argv[index], (char *)"-{", 2) == 0) |
| 356 | { |
| 357 | // found a -q option; grab the semaphore number |
| 358 | sscanf(pclp->m_argv[index], (char *)"-{%x", &pclp->m_qSemaphore); |
| 359 | fnDeleteArgument(pclp, index); // Delete the argument from the list. |
| 360 | } |
| 361 | else if (strcmp(pclp->m_argv[index], (char *)"--noscreen") == 0) |
| 362 | { |
| 363 | // found a --noscreen option |
| 364 | pclp->m_noScreen = 1; |
| 365 | fnDeleteArgument(pclp, index); |
| 366 | } |
| 367 | else if (strcmp(pclp->m_argv[index], (char *)"--autodestroy") == 0) |
| 368 | { |
| 369 | // found a --autodestroy option - create a screen but close automatically |
| 370 | pclp->m_AutoDestroy = 1; |
| 371 | fnDeleteArgument(pclp, index); |
| 372 | } |
| 373 | else |
| 374 | index++; |
| 375 | } |
| 376 | |
| 377 | // pclp->m_isValid is TRUE if there are more than 2 command line parameters OR |
| 378 | // if there is only one command and if it is the comman PERL. |
| 379 | pclp->m_isValid = ((pclp->m_argc >= 2) || ((pclp->m_argc > 0) && (stricmp(pclp->m_argv[0], LOAD_COMMAND) != 0))); |
| 380 | |
| 381 | if(buffer) |
| 382 | { |
| 383 | free(buffer); |
| 384 | buffer = NULL; |
| 385 | } |
| 386 | |
| 387 | return; |
| 388 | } |
| 389 | |
| 390 | |
| 391 | |
| 392 | /*============================================================================================ |
| 393 | |
| 394 | Function : fnAppendArgument |
| 395 | |
| 396 | Description : This function appends the arguments into a list. |
| 397 | |
| 398 | Parameters : pclp (IN) - CommandLine structure. |
| 399 | new_arg (IN) - The new argument to be appended. |
| 400 | |
| 401 | Returns : Nothing. |
| 402 | |
| 403 | ==============================================================================================*/ |
| 404 | |
| 405 | void fnAppendArgument(PCOMMANDLINEPARSER pclp, char *new_arg) |
| 406 | { |
| 407 | char **new_argv = pclp->new_argv; |
| 408 | |
| 409 | int new_argv_len = pclp->m_argv_len*2; |
| 410 | int i = 0, j = 0; |
| 411 | |
| 412 | |
| 413 | // Lengthen the argument vector if there's not room for another. |
| 414 | // Testing for 'm_argc+2' rather than 'm_argc+1' in the test guarantees |
| 415 | // that there'll always be a NULL terminator at the end of argv. |
| 416 | if ((pclp->m_argc + 2) > pclp->m_argv_len) |
| 417 | { |
| 418 | new_argv = (char **) malloc(new_argv_len * sizeof(char*)); // get a longer arg-vector |
| 419 | if (new_argv == NULL) |
| 420 | { |
| 421 | pclp->m_isValid = FALSE; |
| 422 | return; |
| 423 | } |
| 424 | for(i=0; i<new_argv_len; i++) |
| 425 | { |
| 426 | new_argv[i] = (char *) malloc(MAX_DN_BYTES * sizeof(char)); |
| 427 | if (new_argv[i] == NULL) |
| 428 | { |
| 429 | for(j=0; j<i; j++) |
| 430 | { |
| 431 | if(new_argv[j]) |
| 432 | { |
| 433 | free(new_argv[j]); |
| 434 | new_argv[j] = NULL; |
| 435 | } |
| 436 | } |
| 437 | if(new_argv) |
| 438 | { |
| 439 | free(new_argv); |
| 440 | new_argv = NULL; |
| 441 | } |
| 442 | |
| 443 | pclp->m_isValid = FALSE; |
| 444 | return; |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | for (i=0; i<pclp->m_argc; i++) |
| 449 | strcpy(new_argv[i], pclp->m_argv[i]); // copy old arg strings |
| 450 | |
| 451 | for(i=0; i<(pclp->m_argv_len); i++) |
| 452 | { |
| 453 | if(pclp->m_argv[i]) |
| 454 | { |
| 455 | free(pclp->m_argv[i]); |
| 456 | pclp->m_argv[i] = NULL; |
| 457 | } |
| 458 | } |
| 459 | if (pclp->m_argv != NULL) |
| 460 | { |
| 461 | free(pclp->m_argv); |
| 462 | pclp->m_argv = NULL; |
| 463 | } |
| 464 | |
| 465 | |
| 466 | pclp->m_argv = new_argv; |
| 467 | pclp->m_argv_len = new_argv_len; |
| 468 | |
| 469 | } |
| 470 | |
| 471 | // Once m_argv is guaranteed long enough, appending the argument is a direct job. |
| 472 | strcpy(pclp->m_argv[pclp->m_argc], new_arg); // Appended the new argument. |
| 473 | pclp->m_argc++; // Increment the number of parameters appended. |
| 474 | |
| 475 | // The char array is emptied for all elements upto the end so that there are no |
| 476 | // junk characters. If this is not done, then the issue is like this: |
| 477 | // - Simple perl command like "perl" on the system console works fine for the first time. |
| 478 | // - When "perl" is executed the second time, a new blank screen should come up |
| 479 | // which allows for editing also. This was not consistently working well. |
| 480 | // More so when the command was like, "perl ", that is the name "perl" followed |
| 481 | // by a few blank spaces, it used to give error in opening file: |
| 482 | // "unable to open the file" since the filename would have some junk characters. |
| 483 | // |
| 484 | // These issues are fixed through the code below. |
| 485 | for(i=pclp->m_argc; i<pclp->m_argv_len; i++) |
| 486 | strncpy(pclp->m_argv[i], "", (MAX_DN_BYTES * sizeof(char))); // MAX_DN_BYTES is the size of pclp->m_argv[]. |
| 487 | |
| 488 | |
| 489 | // Fix for empty command line double quote abend - perl <.pl> "" |
| 490 | if ((new_arg==NULL) || ((strlen(new_arg))<=0)) |
| 491 | { |
| 492 | pclp->m_argc--; // Decrement the number of parameters appended. |
| 493 | pclp->m_isValid = FALSE; |
| 494 | return; |
| 495 | } |
| 496 | |
| 497 | |
| 498 | return; |
| 499 | } |
| 500 | |
| 501 | |
| 502 | |
| 503 | /*============================================================================================ |
| 504 | |
| 505 | Function : fnSkipToken |
| 506 | |
| 507 | Description : This function collects the next command-line argument, breaking on |
| 508 | unquoted white space. The quote symbols are copied into the output. |
| 509 | White space has already been skipped. |
| 510 | |
| 511 | Parameters : s (IN) - Input string in which the token is skipped. |
| 512 | r (IN) - The resultant return string. |
| 513 | |
| 514 | Returns : String. |
| 515 | |
| 516 | ==============================================================================================*/ |
| 517 | |
| 518 | char *fnSkipToken(char *s, char *r) |
| 519 | { |
| 520 | register char *t=NULL; |
| 521 | register char quote = '\0'; // NULL, single quote, or double quote |
| 522 | char ch = '\0'; |
| 523 | |
| 524 | for (t=s; t[0]; t++) |
| 525 | { |
| 526 | ch = t[0]; |
| 527 | if (!quote) |
| 528 | { |
| 529 | if (isspace(ch)) // if unquoted whitespace... |
| 530 | { |
| 531 | break; // ...end of token found |
| 532 | } |
| 533 | else if (ch=='"' || ch=='\'') // if opening quote... |
| 534 | { |
| 535 | quote = ch; // ...enter quote mode |
| 536 | } |
| 537 | } |
| 538 | else |
| 539 | { |
| 540 | if (ch=='\\' && t[1]==quote) // if escaped quote... |
| 541 | { |
| 542 | t++; // ...skip backslash |
| 543 | } |
| 544 | else if (ch==quote) // if close quote... |
| 545 | { |
| 546 | quote = 0; // ...leave quote mode |
| 547 | } |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | r = fnStashString(s, r, t-s); // get heap-allocated token string |
| 552 | t = fnSkipWhite(t); // skip any trailing white space |
| 553 | s = t; // return updated source pointer |
| 554 | |
| 555 | s2 = t; // return updated global source pointer |
| 556 | |
| 557 | return r; // return heap-allocated token string |
| 558 | } |
| 559 | |
| 560 | |
| 561 | |
| 562 | /*============================================================================================ |
| 563 | |
| 564 | Function : fnScanToken |
| 565 | |
| 566 | Description : This function collects the next command-line argument, breaking on |
| 567 | unquoted white space or I/O redirection symbols. Quote symbols are not |
| 568 | copied into the output. |
| 569 | When called, any leading white space has already been skipped. |
| 570 | |
| 571 | Parameters : x (IN) - Input string in which the token is scanned. |
| 572 | r (IN) - The resultant return string. |
| 573 | |
| 574 | Returns : String. |
| 575 | |
| 576 | ==============================================================================================*/ |
| 577 | |
| 578 | char *fnScanToken(char *x, char *r) |
| 579 | { |
| 580 | register char *s = x; // input string position |
| 581 | register char *t = x; // output string position |
| 582 | register char quote = '\0'; // either NULL, or single quote, or double quote |
| 583 | register char ch = '\0'; |
| 584 | register char c = '\0'; |
| 585 | |
| 586 | while (*s) |
| 587 | { |
| 588 | ch = *s; // invariant: ch != 0 |
| 589 | |
| 590 | // look to see if we've reached the end of the token |
| 591 | if (!quote) // but don't look for token break if we're inside quotes |
| 592 | { |
| 593 | if (isspace(ch)) |
| 594 | break; // break on whitespace |
| 595 | if (ch=='>') |
| 596 | break; // break on ">" (redirect stdout) |
| 597 | if (ch=='<') |
| 598 | break; // break on "<" (redirect stdin) |
| 599 | if (ch=='&' && x[1]=='>') |
| 600 | break; // break on "&>" (redirect both stdout & stderr) |
| 601 | } |
| 602 | |
| 603 | // process the next source character |
| 604 | if (ch=='\\' && (c=s[1]) && (c=='\\'||c=='>'||c=='<'||c==quote)) |
| 605 | { |
| 606 | //-----------------if an escaped '\\', '>', '<', or quote... |
| 607 | s++; // ...skip over the backslash... |
| 608 | *t++ = *s++; // ...and copy the escaped character |
| 609 | } |
| 610 | else if (ch==quote) // (won't match unless inside quotes because invariant ch!=0) |
| 611 | { |
| 612 | //-----------------if close quote... |
| 613 | s++; // ...skip over the quote... |
| 614 | quote=0; // ...and leave quote mode |
| 615 | } |
| 616 | else if (!quote && (ch=='"' || ch=='\'')) |
| 617 | { |
| 618 | //-----------------if opening quote... |
| 619 | quote = *s++; // ...enter quote mode (remembering quote char, and skipping the quote) |
| 620 | } |
| 621 | else |
| 622 | { //----------if normal character... |
| 623 | *t++ = *s++; // ...copy the character |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | // clean up return values |
| 628 | r = fnStashString(x, r, t-x); // get heap-allocated token string |
| 629 | s = fnSkipWhite(s); // skip any trailing white space |
| 630 | x = s; // return updated source pointer |
| 631 | |
| 632 | s1 = s; // return updated global source pointer |
| 633 | |
| 634 | return r; |
| 635 | } |
| 636 | |
| 637 | |
| 638 | |
| 639 | /*============================================================================================ |
| 640 | |
| 641 | Function : fnStashString |
| 642 | |
| 643 | Description : This function return the heap-allocated token string. |
| 644 | |
| 645 | Parameters : s (IN) - Input string from which the token is extracted. |
| 646 | buffer (IN) - Return string. |
| 647 | length (IN) - Length of the token to be extracted. |
| 648 | |
| 649 | Returns : String. |
| 650 | |
| 651 | ==============================================================================================*/ |
| 652 | |
| 653 | char *fnStashString(char *s, char *buffer, int length) |
| 654 | { |
| 655 | if (length <= 0) |
| 656 | { |
| 657 | // Copy "" instead of NULL since "" indicates that there is memory allocated having no/null value. |
| 658 | // NULL indicates that there is no memory allocated to it! |
| 659 | strcpy(buffer, ""); |
| 660 | } |
| 661 | else |
| 662 | { |
| 663 | strncpy(buffer, s, length); |
| 664 | buffer[length] = '\0'; |
| 665 | } |
| 666 | |
| 667 | return buffer; |
| 668 | } |
| 669 | |
| 670 | |
| 671 | |
| 672 | /*============================================================================================ |
| 673 | |
| 674 | Function : fnDeleteArgument |
| 675 | |
| 676 | Description : This function deletes an argument (that was originally appended) from the list. |
| 677 | |
| 678 | Parameters : pclp (IN) - CommandLine structure. |
| 679 | index (IN) - Index of the argument to be deleted. |
| 680 | |
| 681 | Returns : Nothing. |
| 682 | |
| 683 | ==============================================================================================*/ |
| 684 | |
| 685 | void fnDeleteArgument(PCOMMANDLINEPARSER pclp, int index) |
| 686 | { |
| 687 | int i = index; |
| 688 | |
| 689 | |
| 690 | // If index is greater than the no. of arguments, just return. |
| 691 | if (index >= pclp->m_argc) |
| 692 | return; |
| 693 | |
| 694 | // Move all the arguments after the index one up. |
| 695 | while(i < (pclp->m_argv_len-1)) |
| 696 | { |
| 697 | strcpy(pclp->m_argv[i], pclp->m_argv[i+1]); |
| 698 | i++; |
| 699 | } |
| 700 | |
| 701 | |
| 702 | // Delete the last one and free memory. |
| 703 | if ( pclp->m_argv[i] ) |
| 704 | { |
| 705 | free(pclp->m_argv[i]); |
| 706 | pclp->m_argv[i] = NULL; |
| 707 | } |
| 708 | |
| 709 | |
| 710 | pclp->m_argc--; // Decrement the number of arguments. |
| 711 | pclp->m_argv_len--; |
| 712 | |
| 713 | return; |
| 714 | } |
| 715 | |
| 716 | |
| 717 | |
| 718 | /*============================================================================================ |
| 719 | |
| 720 | Function : fnMy_MkTemp |
| 721 | |
| 722 | Description : This is a standard ANSI C mktemp for NetWare |
| 723 | |
| 724 | Parameters : templatestr (IN) - Input temp filename. |
| 725 | |
| 726 | Returns : String. |
| 727 | |
| 728 | ==============================================================================================*/ |
| 729 | |
| 730 | char* fnMy_MkTemp(char* templatestr) |
| 731 | { |
| 732 | char* pXs=NULL; |
| 733 | char numbuf[50]={'\0'}; |
| 734 | int count=0; |
| 735 | char* pPid=NULL; |
| 736 | |
| 737 | char termchar = '\0'; |
| 738 | char letter = 'a'; |
| 739 | char letter1 = 'a'; |
| 740 | |
| 741 | |
| 742 | if (templatestr && (pXs = strstr(templatestr, (char *)"XXXXXX"))) |
| 743 | { |
| 744 | // generate temp name |
| 745 | termchar = pXs[6]; |
| 746 | ltoa(GetThreadID(), numbuf, 16); |
| 747 | // numbuf[sizeof(numbuf)-1] = '\0'; |
| 748 | numbuf[strlen(numbuf)-1] = '\0'; |
| 749 | // beware! thread IDs are 8 hex digits on NW 4.11 and only the |
| 750 | // lower digits seem to change, whereas on NW 5 they are in the |
| 751 | // range of < 1000 hex or 3 hex digits in length. So the following |
| 752 | // logic ensures we use the least significant portion of the number. |
| 753 | if (strlen(numbuf) > 5) |
| 754 | pPid = &numbuf[strlen(numbuf)-5]; |
| 755 | else |
| 756 | pPid = numbuf; |
| 757 | |
| 758 | /** |
| 759 | Backtick operation uses temp files that are stored under NWDEFPERLTEMP |
| 760 | directory. They are temporarily used and then cleaned up after usage. |
| 761 | In cases where multiple backtick operations are used that call some |
| 762 | complex scripts, new temp files will be created before the old ones are |
| 763 | deleted. So, we need to have a provision to create many temp files. |
| 764 | Hence the below logic. It is found that provision for 26 files may |
| 765 | not be enough in some cases. |
| 766 | |
| 767 | This below logic allows 26 files (like, pla00015.tmp through plz00015.tmp) |
| 768 | plus 6x26=676 (like, plaa0015.tmp through plzz0015.tmp) |
| 769 | **/ |
| 770 | |
| 771 | letter = 'a'; |
| 772 | do |
| 773 | { |
| 774 | sprintf(pXs, (char *)"%c%05.5s", letter, pPid); |
| 775 | pXs[6] = termchar; |
| 776 | if (access(templatestr, 0) != 0) // File does not exist |
| 777 | { |
| 778 | return templatestr; |
| 779 | } |
| 780 | letter++; |
| 781 | } while (letter <= 'z'); |
| 782 | |
| 783 | letter1 = 'a'; |
| 784 | do |
| 785 | { |
| 786 | letter = 'a'; |
| 787 | do |
| 788 | { |
| 789 | sprintf(pXs, (char *)"%c%c%04.5s", letter1, letter, pPid); |
| 790 | pXs[6] = termchar; |
| 791 | if (access(templatestr, 0) != 0) // File does not exist |
| 792 | { |
| 793 | return templatestr; |
| 794 | } |
| 795 | letter++; |
| 796 | } while (letter <= 'z'); |
| 797 | letter1++; |
| 798 | } while (letter1 <= 'z'); |
| 799 | |
| 800 | errno = ENOENT; |
| 801 | return NULL; |
| 802 | } |
| 803 | else |
| 804 | { |
| 805 | errno = EINVAL; |
| 806 | return NULL; |
| 807 | } |
| 808 | } |
| 809 | |
| 810 | |
| 811 | |
| 812 | /*============================================================================================ |
| 813 | |
| 814 | Function : fnSystemCommand |
| 815 | |
| 816 | Description : This function constructs a system command from the given |
| 817 | null-terminated argv array and runs the command on the system console. |
| 818 | |
| 819 | Parameters : argv (IN) - Array of input commands. |
| 820 | argc (IN) - Number of input parameters. |
| 821 | |
| 822 | Returns : Nothing. |
| 823 | |
| 824 | ==============================================================================================*/ |
| 825 | |
| 826 | void fnSystemCommand (char** argv, int argc) |
| 827 | { |
| 828 | // calculate the size of a temp buffer needed |
| 829 | int k = 0; |
| 830 | int totalSize = 0; |
| 831 | int bytes = 0; |
| 832 | char* tempCmd = NULL; |
| 833 | char* tptr = NULL; |
| 834 | |
| 835 | |
| 836 | for(k=0; k<argc; k++) |
| 837 | totalSize += strlen(argv[k]) + 1; |
| 838 | |
| 839 | tempCmd = (char *) malloc((totalSize+1) * sizeof(char)); |
| 840 | if (!tempCmd) |
| 841 | return; |
| 842 | tptr = tempCmd; |
| 843 | |
| 844 | for(k=0; k<argc; k++) |
| 845 | tptr += sprintf(tptr, (char *)"%s ", argv[k]); |
| 846 | *tptr = 0; |
| 847 | |
| 848 | if (stricmp(argv[0], PERL_COMMAND_NAME) == 0) |
| 849 | fnInternalPerlLaunchHandler(tempCmd); // Launch perl. |
| 850 | else |
| 851 | system(tempCmd); |
| 852 | |
| 853 | |
| 854 | free(tempCmd); |
| 855 | tempCmd = NULL; |
| 856 | return; |
| 857 | } |
| 858 | |