Skip the RV printing test under threads until fixed.
[p5sagit/p5-mst-13.2.git] / NetWare / NWUtil.c
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 junk characters.
476         // 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 it is given the second time, a new blank screen should come up which also
479         //   allows for editing. This was not consistently working well.
480         //   More so when the command was like, "perl   ", that is the name "perl"
481         //   followed by a few blank spaces. It used to give error in opening file and
482         //   would give some junk as the filename unable to open.
483         // Once the below fix was done, it is working fine.
484         for(i=pclp->m_argc; i<pclp->m_argv_len; i++)
485                 strncpy(pclp->m_argv[i], "", (MAX_DN_BYTES * sizeof(char)));    // MAX_DN_BYTES is the size of pclp->m_argv[].
486
487
488         // Fix for empty command line double quote abend - perl <.pl> ""
489         if ((new_arg==NULL) || ((strlen(new_arg))<=0))
490         {
491                 pclp->m_argc--;         // Decrement the number of parameters appended.
492                 pclp->m_isValid = FALSE;
493                 return;
494         }
495
496
497         return;
498 }
499
500
501
502 /*============================================================================================
503
504  Function               :       fnSkipToken
505
506  Description    :       This function collects the next command-line argument, breaking on
507                                         unquoted white space. The quote symbols are copied into the output.
508                                         White space has already been skipped.
509
510  Parameters     :       s       (IN)    -       Input string in which the token is skipped.
511                                         r       (IN)    -       The resultant return string.
512
513  Returns                :       String.
514
515 ==============================================================================================*/
516
517 char *fnSkipToken(char *s, char *r)
518 {
519         register char *t=NULL;
520         register char quote = '\0'; // NULL, single quote, or double quote
521         char ch = '\0';
522
523         for (t=s; t[0]; t++)
524         {
525                 ch = t[0];
526                 if (!quote)
527                 {
528                         if (isspace(ch))                                // if unquoted whitespace...
529                         {
530                                 break;                                          // ...end of token found
531                         }
532                         else if (ch=='"' || ch=='\'')   // if opening quote...
533                         {
534                                 quote = ch;                                     // ...enter quote mode
535                         }
536                 }
537                 else
538                 {
539                         if (ch=='\\' && t[1]==quote)    // if escaped quote...
540                         {
541                                 t++;                                            // ...skip backslash
542                         }
543                         else if (ch==quote)                             // if close quote...
544                         {
545                                 quote = 0;                                      // ...leave quote mode
546                         } 
547                 }
548         }
549
550         r = fnStashString(s, r, t-s);  // get heap-allocated token string
551         t = fnSkipWhite(t);                // skip any trailing white space
552         s = t;                           // return updated source pointer
553
554         s2 = t;                           // return updated global source pointer
555
556         return r;                        // return heap-allocated token string
557 }
558
559
560
561 /*============================================================================================
562
563  Function               :       fnScanToken
564
565  Description    :       This function collects the next command-line argument, breaking on
566                                         unquoted white space or I/O redirection symbols. Quote symbols are not
567                                         copied into the output.
568                                         When called, any leading white space has already been skipped.
569
570  Parameters     :       x       (IN)    -       Input string in which the token is scanned.
571                                         r       (IN)    -       The resultant return string.
572
573  Returns                :       String.
574
575 ==============================================================================================*/
576
577 char *fnScanToken(char *x, char *r)
578 {
579         register char *s = x; // input string position
580         register char *t = x; // output string position
581         register char quote = '\0'; // either NULL, or single quote, or double quote
582         register char ch = '\0';
583         register char c = '\0';
584
585         while (*s)
586         {
587                 ch = *s; // invariant: ch != 0
588                 
589                 // look to see if we've reached the end of the token
590                 if (!quote)             // but don't look for token break if we're inside quotes
591                 {
592                         if (isspace(ch))
593                                 break;          // break on whitespace
594                         if (ch=='>')
595                                 break;              // break on ">"  (redirect stdout)
596                         if (ch=='<')
597                                 break;              // break on "<"  (redirect stdin)
598                         if (ch=='&' && x[1]=='>')
599                                 break; // break on "&>" (redirect both stdout & stderr)
600                 }
601                 
602                 // process the next source character
603                 if (ch=='\\' && (c=s[1]) && (c=='\\'||c=='>'||c=='<'||c==quote))
604                 {
605                         //-----------------if an escaped '\\', '>', '<', or quote...
606                         s++;            // ...skip over the backslash...
607                         *t++ = *s++;    // ...and copy the escaped character
608                 }
609                 else if (ch==quote)             // (won't match unless inside quotes because invariant ch!=0)
610                 {
611                         //-----------------if close quote...
612                         s++;            // ...skip over the quote...
613                         quote=0;        // ...and leave quote mode
614                 }
615                 else if (!quote && (ch=='"' || ch=='\''))
616                 {
617                         //-----------------if opening quote...
618                         quote = *s++;   // ...enter quote mode (remembering quote char, and skipping the quote)
619                 }
620                 else
621                 {               //----------if normal character...
622                         *t++ = *s++;    // ...copy the character
623                 }
624         }
625
626         // clean up return values
627         r = fnStashString(x, r, t-x);  // get heap-allocated token string
628         s = fnSkipWhite(s);                // skip any trailing white space
629         x = s;                           // return updated source pointer
630
631         s1 = s;                           // return updated global source pointer
632
633         return r;
634 }
635
636
637
638 /*============================================================================================
639
640  Function               :       fnStashString
641
642  Description    :       This function return the heap-allocated token string.
643
644  Parameters     :       s       (IN)    -       Input string from which the token is extracted.
645                                         buffer  (IN)    -       Return string.
646                                         length  (IN)    -       Length of the token to be extracted.
647
648  Returns                :       String.
649
650 ==============================================================================================*/
651
652 char *fnStashString(char *s, char *buffer, int length)
653 {
654         if (length <= 0)
655         {
656                 // Copy "" instead of NULL since "" indicates that there is memory allocated having no/null value.
657                 // NULL indicates that there is no memory allocated to it!
658                 strcpy(buffer, "");
659         }
660         else
661         {
662                 strncpy(buffer, s, length);
663                 buffer[length] = '\0';
664         }
665
666         return buffer;
667 }
668
669
670
671 /*============================================================================================
672
673  Function               :       fnDeleteArgument
674
675  Description    :       This function deletes an argument (that was originally appended) from the list.
676
677  Parameters     :       pclp    (IN)    -       CommandLine structure.
678                                         index   (IN)    -       Index of the argument to be deleted.
679
680  Returns                :       Nothing.
681
682 ==============================================================================================*/
683
684 void fnDeleteArgument(PCOMMANDLINEPARSER pclp, int index)
685 {
686         int i = index;
687
688
689         // If index is greater than the no. of arguments, just return.
690         if (index >= pclp->m_argc)
691                 return;
692
693         // Move all the arguments after the index one up.
694         while(i < (pclp->m_argv_len-1))
695         {
696                 strcpy(pclp->m_argv[i], pclp->m_argv[i+1]);
697                 i++;
698         }
699
700
701         // Delete the last one and free memory.
702         if ( pclp->m_argv[i] )
703         {
704                 free(pclp->m_argv[i]);
705                 pclp->m_argv[i] = NULL;
706         }
707
708
709         pclp->m_argc--;         // Decrement the number of arguments.
710         pclp->m_argv_len--;
711
712         return;
713 }
714
715
716
717 /*============================================================================================
718
719  Function               :       fnMy_MkTemp
720
721  Description    :       This is a standard ANSI C mktemp for NetWare
722
723  Parameters     :       templatestr     (IN)    -       Input temp filename.
724
725  Returns                :       String.
726
727 ==============================================================================================*/
728
729 char* fnMy_MkTemp(char* templatestr)
730 {
731         char* pXs=NULL;
732         char numbuf[50]={'\0'};
733         int count=0;
734         char* pPid=NULL;
735
736         char termchar = '\0';
737         char letter = 'a';
738         char letter1 = 'a';
739
740
741         if (templatestr && (pXs = strstr(templatestr, (char *)"XXXXXX")))
742         {
743                 // generate temp name
744                 termchar = pXs[6];
745                 ltoa(GetThreadID(), numbuf, 16);
746 //              numbuf[sizeof(numbuf)-1] = '\0';
747                 numbuf[strlen(numbuf)-1] = '\0';
748                 // beware! thread IDs are 8 hex digits on NW 4.11 and only the
749                 // lower digits seem to change, whereas on NW 5 they are in the
750                 // range of < 1000 hex or 3 hex digits in length. So the following
751                 // logic ensures we use the least significant portion of the number.
752                 if (strlen(numbuf) > 5)
753                         pPid = &numbuf[strlen(numbuf)-5];
754                 else
755                         pPid = numbuf;
756
757 /**
758                 Backtick operation uses temp files that are stored under NWDEFPERLTEMP
759                 directory. They are temporarily used and then cleaned up after usage.
760                 In cases where multiple backtick operations are used that call some
761                 complex scripts, new temp files will be created before the old ones are
762                 deleted. So, we need to have a provision to create many temp files.
763                 Hence the below logic. It is found that provision for 26 files may
764                 not be enough in some cases.
765
766                 This below logic allows 26 files (like, pla00015.tmp through plz00015.tmp)
767                 plus 6x26=676 (like, plaa0015.tmp through plzz0015.tmp)
768 **/
769
770                 letter = 'a';
771                 do
772                 {
773                         sprintf(pXs, (char *)"%c%05.5s", letter, pPid);
774                         pXs[6] = termchar;
775                         if (access(templatestr, 0) != 0)        // File does not exist
776                         {
777                                 return templatestr;
778                         }
779                         letter++;
780                 } while (letter <= 'z');
781
782                 letter1 = 'a';
783                 do
784                 {
785                         letter = 'a';
786                         do
787                         {
788                                 sprintf(pXs, (char *)"%c%c%04.5s", letter1, letter, pPid);
789                                 pXs[6] = termchar;
790                                 if (access(templatestr, 0) != 0)        // File does not exist
791                                 {
792                                         return templatestr;
793                                 }
794                                 letter++;
795                         } while (letter <= 'z');
796                         letter1++;
797                 } while (letter1 <= 'z');
798
799                 errno = ENOENT;
800                 return NULL;
801         }
802         else
803         {
804                 errno = EINVAL;
805                 return NULL;
806         }
807 }
808
809
810
811 /*============================================================================================
812
813  Function               :       fnSystemCommand
814
815  Description    :       This function constructs a system command from the given
816                                         null-terminated argv array and runs the command on the system console.
817
818  Parameters     :       argv    (IN)    -       Array of input commands.
819                                         argc    (IN)    -       Number of input parameters.
820
821  Returns                :       Nothing.
822
823 ==============================================================================================*/
824
825 void fnSystemCommand (char** argv, int argc)
826 {
827         // calculate the size of a temp buffer needed
828         int k = 0;
829         int totalSize = 0;
830         int bytes = 0;
831         char* tempCmd = NULL;
832         char* tptr = NULL;
833
834
835         for(k=0; k<argc; k++)
836                 totalSize += strlen(argv[k]) + 1;
837
838         tempCmd = (char *) malloc((totalSize+1) * sizeof(char));
839         if (!tempCmd)
840                 return;
841         tptr = tempCmd;
842
843         for(k=0; k<argc; k++)
844                 tptr += sprintf(tptr, (char *)"%s ", argv[k]);
845         *tptr = 0;
846
847         if (stricmp(argv[0], PERL_COMMAND_NAME) == 0)
848                 fnInternalPerlLaunchHandler(tempCmd);   // Launch perl.
849         else
850                 system(tempCmd);
851
852
853         free(tempCmd);
854         tempCmd = NULL;
855         return;
856 }
857