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 
fnSkipWhite(char * s)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 
fnNwGetEnvironmentStr(char * name,char * defaultvalue)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 
fnCommandLineParser(PCOMMANDLINEPARSER pclp,char * commandLine,BOOL preserveQuotes)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 
fnAppendArgument(PCOMMANDLINEPARSER pclp,char * new_arg)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 
fnSkipToken(char * s,char * r)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 
fnScanToken(char * x,char * r)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 
fnStashString(char * s,char * buffer,int length)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 
fnDeleteArgument(PCOMMANDLINEPARSER pclp,int index)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 
fnMy_MkTemp(char * templatestr)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 
fnSystemCommand(char ** argv,int argc)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 
859