This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate mainline
[perl5.git] / NetWare / NWUtil.c
CommitLineData
2986a63f
JH
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**/
49char *s1 = NULL; // Used in fnScanToken.
50char *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
68char *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
92char *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
117void 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
405void 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
91c54917
NIS
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:
2986a63f 477 // - Simple perl command like "perl" on the system console works fine for the first time.
91c54917
NIS
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.
2986a63f
JH
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
518char *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
578char *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
653char *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
685void 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
730char* 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';
78196db0 739 char letter1 = 'a';
2986a63f
JH
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
78196db0 758/**
1db1659f
JH
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)
78196db0
JH
769**/
770
2986a63f
JH
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
78196db0
JH
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
2986a63f
JH
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
826void 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