Chip noticed that the intended optionality of the 'IV' was
[p5sagit/p5-mst-13.2.git] / NetWare / nw5.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             :       nw5.c
12  * DESCRIPTION  :       Definitions for the redefined functions for NetWare.
13  * Author               :       SGP, HYAK
14  * Date                 :       January 2001.
15  *
16  */
17
18
19
20 #include <perl.h>       // For dTHX, etc.
21 #include "nwpipe.h"
22
23
24 // This was added since the compile failed saying "undefined P_WAIT"
25 // when USE_ITHREADS was commented in the makefile
26 #ifndef P_WAIT
27 #define P_WAIT          0
28 #endif
29
30 #ifndef P_NOWAIT
31 #define P_NOWAIT        1
32 #endif
33
34 #define EXECF_EXEC 1
35 #define EXECF_SPAWN 2
36 #define EXECF_SPAWN_NOWAIT 3
37
38 static BOOL has_shell_metachars(char *ptr);
39
40 // The array is used to store pointer to the memory allocated to the TempPipeFile structure everytime
41 // a call to the function, nw_Popen. If a simple variable is used, everytime the memory is allocated before
42 // the previously allocated memory is freed, the pointer will get overwritten and the previous memory allocations
43 // are lost! Only the most recent one will get freed when calls are made to nw_Pclose.
44 // By using the array and the iPopenCount to index the array, all memory are freed!
45
46 // The size of the array indicates the limit on the no of times the nw_Popen function can be called (and
47 // memory allocted) from within a script through backtick operators!
48 // This is arbitrarily set to MAX_PIPE_RECURSION=256 which indicates there can be 256 nested backtick operators possible!
49 PTEMPPIPEFILE ptpf1[MAX_PIPE_RECURSION] = {'\0'};
50 int iPopenCount = 0;
51 FILE* File1[MAX_PIPE_RECURSION] = {'\0'};
52
53 /**
54 General:
55
56 In this code, wherever there is a  FILE *, the error condition is checked; and only if the FILE * is TRUE,
57 then the corresponding operation is done. Otherwise the error value is returned.
58 This is done because the file operations like "open" in the Perl code returns the FILE *,
59 returning a valid value if the file is found or NULL when the particular file is not found.
60 Now, if the return value is NULL, then an operation say "fgets", "fopen" etc. using this this NULL value
61 for FILE * will abend the server. If the check is made then an operation on a non existing file
62 does not abend the server.
63 **/
64
65 void
66 nw_abort(void)
67 {
68         abort();        // Terminate the NLM application abnormally.
69         return;
70 }
71
72 int
73 nw_access(const char *path, int mode) 
74 {
75     return access(path, mode);
76 }
77
78 int
79 nw_chmod(const char *path, int mode)
80 {
81     return chmod(path, mode);
82 }
83
84 void
85 nw_clearerr(FILE *pf)
86 {
87         if(pf)
88             clearerr(pf);
89 }
90
91 int
92 nw_close(int fd)
93 {
94     return close(fd);
95 }
96
97 nw_closedir(DIR *dirp)
98 {
99         return (closedir(dirp));
100 }
101
102 void
103 nw_setbuf(FILE *pf, char *buf)
104 {
105         if(pf)
106             setbuf(pf, buf);
107 }
108
109 int
110 nw_setmode(FILE *fp, int mode)
111 {
112 /**
113         // Commented since a few abends were happening in fnFpSetMode
114         int *dummy = 0;
115         return(fnFpSetMode(fp, mode, dummy));
116 **/
117
118         int handle = -1;
119         errno = 0;
120
121         handle = fileno(fp);
122         if (errno)
123         {
124                 errno = 0;
125                 return -1;
126         }
127         return setmode(handle, mode);
128 }
129
130 int
131 nw_setvbuf(FILE *pf, char *buf, int type, size_t size)
132 {
133         if(pf)
134             return setvbuf(pf, buf, type, size);
135         else
136             return -1;
137 }
138
139
140 unsigned int
141 nw_sleep(unsigned int t)
142 {
143         delay(t*1000);  // Put the thread to sleep for 't' seconds.  Initially 't' is passed in milliseconds.
144     return 0;
145 }
146
147 int
148 nw_spawnvp(int mode, char *cmdname, char **argv)
149 {
150         // There is no pass-around environment on NetWare so we throw that
151         // argument away for now.
152
153         //  The function "spawnvp" does not work in all situations. Loading
154         // edit.nlm seems to work, for example, but the name of the file
155         // to edit does not appear to get passed correctly. Another problem
156         // is that on Netware, P_WAIT does not really work reliably. It only
157         // works with NLMs built to use CLIB (according to Nile Thayne).
158         // NLMs such as EDIT that are written directly to the system have no
159         // way of running synchronously from another process. The whole
160         // architecture on NetWare seems pretty busted, so we just support it
161         // as best we can.
162         //
163         // The spawnvp function only launches NLMs, it will not execute a command;
164         // the NetWare "system" function is used for that purpose. Unfortunately, "system"
165         // always returns success whether the command is successful or not or even
166         // if the command was not found! To avoid ambiguity--you can have both an
167         // NLM named "perl" and a system command named "perl"--we need to
168         // force perl scripts to carry the word "load" when loading an NLM. This
169         // might be clearer anyway.
170
171         int ret = 0;
172         int argc = 0;
173
174
175         if (stricmp(cmdname, LOAD_COMMAND) == 0)
176         {
177                 if (argv[1] != NULL)
178                         ret = spawnvp(mode, argv[1], &argv[1]);
179         }
180         else
181         {
182                 int i=0;
183                 while (argv[i] != '\0')
184                         i++;
185                 argc = i;
186
187                 fnSystemCommand(argv, argc);
188         }
189
190         return ret;
191 }
192
193 int
194 nw_execv(char *cmdname, char **argv)
195 {
196         return spawnvp(P_WAIT, cmdname, (char **)argv);
197 }
198
199
200 int
201 nw_execvp(char *cmdname, char **argv)
202 {
203         return nw_spawnvp(P_WAIT, cmdname, (char **)argv);
204 }
205
206 int
207 nw_stat(const char *path, struct stat *sbuf)
208 {
209         return (stat(path, sbuf));
210 }
211
212 FILE *
213 nw_stderr(void)
214 {
215         return (stderr);
216 }
217
218 FILE *
219 nw_stdin(void)
220 {
221         return (stdin);
222 }
223
224 FILE *
225 nw_stdout()
226 {
227         return (stdout);
228 }
229
230 long
231 nw_telldir(DIR *dirp)
232 {
233         dTHX;
234         Perl_croak(aTHX_ "The telldir() function is not implemented on NetWare\n");
235         return 0l;
236 }
237
238 int
239 nw_times(struct tms *timebuf)
240 {
241         clock_t now = clock();
242
243         timebuf->tms_utime = now;
244         timebuf->tms_stime = 0;
245         timebuf->tms_cutime = 0;
246         timebuf->tms_cstime = 0;
247
248         return 0;
249 }
250
251 FILE*
252 nw_tmpfile(void)
253 {
254     return tmpfile();
255 }
256
257 int
258 nw_uname(struct utsname *name)
259 {
260         return(uname(name));
261 }
262
263 int
264 nw_ungetc(int c, FILE *pf)
265 {
266         if(pf)
267             return ungetc(c, pf);
268         else
269             return -1;
270 }
271
272 int
273 nw_unlink(const char *filename)
274 {
275         return(unlink(filename));
276 }
277
278 int
279 nw_utime(const char *filename, struct utimbuf *times)
280 {
281          return(utime(filename, times));
282 }
283
284 int
285 nw_vfprintf(FILE *fp, const char *format, va_list args)
286 {
287         if(fp)
288             return (vfprintf(fp, format, args));
289         else
290             return -1;
291 }
292
293 int
294 nw_wait(int *status)
295 {
296     return 0;   
297 }
298
299 int
300 nw_waitpid(int pid, int *status, int flags)
301 {
302     return 0;   
303 }
304
305 int
306 nw_write(int fd, const void *buf, unsigned int cnt)
307 {
308     return write(fd, buf, cnt);
309 }
310
311 char *
312 nw_crypt(const char *txt, const char *salt)
313 {
314          dTHX;
315
316 #ifdef HAVE_DES_FCRYPT
317     dTHR;
318     return des_fcrypt(txt, salt, w32_crypt_buffer);
319 #else
320     Perl_croak(aTHX_ "The crypt() function is not implemented on NetWare\n");
321     return Nullch;
322 #endif
323 }
324
325 int
326 nw_dup(int fd)
327 {
328     return dup(fd);
329 }
330
331 int
332 nw_dup2(int fd1,int fd2)
333 {
334         return dup2(fd1,fd2);
335 }
336
337 void*
338 nw_dynaload(const char* filename)
339 {
340         return NULL;
341 }
342
343 int
344 nw_fclose(FILE *pf)
345 {
346         if(pf)
347             return (fclose(pf));
348         else
349             return -1;
350 }
351
352 FILE *
353 nw_fdopen(int handle, const char *mode)
354 {
355         return(fdopen(handle, mode));
356 }
357
358 int
359 nw_feof(FILE *fp)
360 {
361         if(fp)
362             return (feof(fp));
363         else
364             return -1;
365 }
366
367 int
368 nw_ferror(FILE *fp)
369 {
370         if(fp)
371             return (ferror(fp));
372         else
373             return -1;
374 }
375
376
377 int
378 nw_fflush(FILE *pf)
379 {
380         if(pf)
381             return fflush(pf);
382         else
383             return -1;
384 }
385
386 int
387 nw_fgetpos(FILE *pf, fpos_t *p)
388 {
389         if(pf)
390             return fgetpos(pf, p);
391         else
392             return -1;
393 }
394
395 char*
396 nw_fgets(char *s, int n, FILE *pf)
397 {
398         if(pf)
399             return(fgets(s, n, pf));
400         else
401             return NULL;
402 }
403
404 int
405 nw_fileno(FILE *pf)
406 {
407         if(pf)
408             return fileno(pf);
409         else
410             return -1;
411 }
412
413 int
414 nw_flock(int fd, int oper)
415 {
416         dTHX;
417         Perl_croak(aTHX_ "The flock() function is not implemented on NetWare\n");
418         return 0;
419 }
420
421
422 FILE *
423 nw_fopen(const char *filename, const char *mode)
424 {
425         return (fopen(filename, mode));
426 }
427
428 int
429 nw_fputc(int c, FILE *pf)
430 {
431         if(pf)
432             return fputc(c,pf);
433         else
434             return -1;
435 }
436
437 int
438 nw_fputs(const char *s, FILE *pf)
439 {
440         if(pf)
441             return fputs(s, pf);
442         else
443             return -1;
444 }
445
446 size_t
447 nw_fread(void *buf, size_t size, size_t count, FILE *fp)
448 {
449         if(fp)
450             return fread(buf, size, count, fp);
451         else
452             return -1;
453 }
454
455 FILE *
456 nw_freopen(const char *path, const char *mode, FILE *stream)
457 {
458         if(stream)
459             return freopen(path, mode, stream);
460         else
461             return NULL;
462 }
463
464 int
465 nw_fseek(FILE *pf, long offset, int origin)
466 {
467         if(pf)
468             return (fseek(pf, offset, origin));
469         else
470             return -1;
471 }
472
473 int
474 nw_fsetpos(FILE *pf, const fpos_t *p)
475 {
476         if(pf)
477             return fsetpos(pf, p);
478         else
479             return -1;
480 }
481
482 long
483 nw_ftell(FILE *pf)
484 {
485         if(pf)
486             return ftell(pf);
487         else
488             return -1;
489 }
490
491 size_t
492 nw_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
493 {
494         if(fp)
495             return fwrite(buf, size, count, fp);
496         else
497             return -1;
498 }
499
500 long
501 nw_get_osfhandle(int fd)
502 {
503         return 0l;
504 }
505
506 int
507 nw_getc(FILE *pf)
508 {
509         if(pf)
510             return getc(pf);
511         else
512             return -1;
513 }
514
515 int
516 nw_putc(int c, FILE *pf)
517 {
518         if(pf)
519             return putc(c,pf);
520         else
521             return -1;
522 }
523
524 int
525 nw_fgetc(FILE *pf)
526 {
527         if(pf)
528             return fgetc(pf);
529         else
530             return -1;
531 }
532
533 int
534 nw_getpid(void)
535 {
536         return GetThreadGroupID();
537 }
538
539 int
540 nw_kill(int pid, int sig)
541 {
542         return 0;
543 }
544
545 int
546 nw_link(const char *oldname, const char *newname)
547 {
548         return 0;
549 }
550
551 long
552 nw_lseek(int fd, long offset, int origin)
553 {
554     return lseek(fd, offset, origin);
555 }
556
557 int
558 nw_chdir(const char *dir)
559 {
560     return chdir(dir);
561 }
562
563 int
564 nw_rmdir(const char *dir)
565 {
566     return rmdir(dir);
567 }
568
569 DIR *
570 nw_opendir(char *filename)
571 {
572         char    *buff = NULL;
573         int             len = 0;
574         DIR             *ret = NULL;
575         
576         len = strlen(filename);
577         buff = malloc(len + 5);
578         if (buff) {
579                 strcpy(buff, filename);
580                 if (buff[len-1]=='/' || buff[len-1]=='\\') {
581                         buff[--len] = 0;
582                 }
583                 strcpy(buff+len, "/*.*");
584                 ret = opendir(buff);
585                 free (buff);
586                 buff = NULL;
587                 return ret;
588         } else {
589                 return NULL;
590         }
591 }
592
593 int
594 nw_open(const char *path, int flag, ...)
595 {
596         va_list ap;
597         int pmode = -1;
598
599         va_start(ap, flag);
600     pmode = va_arg(ap, int);
601     va_end(ap);
602
603         if (stricmp(path, "/dev/null")==0)
604         path = "NWNUL";
605
606         return open(path, flag, pmode);
607 }
608
609 int
610 nw_open_osfhandle(long handle, int flags)
611 {
612         return 0;
613 }
614
615 unsigned long
616 nw_os_id(void)
617 {
618         return 0l;
619 }
620
621 int nw_Pipe(int* a, int* e)
622 {
623         int ret = 0;
624
625         errno = 0;
626         ret = pipe(a);
627         if(errno)
628                 e = &errno;
629
630         return ret;
631 }
632
633 FILE* nw_Popen(char* command, char* mode, int* e)
634 {
635         int i = -1;
636
637         FILE* ret = NULL;
638         PTEMPPIPEFILE ptpf = NULL;
639
640         // this callback is supposed to call _popen, which spawns an
641         // asynchronous command and opens a pipe to it. The returned
642         // file handle can be read or written to; if read, it represents
643         // stdout of the called process and will return EOF when the
644         // called process finishes. If written to, it represents stdin
645         // of the called process. Naturally _popen is not available on
646         // NetWare so we must do some fancy stuff to simulate it. We will
647         // redirect to and from temp files; this has the side effect
648         // of having to run the process synchronously rather than
649         // asynchronously. This means that you will only be able to do
650         // this with CLIB NLMs built to run on the calling thread.
651
652         errno = 0;
653
654         ptpf1[iPopenCount] = (PTEMPPIPEFILE) malloc(sizeof(TEMPPIPEFILE));
655         if (!ptpf1[iPopenCount])
656                 return NULL;
657
658         ptpf = ptpf1[iPopenCount];
659         iPopenCount ++;
660         if(iPopenCount > MAX_PIPE_RECURSION)
661                 iPopenCount = MAX_PIPE_RECURSION;       // Limit to the max no of pipes to be open recursively.
662
663         fnTempPipeFile(ptpf);
664         ret = fnPipeFileOpen((PTEMPPIPEFILE) ptpf, (char *) command, (char *) mode);
665         if (ret)
666                 File1[iPopenCount-1] = ret;     // Store the obtained Pipe file handle.
667         else
668         {       // Pipe file not obtained. So free the allocated memory.
669                 if(ptpf1[iPopenCount-1])
670                 {
671                         free(ptpf1[iPopenCount-1]);
672                         ptpf1[iPopenCount-1] = NULL;
673                         ptpf = NULL;
674                         iPopenCount --;
675                 }
676         }
677
678         if (errno)
679                 e = &errno;
680
681         return ret;
682 }
683
684 int nw_Pclose(FILE* file, int* e)
685 {
686         int i=0, j=0;
687
688         errno = 0;
689
690         if(file)
691         {
692                 if(iPopenCount > 0)
693                 {
694                         for (i=0; i<iPopenCount; i++)
695                         {
696                                 if(File1[i] == file)
697                                 {
698                                         // Delete the memory allocated corresponding to the file handle passed-in and
699                                         // also close the file corresponding to the file handle passed-in!
700                                         if(ptpf1[i])
701                                         {
702                                                 fnPipeFileClose(ptpf1[i]);
703
704                                                 free(ptpf1[i]);
705                                                 ptpf1[i] = NULL;
706                                         }
707
708                                         fclose(File1[i]);
709                                         File1[i] = NULL;
710
711                                         break;
712                                 }
713                         }
714
715                         // Rearrange the file pointer array
716                         for(j=i; j<(iPopenCount-1); j++)
717                         {
718                                 File1[j] = File1[j+1];
719                                 ptpf1[j] = ptpf1[j+1];
720                         }
721                         iPopenCount--;
722                 }
723         }
724         else
725             return -1;
726
727         if (errno)
728                 e = &errno;
729
730         return 0;
731 }
732
733
734 int
735 nw_vprintf(const char *format, va_list args)
736 {
737     return (vprintf(format, args));
738 }
739
740 int
741 nw_printf(const char *format, ...)
742 {
743         
744         va_list marker;
745     va_start(marker, format);     /* Initialize variable arguments. */
746
747     return (vprintf(format, marker));
748 }
749
750 int
751 nw_read(int fd, void *buf, unsigned int cnt)
752 {
753         return read(fd, buf, cnt);
754 }
755
756 struct direct *
757 nw_readdir(DIR *dirp)
758 {
759         DIR* ret=NULL;
760
761         ret = readdir(dirp);
762         if(ret)
763                 return((struct direct *)ret);
764         return NULL;
765 }
766
767 int
768 nw_rename(const char *oname, const char *newname)
769 {
770         return(rename(oname,newname));
771 }
772
773 void
774 nw_rewinddir(DIR *dirp)
775 {
776         dTHX;
777         Perl_croak(aTHX_ "The rewinddir() function is not implemented on NetWare\n");
778 }
779
780 void
781 nw_rewind(FILE *pf)
782 {
783         if(pf)
784             rewind(pf);
785 }
786
787 void
788 nw_seekdir(DIR *dirp, long loc)
789 {
790         dTHX;
791         Perl_croak(aTHX_ "The seekdir() function is not implemented on NetWare\n");
792 }
793
794 int *
795 nw_errno(void)
796 {
797     return (&errno);
798 }
799
800 char ***
801 nw_environ(void)
802 {
803         return ((char ***)nw_getenviron());
804 }
805
806 char *
807 nw_strerror(int e)
808 {
809         return (strerror(e));
810 }
811
812 int
813 nw_isatty(int fd)
814 {
815         return(isatty(fd));
816 }
817
818 char *
819 nw_mktemp(char *Template)
820 {
821         return (fnMy_MkTemp(Template));
822 }
823
824 int
825 nw_chsize(int handle, long size)
826 {
827         return(chsize(handle,size));
828 }
829
830 #ifdef HAVE_INTERP_INTERN
831 void
832 sys_intern_init(pTHX)
833 {
834
835 }
836
837 void
838 sys_intern_clear(pTHX)
839 {
840
841 }
842
843 void
844 sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
845 {
846
847 }
848 #endif  /* HAVE_INTERP_INTERN */
849
850 void
851 Perl_init_os_extras(void)
852 {
853     
854 }
855
856 void
857 Perl_nw5_init(int *argcp, char ***argvp)
858 {
859     MALLOC_INIT;
860 }
861
862 #ifdef USE_ITHREADS
863 PerlInterpreter *
864 perl_clone_host(PerlInterpreter* proto_perl, UV flags)
865 {
866         // Perl Clone is not implemented on NetWare.
867     return NULL;
868 }
869 #endif
870
871 // Some more functions:
872
873 char *
874 nw_get_sitelib(const char *pl)
875 {
876     return (NULL);
877 }
878
879 int
880 execv(char *cmdname, char **argv)
881 {
882         // This feature needs to be implemented.
883         // _asm is commented out since it goes into the internal debugger.
884 //      _asm {int 3};
885         return(0);
886 }
887
888 int
889 execvp(char *cmdname, char **argv)
890 {
891         // This feature needs to be implemented.
892         // _asm is commented out since it goes into the internal debugger.
893 //      _asm {int 3};
894         return(0);
895 }
896
897 int
898 do_aspawn(void *vreally, void **vmark, void **vsp)
899 {
900         // This feature needs to be implemented.
901         // _asm is commented out since it goes into the internal debugger.
902 //      _asm {int 3};
903 ////    return(0);
904
905
906         // This below code is required for system() call.
907         // Otherwise system() does not work on NetWare.
908         // Ananth, 3 Sept 2001
909
910     dTHX;
911     SV *really = (SV*)vreally;
912     SV **mark = (SV**)vmark;
913     SV **sp = (SV**)vsp;
914     char **argv;
915     char *str;
916     int status;
917     int flag = P_WAIT;
918     int index = 0;
919
920
921     if (sp <= mark)
922         return -1;
923
924         nw_perlshell_items = 0; // No Shell
925 //    New(1306, argv, (sp - mark) + nw_perlshell_items + 3, char*);     // In the old code of 5.6.1
926     New(1306, argv, (sp - mark) + nw_perlshell_items + 2, char*);
927
928     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
929         ++mark;
930         flag = SvIVx(*mark);
931     }
932
933     while (++mark <= sp) {
934         if (*mark && (str = (char *)SvPV_nolen(*mark)))
935         {
936             argv[index] = str;
937                 index++;
938         }
939         else
940         {
941                 argv[index] = "";
942 //              argv[index] = '\0';
943                 index++;
944     }
945         }
946     argv[index] = '\0';
947         index++;
948
949     status = nw_spawnvp(flag,
950                            (char*)(really ? SvPV_nolen(really) : argv[0]),
951                            (char**)argv);
952
953     if (flag != P_NOWAIT) {
954         if (status < 0) {
955 //          dTHR;       // Only in old code of 5.6.1
956             if (ckWARN(WARN_EXEC))
957                 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
958             status = 255 * 256;
959         }
960         else
961             status *= 256;
962         PL_statusvalue = status;
963     }
964
965     Safefree(argv);
966     return (status);
967 }
968
969 int
970 do_spawn2(char *cmd, int exectype)
971 {
972         // This feature needs to be implemented.
973         // _asm is commented out since it goes into the internal debugger.
974 //      _asm {int 3};
975 ////    return(0);
976
977         // Below added to make system() work for NetWare
978
979     dTHX;
980     char **a;
981     char *s;
982     char **argv;
983     int status = -1;
984     BOOL needToTry = TRUE;
985     char *cmd2;
986
987     /* Save an extra exec if possible. See if there are shell
988      * metacharacters in it */
989     if (!has_shell_metachars(cmd)) {
990         New(1301,argv, strlen(cmd) / 2 + 2, char*);
991         New(1302,cmd2, strlen(cmd) + 1, char);
992         strcpy(cmd2, cmd);
993         a = argv;
994         for (s = cmd2; *s;) {
995             while (*s && isSPACE(*s))
996                 s++;
997             if (*s)
998                 *(a++) = s;
999             while (*s && !isSPACE(*s))
1000                 s++;
1001             if (*s)
1002                 *s++ = '\0';
1003         }
1004         *a = Nullch;
1005         if (argv[0]) {
1006             switch (exectype) {
1007                         case EXECF_SPAWN:
1008                                 status = nw_spawnvp(P_WAIT, argv[0], (char **)argv);
1009                                 break;
1010
1011                         case EXECF_SPAWN_NOWAIT:
1012                                 status = nw_spawnvp(P_NOWAIT, argv[0], (char **)argv);
1013                                 break;
1014
1015                         case EXECF_EXEC:
1016                                 status = nw_execvp(argv[0], (char **)argv);
1017                                 break;
1018             }
1019             if (status != -1 || errno == 0)
1020                 needToTry = FALSE;
1021         }
1022         Safefree(argv);
1023         Safefree(cmd2);
1024     }
1025
1026     if (needToTry) {
1027         char **argv = NULL;
1028         int i = -1;
1029
1030         New(1306, argv, nw_perlshell_items + 2, char*);
1031         while (++i < nw_perlshell_items)
1032             argv[i] = nw_perlshell_vec[i];
1033         argv[i++] = cmd;
1034         argv[i] = Nullch;
1035         switch (exectype) {
1036                 case EXECF_SPAWN:
1037                         status = nw_spawnvp(P_WAIT, argv[0], (char **)argv);
1038                         break;
1039
1040                 case EXECF_SPAWN_NOWAIT:
1041                         status = nw_spawnvp(P_NOWAIT, argv[0], (char **)argv);
1042                         break;
1043
1044                 case EXECF_EXEC:
1045                         status = nw_execvp(argv[0], (char **)argv);
1046                         break;
1047         }
1048         cmd = argv[0];
1049         Safefree(argv);
1050     }
1051
1052     if (exectype != EXECF_SPAWN_NOWAIT) {
1053         if (status < 0) {
1054             dTHR;
1055             if (ckWARN(WARN_EXEC))
1056                 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
1057                      (exectype == EXECF_EXEC ? "exec" : "spawn"),
1058                      cmd, strerror(errno));
1059             status = 255 * 256;
1060         }
1061         else
1062             status *= 256;
1063         PL_statusvalue = status;
1064     }
1065     return (status);
1066 }
1067
1068 int
1069 do_spawn(char *cmd)
1070 {
1071     return do_spawn2(cmd, EXECF_SPAWN);
1072 }
1073
1074 // Added to make system() work for NetWare
1075 static BOOL
1076 has_shell_metachars(char *ptr)
1077 {
1078     int inquote = 0;
1079     char quote = '\0';
1080
1081     /*
1082      * Scan string looking for redirection (< or >) or pipe
1083      * characters (|) that are not in a quoted string.
1084      * Shell variable interpolation (%VAR%) can also happen inside strings.
1085      */
1086     while (*ptr) {
1087         switch(*ptr) {
1088         case '%':
1089             return TRUE;
1090         case '\'':
1091         case '\"':
1092             if (inquote) {
1093                 if (quote == *ptr) {
1094                     inquote = 0;
1095                     quote = '\0';
1096                 }
1097             }
1098             else {
1099                 quote = *ptr;
1100                 inquote++;
1101             }
1102             break;
1103         case '>':
1104         case '<':
1105         case '|':
1106             if (!inquote)
1107                 return TRUE;
1108         default:
1109             break;
1110         }
1111         ++ptr;
1112     }
1113     return FALSE;
1114 }
1115
1116 int
1117 fork(void)
1118 {
1119         return 0;
1120 }
1121
1122
1123 // added to remove undefied symbol error in CodeWarrior compilation
1124 int
1125 Perl_Ireentrant_buffer_ptr(aTHX)
1126 {
1127         return 0;
1128 }