diff options
Diffstat (limited to 'NetWare/NWUtil.c')
-rw-r--r-- | NetWare/NWUtil.c | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/NetWare/NWUtil.c b/NetWare/NWUtil.c new file mode 100644 index 0000000000..9cc5b5c629 --- /dev/null +++ b/NetWare/NWUtil.c @@ -0,0 +1,826 @@ + +/* + * Copyright © 2001 Novell, Inc. All Rights Reserved. + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + * + */ + +/* + * FILENAME : NWUtil.c + * DESCRIPTION : Utility functions for NetWare implementation of Perl. + * Author : HYAK + * Date : Januray 2001. + * + */ + + + +#include "stdio.h" +#include "string.h" + +#include <nwdsdefs.h> // For "MAX_DN_BYTES" +#include <malloc.h> // For "malloc" and "free" +#include <stdlib.h> // For "getenv" +#include <ctype.h> // For "isspace" + +#include <process.h> +#include <unistd.h> +#include <errno.h> +#include <nwerrno.h> + +#include <nwlocale.h> +#include <nwadv.h> + +#include "nwutil.h" + + +#define TRUE 1 +#define FALSE 0 + + +/** + Global variables used for better token parsing. When these were absent, + token parsing was not correct when there were more number of arguments passed. + These are used in fnCommandLineParser, fnSkipToken and fnScanToken to get/return + the correct and updated pointer to the command line string. +**/ +char *s1 = NULL; // Used in fnScanToken. +char *s2 = NULL; // Used in fnSkipToken. + + + + +/*============================================================================================ + + Function : fnSkipWhite + + Description : This function skips the white space characters in the given string and + returns the resultant value. + + Parameters : s (IN) - Input string. + + Returns : String. + +==============================================================================================*/ + +char *fnSkipWhite(char *s) +{ + while (isspace(*s)) + s++; + return s; +} + + + +/*============================================================================================ + + Function : fnNwGetEnvironmentStr + + Description : This function returns the NetWare environment string if available, + otherwise returns the supplied default value + + Parameters : name (IN) - To hold the NetWare environment value. + defaultvalue (IN) - Default value. + + + Returns : String. + +==============================================================================================*/ + +char *fnNwGetEnvironmentStr(char *name, char *defaultvalue) +{ + char* ret = getenv(name); + if (ret == NULL) + ret = defaultvalue; + return ret; +} + + + +/*============================================================================================ + + Function : fnCommandLineParser + + Description : This function parses the command line into argc/argv style of + Number of params and array of params. + + Parameters : pclp (IN) - CommandLine structure. + commandLine (IN) - CommandLine String. + preserverQuotes (IN) - Indicates whether to preserve/copy the quotes or not. + + Returns : Nothing. + +==============================================================================================*/ + +void fnCommandLineParser(PCOMMANDLINEPARSER pclp, char * commandLine, BOOL preserveQuotes) +{ + char *buffer = NULL; + + int index = 0; + int do_delete = 1; + int i=0, j=0, k=0; + + + // +1 makes room for the terminating NULL + buffer = (char *) malloc((strlen(commandLine) + 1) * sizeof(char)); + if (buffer == NULL) + { + pclp->m_isValid = FALSE; + return; + } + + if (preserveQuotes) + { + // No I/O redirection nor quote processing if preserveQuotes + + char *s = NULL; + char *sSkippedToken = NULL; + + + strcpy(buffer, commandLine); + s = buffer; + s = fnSkipWhite(s); // Skip white spaces. + + s2 = s; // Update the global pointer. + + + pclp->sSkippedToken = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->sSkippedToken == NULL) + { + pclp->m_isValid = FALSE; + return; + } + + while (*s && pclp->m_isValid) + { +/**** +// Commented since only one time malloc and free is enough as is done outside this while loop. +// It is not required to do them everytime the execution comes into this while loop. +// Still retained here. Remove this once things are proved to be working fine to a good confident level, + + if(pclp->sSkippedToken) + { + free(pclp->sSkippedToken); + pclp->sSkippedToken = NULL; + } + + if(pclp->sSkippedToken == NULL) + { + pclp->sSkippedToken = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->sSkippedToken == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } +****/ + + // Empty the string. + strncpy(pclp->sSkippedToken, "", (MAX_DN_BYTES * sizeof(char))); + + // s is advanced by fnSkipToken + pclp->sSkippedToken = fnSkipToken(s, pclp->sSkippedToken); // Collect the next command-line argument. + + s2 = fnSkipWhite(s2); // s2 is already updated by fnSkipToken. + s = s2; // Update the local pointer too. + + fnAppendArgument(pclp, pclp->sSkippedToken); // Append the argument into an array. + } + + if(pclp->sSkippedToken) + { + free(pclp->sSkippedToken); + pclp->sSkippedToken = NULL; + } + } + else + { + char *s = NULL; + + strcpy(buffer, commandLine); + s = buffer; + s = fnSkipWhite(s); + + s1 = s; // Update the global pointer. + + while (*s && pclp->m_isValid) + { + // s is advanced by fnScanToken + // Check for I/O redirection here, *outside* of + // fnScanToken(), so that quote-protected angle + // brackets do NOT cause redirection. + if (*s == '<') + { + s = fnSkipWhite(s+1); // get stdin redirection + + if(pclp->m_redirInName) + { + free(pclp->m_redirInName); + pclp->m_redirInName = NULL; + } + + if(pclp->m_redirInName == NULL) + { + pclp->m_redirInName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->m_redirInName == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } + + // Collect the next command-line argument. + pclp->m_redirInName = fnScanToken(s, pclp->m_redirInName); + + s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. + s = s1; // Update the local pointer too. + } + else if (*s == '>') + { + s = fnSkipWhite(s+1); //get stdout redirection + + if(pclp->m_redirOutName) + { + free(pclp->m_redirOutName); + pclp->m_redirOutName = NULL; + } + + if(pclp->m_redirOutName == NULL) + { + pclp->m_redirOutName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->m_redirOutName == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } + + // Collect the next command-line argument. + pclp->m_redirOutName = fnScanToken(s, pclp->m_redirOutName); + + s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. + s = s1; // Update the local pointer too. + } + else if (*s == '2' && s[1] == '>') + { + s = fnSkipWhite(s+2); // get stderr redirection + + if(pclp->m_redirErrName) + { + free(pclp->m_redirErrName); + pclp->m_redirErrName = NULL; + } + + if(pclp->m_redirErrName == NULL) + { + pclp->m_redirErrName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->m_redirErrName == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } + + // Collect the next command-line argument. + pclp->m_redirErrName = fnScanToken(s, pclp->m_redirErrName); + + s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. + s = s1; // Update the local pointer too. + } + else if (*s == '&' && s[1] == '>') + { + s = fnSkipWhite(s+2); // get stdout+stderr redirection + + if(pclp->m_redirBothName) + { + free(pclp->m_redirBothName); + pclp->m_redirBothName = NULL; + } + + if(pclp->m_redirBothName == NULL) + { + pclp->m_redirBothName = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->m_redirBothName == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } + + // Collect the next command-line argument. + pclp->m_redirBothName = fnScanToken(s, pclp->m_redirBothName); + + s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. + s = s1; // Update the local pointer too. + } + else + { + if(pclp->nextarg) + { + free(pclp->nextarg); + pclp->nextarg = NULL; + } + + if(pclp->nextarg == NULL) + { + pclp->nextarg = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if(pclp->nextarg == NULL) + { + pclp->m_isValid = FALSE; + return; + } + } + + // Collect the next command-line argument. + pclp->nextarg = fnScanToken(s, pclp->nextarg); + + s1 = fnSkipWhite(s1); // s1 is already updated by fnScanToken. + s = s1; // Update the local pointer too. + + // Append the next command-line argument into an array. + fnAppendArgument(pclp, pclp->nextarg); + } + } + } + + + // The -{ option, the --noscreen option, the --autodestroy option, if present, + // are processed now and removed from the argument vector. + for(index=0; index < pclp->m_argc; ) + { + // "-q" is replaced by "-{", because of clash with GetOpt - sgp - 7th Nov 2000 + // Copied from NDK build - Jan 5th 2001 + if (strncmp(pclp->m_argv[index], (char *)"-{", 2) == 0) + { + // found a -q option; grab the semaphore number + sscanf(pclp->m_argv[index], (char *)"-{%x", &pclp->m_qSemaphore); + fnDeleteArgument(pclp, index); // Delete the argument from the list. + } + else if (strcmp(pclp->m_argv[index], (char *)"--noscreen") == 0) + { + // found a --noscreen option + pclp->m_noScreen = 1; + fnDeleteArgument(pclp, index); + } + else if (strcmp(pclp->m_argv[index], (char *)"--autodestroy") == 0) + { + // found a --autodestroy option - create a screen but close automatically + pclp->m_AutoDestroy = 1; + fnDeleteArgument(pclp, index); + } + else + index++; + } + + // pclp->m_isValid is TRUE if there are more than 2 command line parameters OR + // if there is only one command and if it is the comman PERL. + pclp->m_isValid = ((pclp->m_argc >= 2) || ((pclp->m_argc > 0) && (stricmp(pclp->m_argv[0], LOAD_COMMAND) != 0))); + + if(buffer) + { + free(buffer); + buffer = NULL; + } + + return; +} + + + +/*============================================================================================ + + Function : fnAppendArgument + + Description : This function appends the arguments into a list. + + Parameters : pclp (IN) - CommandLine structure. + new_arg (IN) - The new argument to be appended. + + Returns : Nothing. + +==============================================================================================*/ + +void fnAppendArgument(PCOMMANDLINEPARSER pclp, char *new_arg) +{ + char **new_argv = pclp->new_argv; + + int new_argv_len = pclp->m_argv_len*2; + int i = 0, j = 0; + + + // Lengthen the argument vector if there's not room for another. + // Testing for 'm_argc+2' rather than 'm_argc+1' in the test guarantees + // that there'll always be a NULL terminator at the end of argv. + if ((pclp->m_argc + 2) > pclp->m_argv_len) + { + new_argv = (char **) malloc(new_argv_len * sizeof(char*)); // get a longer arg-vector + if (new_argv == NULL) + { + pclp->m_isValid = FALSE; + return; + } + for(i=0; i<new_argv_len; i++) + { + new_argv[i] = (char *) malloc(MAX_DN_BYTES * sizeof(char)); + if (new_argv[i] == NULL) + { + for(j=0; j<i; j++) + { + if(new_argv[j]) + { + free(new_argv[j]); + new_argv[j] = NULL; + } + } + if(new_argv) + { + free(new_argv); + new_argv = NULL; + } + + pclp->m_isValid = FALSE; + return; + } + } + + for (i=0; i<pclp->m_argc; i++) + strcpy(new_argv[i], pclp->m_argv[i]); // copy old arg strings + + for(i=0; i<(pclp->m_argv_len); i++) + { + if(pclp->m_argv[i]) + { + free(pclp->m_argv[i]); + pclp->m_argv[i] = NULL; + } + } + if (pclp->m_argv != NULL) + { + free(pclp->m_argv); + pclp->m_argv = NULL; + } + + + pclp->m_argv = new_argv; + pclp->m_argv_len = new_argv_len; + + } + + // Once m_argv is guaranteed long enough, appending the argument is a direct job. + strcpy(pclp->m_argv[pclp->m_argc], new_arg); // Appended the new argument. + pclp->m_argc++; // Increment the number of parameters appended. + + // The char array is emptied for all elements upto the end so that there are no junk characters. + // If this is not done, then the issue is like this: + // - Simple perl command like "perl" on the system console works fine for the first time. + // - When it is given the second time, a new blank screen should come up which also + // allows for editing. This was not consistently working well. + // More so when the command was like, "perl ", that is the name "perl" + // followed by a few blank spaces. It used to give error in opening file and + // would give some junk as the filename unable to open. + // Once the below fix was done, it is working fine. + for(i=pclp->m_argc; i<pclp->m_argv_len; i++) + strncpy(pclp->m_argv[i], "", (MAX_DN_BYTES * sizeof(char))); // MAX_DN_BYTES is the size of pclp->m_argv[]. + + + // Fix for empty command line double quote abend - perl <.pl> "" + if ((new_arg==NULL) || ((strlen(new_arg))<=0)) + { + pclp->m_argc--; // Decrement the number of parameters appended. + pclp->m_isValid = FALSE; + return; + } + + + return; +} + + + +/*============================================================================================ + + Function : fnSkipToken + + Description : This function collects the next command-line argument, breaking on + unquoted white space. The quote symbols are copied into the output. + White space has already been skipped. + + Parameters : s (IN) - Input string in which the token is skipped. + r (IN) - The resultant return string. + + Returns : String. + +==============================================================================================*/ + +char *fnSkipToken(char *s, char *r) +{ + register char *t=NULL; + register char quote = '\0'; // NULL, single quote, or double quote + char ch = '\0'; + + for (t=s; t[0]; t++) + { + ch = t[0]; + if (!quote) + { + if (isspace(ch)) // if unquoted whitespace... + { + break; // ...end of token found + } + else if (ch=='"' || ch=='\'') // if opening quote... + { + quote = ch; // ...enter quote mode + } + } + else + { + if (ch=='\\' && t[1]==quote) // if escaped quote... + { + t++; // ...skip backslash + } + else if (ch==quote) // if close quote... + { + quote = 0; // ...leave quote mode + } + } + } + + r = fnStashString(s, r, t-s); // get heap-allocated token string + t = fnSkipWhite(t); // skip any trailing white space + s = t; // return updated source pointer + + s2 = t; // return updated global source pointer + + return r; // return heap-allocated token string +} + + + +/*============================================================================================ + + Function : fnScanToken + + Description : This function collects the next command-line argument, breaking on + unquoted white space or I/O redirection symbols. Quote symbols are not + copied into the output. + When called, any leading white space has already been skipped. + + Parameters : x (IN) - Input string in which the token is scanned. + r (IN) - The resultant return string. + + Returns : String. + +==============================================================================================*/ + +char *fnScanToken(char *x, char *r) +{ + register char *s = x; // input string position + register char *t = x; // output string position + register char quote = '\0'; // either NULL, or single quote, or double quote + register char ch = '\0'; + register char c = '\0'; + + while (*s) + { + ch = *s; // invariant: ch != 0 + + // look to see if we've reached the end of the token + if (!quote) // but don't look for token break if we're inside quotes + { + if (isspace(ch)) + break; // break on whitespace + if (ch=='>') + break; // break on ">" (redirect stdout) + if (ch=='<') + break; // break on "<" (redirect stdin) + if (ch=='&' && x[1]=='>') + break; // break on "&>" (redirect both stdout & stderr) + } + + // process the next source character + if (ch=='\\' && (c=s[1]) && (c=='\\'||c=='>'||c=='<'||c==quote)) + { + //-----------------if an escaped '\\', '>', '<', or quote... + s++; // ...skip over the backslash... + *t++ = *s++; // ...and copy the escaped character + } + else if (ch==quote) // (won't match unless inside quotes because invariant ch!=0) + { + //-----------------if close quote... + s++; // ...skip over the quote... + quote=0; // ...and leave quote mode + } + else if (!quote && (ch=='"' || ch=='\'')) + { + //-----------------if opening quote... + quote = *s++; // ...enter quote mode (remembering quote char, and skipping the quote) + } + else + { //----------if normal character... + *t++ = *s++; // ...copy the character + } + } + + // clean up return values + r = fnStashString(x, r, t-x); // get heap-allocated token string + s = fnSkipWhite(s); // skip any trailing white space + x = s; // return updated source pointer + + s1 = s; // return updated global source pointer + + return r; +} + + + +/*============================================================================================ + + Function : fnStashString + + Description : This function return the heap-allocated token string. + + Parameters : s (IN) - Input string from which the token is extracted. + buffer (IN) - Return string. + length (IN) - Length of the token to be extracted. + + Returns : String. + +==============================================================================================*/ + +char *fnStashString(char *s, char *buffer, int length) +{ + if (length <= 0) + { + // Copy "" instead of NULL since "" indicates that there is memory allocated having no/null value. + // NULL indicates that there is no memory allocated to it! + strcpy(buffer, ""); + } + else + { + strncpy(buffer, s, length); + buffer[length] = '\0'; + } + + return buffer; +} + + + +/*============================================================================================ + + Function : fnDeleteArgument + + Description : This function deletes an argument (that was originally appended) from the list. + + Parameters : pclp (IN) - CommandLine structure. + index (IN) - Index of the argument to be deleted. + + Returns : Nothing. + +==============================================================================================*/ + +void fnDeleteArgument(PCOMMANDLINEPARSER pclp, int index) +{ + int i = index; + + + // If index is greater than the no. of arguments, just return. + if (index >= pclp->m_argc) + return; + + // Move all the arguments after the index one up. + while(i < (pclp->m_argv_len-1)) + { + strcpy(pclp->m_argv[i], pclp->m_argv[i+1]); + i++; + } + + + // Delete the last one and free memory. + if ( pclp->m_argv[i] ) + { + free(pclp->m_argv[i]); + pclp->m_argv[i] = NULL; + } + + + pclp->m_argc--; // Decrement the number of arguments. + pclp->m_argv_len--; + + return; +} + + + +/*============================================================================================ + + Function : fnMy_MkTemp + + Description : This is a standard ANSI C mktemp for NetWare + + Parameters : templatestr (IN) - Input temp filename. + + Returns : String. + +==============================================================================================*/ + +char* fnMy_MkTemp(char* templatestr) +{ + char* pXs=NULL; + char numbuf[50]={'\0'}; + int count=0; + char* pPid=NULL; + + char termchar = '\0'; + char letter = 'a'; + + + if (templatestr && (pXs = strstr(templatestr, (char *)"XXXXXX"))) + { + // generate temp name + termchar = pXs[6]; + ltoa(GetThreadID(), numbuf, 16); +// numbuf[sizeof(numbuf)-1] = '\0'; + numbuf[strlen(numbuf)-1] = '\0'; + // beware! thread IDs are 8 hex digits on NW 4.11 and only the + // lower digits seem to change, whereas on NW 5 they are in the + // range of < 1000 hex or 3 hex digits in length. So the following + // logic ensures we use the least significant portion of the number. + if (strlen(numbuf) > 5) + pPid = &numbuf[strlen(numbuf)-5]; + else + pPid = numbuf; + + letter = 'a'; + do + { + sprintf(pXs, (char *)"%c%05.5s", letter, pPid); + pXs[6] = termchar; + if (access(templatestr, 0) != 0) // File does not exist + { + return templatestr; + } + letter++; + } while (letter <= 'z'); + + errno = ENOENT; + return NULL; + } + else + { + errno = EINVAL; + return NULL; + } +} + + + +/*============================================================================================ + + Function : fnSystemCommand + + Description : This function constructs a system command from the given + null-terminated argv array and runs the command on the system console. + + Parameters : argv (IN) - Array of input commands. + argc (IN) - Number of input parameters. + + Returns : Nothing. + +==============================================================================================*/ + +void fnSystemCommand (char** argv, int argc) +{ + // calculate the size of a temp buffer needed + int k = 0; + int totalSize = 0; + int bytes = 0; + char* tempCmd = NULL; + char* tptr = NULL; + + + for(k=0; k<argc; k++) + totalSize += strlen(argv[k]) + 1; + + tempCmd = (char *) malloc((totalSize+1) * sizeof(char)); + if (!tempCmd) + return; + tptr = tempCmd; + + for(k=0; k<argc; k++) + tptr += sprintf(tptr, (char *)"%s ", argv[k]); + *tptr = 0; + + if (stricmp(argv[0], PERL_COMMAND_NAME) == 0) + fnInternalPerlLaunchHandler(tempCmd); // Launch perl. + else + system(tempCmd); + + + free(tempCmd); + tempCmd = NULL; + return; +} + |