(perl #134221) MSVC doesn't define O_ACCMODE
[perl.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                 :       January 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         char *t=NULL;
521         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         char *s = x; // input string position
581         char *t = x; // output string position
582         char quote = '\0'; // either NULL, or single quote, or double quote
583         char ch = '\0';
584         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