Remove trailing space from perlipc.pod.
[perl.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 NULL;
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(const 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     PERL_ARGS_ASSERT_SYS_INTERN_DUP;
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 int
874 execv(char *cmdname, char **argv)
875 {
876         // This feature needs to be implemented.
877         // _asm is commented out since it goes into the internal debugger.
878 //      _asm {int 3};
879         return(0);
880 }
881
882 int
883 execvp(char *cmdname, char **argv)
884 {
885         // This feature needs to be implemented.
886         // _asm is commented out since it goes into the internal debugger.
887 //      _asm {int 3};
888         return(0);
889 }
890
891 int
892 do_aspawn(void *vreally, void **vmark, void **vsp)
893 {
894         // This feature needs to be implemented.
895         // _asm is commented out since it goes into the internal debugger.
896 //      _asm {int 3};
897 ////    return(0);
898
899
900         // This below code is required for system() call.
901         // Otherwise system() does not work on NetWare.
902         // Ananth, 3 Sept 2001
903
904     dTHX;
905     SV *really = (SV*)vreally;
906     SV **mark = (SV**)vmark;
907     SV **sp = (SV**)vsp;
908     char **argv;
909     char *str;
910     int status;
911     int flag = P_WAIT;
912     int index = 0;
913
914
915     if (sp <= mark)
916         return -1;
917
918         nw_perlshell_items = 0; // No Shell
919 //    Newx(argv, (sp - mark) + nw_perlshell_items + 3, char*);  // In the old code of 5.6.1
920     Newx(argv, (sp - mark) + nw_perlshell_items + 2, char*);
921
922     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
923         ++mark;
924         flag = SvIVx(*mark);
925     }
926
927     while (++mark <= sp) {
928         if (*mark && (str = (char *)SvPV_nolen(*mark)))
929         {
930             argv[index] = str;
931                 index++;
932         }
933         else
934         {
935                 argv[index] = "";
936 //              argv[index] = '\0';
937                 index++;
938     }
939         }
940     argv[index] = '\0';
941         index++;
942
943     status = nw_spawnvp(flag,
944                            (char*)(really ? SvPV_nolen(really) : argv[0]),
945                            (char**)argv);
946
947     if (flag != P_NOWAIT) {
948         if (status < 0) {
949 //          dTHR;       // Only in old code of 5.6.1
950             if (ckWARN(WARN_EXEC))
951                 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
952             status = 255 * 256;
953         }
954         else
955             status *= 256;
956         PL_statusvalue = status;
957     }
958
959     Safefree(argv);
960     return (status);
961 }
962
963 int
964 do_spawn2(char *cmd, int exectype)
965 {
966         // This feature needs to be implemented.
967         // _asm is commented out since it goes into the internal debugger.
968 //      _asm {int 3};
969 ////    return(0);
970
971         // Below added to make system() work for NetWare
972
973     dTHX;
974     char **a;
975     char *s;
976     char **argv;
977     int status = -1;
978     BOOL needToTry = TRUE;
979     char *cmd2;
980
981     /* Save an extra exec if possible. See if there are shell
982      * metacharacters in it */
983     if (!has_shell_metachars(cmd)) {
984         Newx(argv, strlen(cmd) / 2 + 2, char*);
985         Newx(cmd2, strlen(cmd) + 1, char);
986         strcpy(cmd2, cmd);
987         a = argv;
988         for (s = cmd2; *s;) {
989             while (*s && isSPACE(*s))
990                 s++;
991             if (*s)
992                 *(a++) = s;
993             while (*s && !isSPACE(*s))
994                 s++;
995             if (*s)
996                 *s++ = '\0';
997         }
998         *a = NULL;
999         if (argv[0]) {
1000             switch (exectype) {
1001                         case EXECF_SPAWN:
1002                                 status = nw_spawnvp(P_WAIT, argv[0], (char **)argv);
1003                                 break;
1004
1005                         case EXECF_SPAWN_NOWAIT:
1006                                 status = nw_spawnvp(P_NOWAIT, argv[0], (char **)argv);
1007                                 break;
1008
1009                         case EXECF_EXEC:
1010                                 status = nw_execvp(argv[0], (char **)argv);
1011                                 break;
1012             }
1013             if (status != -1 || errno == 0)
1014                 needToTry = FALSE;
1015         }
1016         Safefree(argv);
1017         Safefree(cmd2);
1018     }
1019
1020     if (needToTry) {
1021         char **argv = NULL;
1022         int i = -1;
1023
1024         Newx(argv, nw_perlshell_items + 2, char*);
1025         while (++i < nw_perlshell_items)
1026             argv[i] = nw_perlshell_vec[i];
1027         argv[i++] = cmd;
1028         argv[i] = NULL;
1029         switch (exectype) {
1030                 case EXECF_SPAWN:
1031                         status = nw_spawnvp(P_WAIT, argv[0], (char **)argv);
1032                         break;
1033
1034                 case EXECF_SPAWN_NOWAIT:
1035                         status = nw_spawnvp(P_NOWAIT, argv[0], (char **)argv);
1036                         break;
1037
1038                 case EXECF_EXEC:
1039                         status = nw_execvp(argv[0], (char **)argv);
1040                         break;
1041         }
1042         cmd = argv[0];
1043         Safefree(argv);
1044     }
1045
1046     if (exectype != EXECF_SPAWN_NOWAIT) {
1047         if (status < 0) {
1048             dTHR;
1049             if (ckWARN(WARN_EXEC))
1050                 Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
1051                      (exectype == EXECF_EXEC ? "exec" : "spawn"),
1052                      cmd, strerror(errno));
1053             status = 255 * 256;
1054         }
1055         else
1056             status *= 256;
1057         PL_statusvalue = status;
1058     }
1059     return (status);
1060 }
1061
1062 int
1063 do_spawn(char *cmd)
1064 {
1065     return do_spawn2(cmd, EXECF_SPAWN);
1066 }
1067
1068 // Added to make system() work for NetWare
1069 static BOOL
1070 has_shell_metachars(char *ptr)
1071 {
1072     int inquote = 0;
1073     char quote = '\0';
1074
1075     /*
1076      * Scan string looking for redirection (< or >) or pipe
1077      * characters (|) that are not in a quoted string.
1078      * Shell variable interpolation (%VAR%) can also happen inside strings.
1079      */
1080     while (*ptr) {
1081         switch(*ptr) {
1082         case '%':
1083             return TRUE;
1084         case '\'':
1085         case '\"':
1086             if (inquote) {
1087                 if (quote == *ptr) {
1088                     inquote = 0;
1089                     quote = '\0';
1090                 }
1091             }
1092             else {
1093                 quote = *ptr;
1094                 inquote++;
1095             }
1096             break;
1097         case '>':
1098         case '<':
1099         case '|':
1100             if (!inquote)
1101                 return TRUE;
1102         default:
1103             break;
1104         }
1105         ++ptr;
1106     }
1107     return FALSE;
1108 }
1109
1110 int
1111 fork(void)
1112 {
1113         return 0;
1114 }
1115
1116
1117 // added to remove undefied symbol error in CodeWarrior compilation
1118 int
1119 Perl_Ireentrant_buffer_ptr(aTHX)
1120 {
1121         return 0;
1122 }