This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
amigaos4: minimized config.sh
[perl5.git] / amigaos4 / amigaos.c
CommitLineData
a83a2cd1
AB
1/* amigaos.c uses only amigaos APIs,
2 * as opposed to amigaio.c which mixes amigaos and perl APIs */
3
4#include <string.h>
5
6#include <sys/stat.h>
7#include <unistd.h>
8#include <assert.h>
9
10#include <errno.h>
11#include <stdio.h>
12#include <stdlib.h>
13#if defined(__CLIB2__)
14# include <dos.h>
15#endif
16#if defined(__NEWLIB__)
17# include <amiga_platform.h>
18#endif
19#include <fcntl.h>
20#include <ctype.h>
21#include <stdarg.h>
22
23#include <dos/dos.h>
24#include <proto/dos.h>
25#include <proto/exec.h>
26#include <proto/utility.h>
27
28#include "amigaos.h"
29
30struct UtilityIFace *IUtility = NULL;
31
32/***************************************************************************/
33
34struct Interface *OpenInterface(CONST_STRPTR libname, uint32 libver)
35{
36 struct Library *base = IExec->OpenLibrary(libname, libver);
37 struct Interface *iface = IExec->GetInterface(base, "main", 1, NULL);
38 if (iface == NULL)
39 {
40 // We should probably post some kind of error message here.
41
42 IExec->CloseLibrary(base);
43 }
44
45 return iface;
46}
47
48/***************************************************************************/
49
50void CloseInterface(struct Interface *iface)
51{
52 if (iface != NULL)
53 {
54 struct Library *base = iface->Data.LibBase;
55 IExec->DropInterface(iface);
56 IExec->CloseLibrary(base);
57 }
58}
59
60BOOL __unlink_retries = FALSE;
61
62void ___makeenviron() __attribute__((constructor));
63void ___freeenviron() __attribute__((destructor));
64
65void ___openinterfaces() __attribute__((constructor));
66void ___closeinterfaces() __attribute__((destructor));
67
68void ___openinterfaces()
69{
70 if (!IDOS)
71 IDOS = (struct DOSIFace *)OpenInterface("dos.library", 53);
72 if (!IUtility)
73 IUtility =
74 (struct UtilityIFace *)OpenInterface("utility.library", 53);
75}
76
77void ___closeinterfaces()
78{
79 CloseInterface((struct Interface *)IDOS);
80 CloseInterface((struct Interface *)IUtility);
81}
82int VARARGS68K araddebug(UBYTE *fmt, ...);
83int VARARGS68K adebug(UBYTE *fmt, ...);
84
85#define __USE_RUNCOMMAND__
86
87char **myenviron = NULL;
88char **origenviron = NULL;
89
90int myexecve(const char *path, char *argv[], char *envp[]);
91static void createvars(char **envp);
92
93struct args
94{
95 BPTR seglist;
96 int stack;
97 char *command;
98 int length;
99 int result;
100 char **envp;
101};
102
103int __myrc(char *arg)
104{
105 struct Task *thisTask = IExec->FindTask(0);
106 struct args *myargs = (struct args *)thisTask->tc_UserData;
107 if (myargs->envp)
108 createvars(myargs->envp);
109 // adebug("%s %ld %s \n",__FUNCTION__,__LINE__,myargs->command);
110 myargs->result = IDOS->RunCommand(myargs->seglist, myargs->stack,
111 myargs->command, myargs->length);
112 return 0;
113}
114
115int32 myruncommand(
116 BPTR seglist, int stack, char *command, int length, char **envp)
117{
118 struct args myargs;
119 struct Task *thisTask = IExec->FindTask(0);
120 struct Process *proc;
121
122 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
123
124 myargs.seglist = seglist;
125 myargs.stack = stack;
126 myargs.command = command;
127 myargs.length = length;
128 myargs.result = -1;
129 myargs.envp = envp;
130
131 if ((proc = IDOS->CreateNewProcTags(
132 NP_Entry, __myrc, NP_Child, TRUE, NP_Input, IDOS->Input(),
133 NP_Output, IDOS->Output(), NP_Error, IDOS->ErrorOutput(),
134 NP_CloseInput, FALSE, NP_CloseOutput, FALSE, NP_CloseError,
135 FALSE, NP_CopyVars, FALSE,
136
137 // NP_StackSize, ((struct Process
138 // *)myargs.parent)->pr_StackSize,
139 NP_Cli, TRUE, NP_UserData, (int)&myargs,
140 NP_NotifyOnDeathSigTask, thisTask, TAG_DONE)))
141
142 {
143 IExec->Wait(SIGF_CHILD);
144 }
145 return myargs.result;
146}
147
148static char *mystrdup(const char *s)
149{
150 char *result = NULL;
151 size_t size;
152
153 size = strlen(s) + 1;
154
155 if ((result = (char *)IExec->AllocVec(size, MEMF_ANY)))
156 {
157 memmove(result, s, size);
158 }
159 return result;
160}
161
162static int pipenum = 0;
163
164int pipe(int filedes[2])
165{
166 char pipe_name[1024];
167
168// adebug("%s %ld \n",__FUNCTION__,__LINE__);
169#ifdef USE_TEMPFILES
170 sprintf(pipe_name, "/T/%x.%08lx", pipenum++, IUtility->GetUniqueID());
171#else
172 sprintf(pipe_name, "/PIPE/%x%08lx/4096/0", pipenum++,
173 IUtility->GetUniqueID());
174#endif
175
176 /* printf("pipe: %s \n", pipe_name);*/
177
178 filedes[1] = open(pipe_name, O_WRONLY | O_CREAT);
179 filedes[0] = open(pipe_name, O_RDONLY);
180 if (filedes[0] == -1 || filedes[1] == -1)
181 {
182 if (filedes[0] != -1)
183 close(filedes[0]);
184 if (filedes[1] != -1)
185 close(filedes[1]);
186 return -1;
187 }
188 /* printf("filedes %d %d\n", filedes[0],
189 * filedes[1]);fflush(stdout);*/
190
191 return 0;
192}
193
194int fork(void)
195{
196 fprintf(stderr, "Can not bloody fork\n");
197 errno = ENOMEM;
198 return -1;
199}
200
201int wait(int *status)
202{
203 fprintf(stderr, "No wait try waitpid instead\n");
204 errno = ECHILD;
205 return -1;
206}
207
208char *convert_path_a2u(const char *filename)
209{
210 struct NameTranslationInfo nti;
211
212 if (!filename)
213 {
214 return 0;
215 }
216
217 __translate_amiga_to_unix_path_name(&filename, &nti);
218
219 return mystrdup(filename);
220}
221char *convert_path_u2a(const char *filename)
222{
223 struct NameTranslationInfo nti;
224
225 if (!filename)
226 {
227 return 0;
228 }
229
230 if (strcmp(filename, "/dev/tty") == 0)
231 {
232 return mystrdup("CONSOLE:");
233 ;
234 }
235
236 __translate_unix_to_amiga_path_name(&filename, &nti);
237
238 return mystrdup(filename);
239}
240
241static struct SignalSemaphore environ_sema;
242
243void amigaos4_init_environ_sema() { IExec->InitSemaphore(&environ_sema); }
244
245void amigaos4_obtain_environ() { IExec->ObtainSemaphore(&environ_sema); }
246
247void amigaos4_release_environ() { IExec->ReleaseSemaphore(&environ_sema); }
248
249static void createvars(char **envp)
250{
251 if (envp)
252 {
253 /* Set a local var to indicate to any subsequent sh that it is
254 * not
255 * the top level shell and so should only inherit local amigaos
256 * vars */
257 IDOS->SetVar("ABCSH_IMPORT_LOCAL", "TRUE", 5, GVF_LOCAL_ONLY);
258
259 amigaos4_obtain_environ();
260
261 envp = myenviron;
262
263 while ((envp != NULL) && (*envp != NULL))
264 {
265 int len;
266 char *var;
267 char *val;
268 if ((len = strlen(*envp)))
269 {
270 if ((var = (char *)IExec->AllocVec(
271 len + 1, MEMF_ANY | MEMF_CLEAR)))
272 {
273 strcpy(var, *envp);
274
275 val = strchr(var, '=');
276 if (val)
277 {
278 *val++ = '\0';
279 if (*val)
280 {
281 IDOS->SetVar(
282 var, val,
283 strlen(val) + 1,
284 GVF_LOCAL_ONLY);
285 }
286 }
287 IExec->FreeVec(var);
288 }
289 }
290 envp++;
291 }
292 amigaos4_release_environ();
293 }
294}
295
296static BOOL contains_whitespace(char *string)
297{
298
299 if (string)
300 {
301
302 if (strchr(string, ' '))
303 return TRUE;
304 if (strchr(string, '\t'))
305 return TRUE;
306 if (strchr(string, '\n'))
307 return TRUE;
308 if (strchr(string, 0xA0))
309 return TRUE;
310 if (strchr(string, '"'))
311 return TRUE;
312 }
313 return FALSE;
314}
315
316static int no_of_escapes(char *string)
317{
318 int cnt = 0;
319 char *p;
320 for (p = string; p < string + strlen(string); p++)
321 {
322 if (*p == '"')
323 cnt++;
324 if (*p == '*')
325 cnt++;
326 if (*p == '\n')
327 cnt++;
328 if (*p == '\t')
329 cnt++;
330 }
331 return cnt;
332}
333
334struct command_data
335{
336 STRPTR args;
337 BPTR seglist;
338 struct Task *parent;
339};
340
341int myexecvp(const char *filename, char *argv[])
342{
343 // adebug("%s %ld
344 //%s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
345 /* if there's a slash or a colon consider filename a path and skip
346 * search */
347 int res;
348 if ((strchr(filename, '/') == NULL) && (strchr(filename, ':') == NULL))
349 {
350 char *path;
351 char *name;
352 char *pathpart;
353 char *p;
354 size_t len;
355 struct stat st;
356
357 if (!(path = getenv("PATH")))
358 {
359 path = ".:/bin:/usr/bin:/c";
360 }
361
362 len = strlen(filename) + 1;
363 name = (char *)alloca(strlen(path) + len);
364 pathpart = (char *)alloca(strlen(path) + 1);
365 p = path;
366 do
367 {
368 path = p;
369
370 if (!(p = strchr(path, ':')))
371 {
372 p = strchr(path, '\0');
373 }
374
375 memcpy(pathpart, path, p - path);
376 pathpart[p - path] = '\0';
377 if (!(strlen(pathpart) == 0))
378 {
379 sprintf(name, "%s/%s", pathpart, filename);
380 }
381 else
382 sprintf(name, "%s", filename);
383
384 if ((stat(name, &st) == 0) && (S_ISREG(st.st_mode)))
385 {
386 /* we stated it and it's a regular file */
387 /* let's boogie! */
388 filename = name;
389 break;
390 }
391
392 } while (*p++ != '\0');
393 }
394 res = myexecve(filename, argv, myenviron);
395 return res;
396}
397
398int myexecv(const char *path, char *argv[])
399{
400 return myexecve(path, argv, myenviron);
401}
402
403int myexecl(const char *path, ...)
404{
405 va_list va;
406 char *argv[1024]; /* 1024 enough? let's hope so! */
407 int i = 0;
408 // adebug("%s %ld\n",__FUNCTION__,__LINE__);
409
410 va_start(va, path);
411 i = 0;
412
413 do
414 {
415 argv[i] = va_arg(va, char *);
416 } while (argv[i++] != NULL);
417
418 va_end(va);
419 return myexecve(path, argv, myenviron);
420}
421
422int myexecve(const char *filename, char *argv[], char *envp[])
423{
424 FILE *fh;
425 char buffer[1000];
426 int size = 0;
427 char **cur;
428 char *interpreter = 0;
429 char *interpreter_args = 0;
430 char *full = 0;
431 char *filename_conv = 0;
432 char *interpreter_conv = 0;
433 // char *tmp = 0;
434 char *fname;
435 // int tmpint;
436 // struct Task *thisTask = IExec->FindTask(0);
437 int result = -1;
438
439 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,filename?filename:"NULL");
440
441 /* Calculate the size of filename and all args, including spaces and
442 * quotes */
443 size = 0; // strlen(filename) + 1;
444 for (cur = (char **)argv /* +1 */; *cur; cur++)
445 {
446 size +=
447 strlen(*cur) + 1 +
448 (contains_whitespace(*cur) ? (2 + no_of_escapes(*cur)) : 0);
449 }
450 /* Check if it's a script file */
451
452 fh = fopen(filename, "r");
453 if (fh)
454 {
455 if (fgetc(fh) == '#' && fgetc(fh) == '!')
456 {
457 char *p;
458 char *q;
459 fgets(buffer, 999, fh);
460 p = buffer;
461 while (*p == ' ' || *p == '\t')
462 p++;
463 if (buffer[strlen(buffer) - 1] == '\n')
464 buffer[strlen(buffer) - 1] = '\0';
465 if ((q = strchr(p, ' ')))
466 {
467 *q++ = '\0';
468 if (*q != '\0')
469 {
470 interpreter_args = mystrdup(q);
471 }
472 }
473 else
474 interpreter_args = mystrdup("");
475
476 interpreter = mystrdup(p);
477 size += strlen(interpreter) + 1;
478 size += strlen(interpreter_args) + 1;
479 }
480
481 fclose(fh);
482 }
483 else
484 {
485 /* We couldn't open this why not? */
486 if (errno == ENOENT)
487 {
488 /* file didn't exist! */
489 return -1;
490 }
491 }
492
493 /* Allocate the command line */
494 filename_conv = convert_path_u2a(filename);
495
496 if (filename_conv)
497 size += strlen(filename_conv);
498 size += 1;
499 full = (char *)IExec->AllocVec(size + 10, MEMF_ANY | MEMF_CLEAR);
500 if (full)
501 {
502 if (interpreter)
503 {
504 interpreter_conv = convert_path_u2a(interpreter);
505#if !defined(__USE_RUNCOMMAND__)
506#warning(using system!)
507 sprintf(full, "%s %s %s ", interpreter_conv,
508 interpreter_args, filename_conv);
509#else
510 sprintf(full, "%s %s ", interpreter_args,
511 filename_conv);
512#endif
513 IExec->FreeVec(interpreter);
514 IExec->FreeVec(interpreter_args);
515
516 if (filename_conv)
517 IExec->FreeVec(filename_conv);
518 fname = mystrdup(interpreter_conv);
519
520 if (interpreter_conv)
521 IExec->FreeVec(interpreter_conv);
522 }
523 else
524 {
525#ifndef __USE_RUNCOMMAND__
526 sprintf(full, "%s ", filename_conv);
527#else
528 sprintf(full, "");
529#endif
530 fname = mystrdup(filename_conv);
531 if (filename_conv)
532 IExec->FreeVec(filename_conv);
533 }
534
535 for (cur = (char **)(argv + 1); *cur != 0; cur++)
536 {
537 if (contains_whitespace(*cur))
538 {
539 int esc = no_of_escapes(*cur);
540
541 if (esc > 0)
542 {
543 char *buff = IExec->AllocVec(
544 strlen(*cur) + 4 + esc,
545 MEMF_ANY | MEMF_CLEAR);
546 char *p = *cur;
547 char *q = buff;
548
549 *q++ = '"';
550 while (*p != '\0')
551 {
552
553 if (*p == '\n')
554 {
555 *q++ = '*';
556 *q++ = 'N';
557 p++;
558 continue;
559 }
560 else if (*p == '"')
561 {
562 *q++ = '*';
563 *q++ = '"';
564 p++;
565 continue;
566 }
567 else if (*p == '*')
568 {
569 *q++ = '*';
570 }
571 *q++ = *p++;
572 }
573 *q++ = '"';
574 *q++ = ' ';
575 *q = '\0';
576 strcat(full, buff);
577 IExec->FreeVec(buff);
578 }
579 else
580 {
581 strcat(full, "\"");
582 strcat(full, *cur);
583 strcat(full, "\" ");
584 }
585 }
586 else
587 {
588 strcat(full, *cur);
589 strcat(full, " ");
590 }
591 }
592 strcat(full, "\n");
593
594// if(envp)
595// createvars(envp);
596
597#ifndef __USE_RUNCOMMAND__
598 result = IDOS->SystemTags(
599 full, SYS_UserShell, TRUE, NP_StackSize,
600 ((struct Process *)thisTask)->pr_StackSize, SYS_Input,
601 ((struct Process *)thisTask)->pr_CIS, SYS_Output,
602 ((struct Process *)thisTask)->pr_COS, SYS_Error,
603 ((struct Process *)thisTask)->pr_CES, TAG_DONE);
604#else
605
606 if (fname)
607 {
608 BPTR seglist = IDOS->LoadSeg(fname);
609 if (seglist)
610 {
611 /* check if we have an executable! */
612 struct PseudoSegList *ps = NULL;
613 if (!IDOS->GetSegListInfoTags(
614 seglist, GSLI_Native, &ps, TAG_DONE))
615 {
616 IDOS->GetSegListInfoTags(
617 seglist, GSLI_68KPS, &ps, TAG_DONE);
618 }
619 if (ps != NULL)
620 {
621 // adebug("%s %ld %s
622 // %s\n",__FUNCTION__,__LINE__,fname,full);
623 IDOS->SetCliProgramName(fname);
624 // result=RunCommand(seglist,8*1024,full,strlen(full));
625 // result=myruncommand(seglist,8*1024,full,strlen(full),envp);
626 result = myruncommand(seglist, 8 * 1024,
627 full, -1, envp);
628 errno = 0;
629 }
630 else
631 {
632 errno = ENOEXEC;
633 }
634 IDOS->UnLoadSeg(seglist);
635 }
636 else
637 {
638 errno = ENOEXEC;
639 }
640 IExec->FreeVec(fname);
641 }
642
643#endif /* USE_RUNCOMMAND */
644
645 IExec->FreeVec(full);
646 if (errno == ENOEXEC)
647 return -1;
648 return result;
649 }
650
651 if (interpreter)
652 IExec->FreeVec(interpreter);
653 if (filename_conv)
654 IExec->FreeVec(filename_conv);
655
656 errno = ENOMEM;
657
658 return -1;
659}
660
661int pause(void)
662{
663 fprintf(stderr, "Pause not implemented\n");
664
665 errno = EINTR;
666 return -1;
667}
668
669uint32 size_env(struct Hook *hook, APTR userdata, struct ScanVarsMsg *message)
670{
671 if (strlen(message->sv_GDir) <= 4)
672 {
673 hook->h_Data = (APTR)(((uint32)hook->h_Data) + 1);
674 }
675 return 0;
676}
677
678uint32 copy_env(struct Hook *hook, APTR userdata, struct ScanVarsMsg *message)
679{
680 if (strlen(message->sv_GDir) <= 4)
681 {
682 char **env = (char **)hook->h_Data;
683 uint32 size =
684 strlen(message->sv_Name) + 1 + message->sv_VarLen + 1 + 1;
685 char *buffer = (char *)IExec->AllocVec((uint32)size,
686 MEMF_ANY | MEMF_CLEAR);
687
688 snprintf(buffer, size - 1, "%s=%s", message->sv_Name,
689 message->sv_Var);
690
691 *env = buffer;
692 env++;
693 hook->h_Data = env;
694 }
695 return 0;
696}
697
698void ___makeenviron()
699{
700 struct Hook hook;
701
702 char varbuf[8];
703 uint32 flags = 0;
704
705 struct DOSIFace *myIDOS =
706 (struct DOSIFace *)OpenInterface("dos.library", 53);
707 if (myIDOS)
708 {
709 if (myIDOS->GetVar("ABCSH_IMPORT_LOCAL", varbuf, 8,
710 GVF_LOCAL_ONLY) > 0)
711 {
712 flags = GVF_LOCAL_ONLY;
713 }
714 else
715 {
716 flags = GVF_GLOBAL_ONLY;
717 }
718
719 hook.h_Entry = size_env;
720 hook.h_Data = 0;
721
722 myIDOS->ScanVars(&hook, flags, 0);
723 hook.h_Data = (APTR)(((uint32)hook.h_Data) + 1);
724
725 myenviron = (char **)IExec->AllocVec((uint32)hook.h_Data *
726 sizeof(char **),
727 MEMF_ANY | MEMF_CLEAR);
728 origenviron = myenviron;
729 if (!myenviron)
730 {
731 return;
732 }
733 hook.h_Entry = copy_env;
734 hook.h_Data = myenviron;
735
736 myIDOS->ScanVars(&hook, flags, 0);
737 CloseInterface((struct Interface *)myIDOS);
738 }
739}
740
741void ___freeenviron()
742{
743 char **i;
744 /* perl might change environ, it puts it back except for ctrl-c */
745 /* so restore our own copy here */
746 struct DOSIFace *myIDOS =
747 (struct DOSIFace *)OpenInterface("dos.library", 53);
748 if (myIDOS)
749 {
750 myenviron = origenviron;
751
752 if (myenviron)
753 {
754 for (i = myenviron; *i != NULL; i++)
755 {
756 IExec->FreeVec(*i);
757 }
758 IExec->FreeVec(myenviron);
759 myenviron = NULL;
760 }
761 CloseInterface((struct Interface *)myIDOS);
762 }
763}
764
765/* reimplementation of popen, clib2's doesn't do all we want */
766
767static BOOL is_final_quote_character(const char *str)
768{
769 BOOL result;
770
771 result = (BOOL)(str[0] == '\"' && (str[1] == '\0' || isspace(str[1])));
772
773 return (result);
774}
775
776static BOOL is_final_squote_character(const char *str)
777{
778 BOOL result;
779
780 result = (BOOL)(str[0] == '\'' && (str[1] == '\0' || isspace(str[1])));
781
782 return (result);
783}
784
785int popen_child()
786{
787 struct Task *thisTask = IExec->FindTask(0);
788
789 char *command = (char *)thisTask->tc_UserData;
790 size_t len;
791 char *str;
792 int argc;
793 int number_of_arguments;
794 char *argv[4];
795
796 argv[0] = "sh";
797 argv[1] = "-c";
798 argv[2] = command ? command : NULL;
799 argv[3] = NULL;
800
801 // adebug("%s %ld %s\n",__FUNCTION__,__LINE__,command?command:"NULL");
802
803 /* We need to give this to sh via execvp, execvp expects filename,
804 * argv[]
805 */
806
807 myexecvp(argv[0], argv);
808 if (command)
809 IExec->FreeVec(command);
810
811 IExec->Forbid();
812 return 0;
813}
814
815FILE *amigaos_popen(const char *cmd, const char *mode)
816{
817 FILE *result = NULL;
818 char pipe_name[50];
819 char unix_pipe[50];
820 char ami_pipe[50];
821 char *cmd_copy;
822 BPTR input = 0;
823 BPTR output = 0;
824 struct Process *proc = NULL;
825 struct Task *thisTask = IExec->FindTask(0);
826
827 /* First we need to check the mode
828 * We can only have unidirectional pipes
829 */
830 // adebug("%s %ld cmd %s mode %s \n",__FUNCTION__,__LINE__,cmd,
831 // mode);
832
833 switch (mode[0])
834 {
835 case 'r':
836 case 'w':
837 break;
838
839 default:
840
841 errno = EINVAL;
842 return result;
843 }
844
845 /* Make a unique pipe name
846 * we need a unix one and an amigaos version (of the same pipe!)
847 * as were linking with libunix.
848 */
849
850 sprintf(pipe_name, "%x%08lx/4096/0", pipenum++,
851 IUtility->GetUniqueID());
852 sprintf(unix_pipe, "/PIPE/%s", pipe_name);
853 sprintf(ami_pipe, "PIPE:%s", pipe_name);
854
855 /* Now we open the AmigaOs Filehandles That we wil pass to our
856 * Sub process
857 */
858
859 if (mode[0] == 'r')
860 {
861 /* A read mode pipe: Output from pipe input from NIL:*/
862 input = IDOS->Open("NIL:", MODE_NEWFILE);
863 if (input != 0)
864 {
865 output = IDOS->Open(ami_pipe, MODE_NEWFILE);
866 }
867 }
868 else
869 {
870
871 input = IDOS->Open(ami_pipe, MODE_NEWFILE);
872 if (input != 0)
873 {
874 output = IDOS->Open("NIL:", MODE_NEWFILE);
875 }
876 }
877 if ((input == 0) || (output == 0))
878 {
879 /* Ouch stream opening failed */
880 /* Close and bail */
881 if (input)
882 IDOS->Close(input);
883 if (output)
884 IDOS->Close(output);
885 return result;
886 }
887
888 /* We have our streams now start our new process
889 * We're using a new process so that execve can modify the environment
890 * with messing things up for the shell that launched perl
891 * Copy cmd before we launch the subprocess as perl seems to waste
892 * no time in overwriting it! The subprocess will free the copy.
893 */
894
895 if ((cmd_copy = mystrdup(cmd)))
896 {
897 // adebug("%s %ld
898 // %s\n",__FUNCTION__,__LINE__,cmd_copy?cmd_copy:"NULL");
899 proc = IDOS->CreateNewProcTags(
900 NP_Entry, popen_child, NP_Child, TRUE, NP_StackSize,
901 ((struct Process *)thisTask)->pr_StackSize, NP_Input, input,
902 NP_Output, output, NP_Error, IDOS->ErrorOutput(),
903 NP_CloseError, FALSE, NP_Cli, TRUE, NP_Name,
904 "Perl: popen process", NP_UserData, (int)cmd_copy,
905 TAG_DONE);
906 }
907 if (!proc)
908 {
909 /* New Process Failed to start
910 * Close and bail out
911 */
912 if (input)
913 IDOS->Close(input);
914 if (output)
915 IDOS->Close(output);
916 if (cmd_copy)
917 IExec->FreeVec(cmd_copy);
918 }
919
920 /* Our new process is running and will close it streams etc
921 * once its done. All we need to is open the pipe via stdio
922 */
923
924 return fopen(unix_pipe, mode);
925}
926
927/* Work arround for clib2 fstat */
928#ifndef S_IFCHR
929#define S_IFCHR 0x0020000
930#endif
931
932#define SET_FLAG(u, v) ((void)((u) |= (v)))
933
934int afstat(int fd, struct stat *statb)
935{
936 int result;
937 BPTR fh;
938 int mode;
939 BOOL input;
940 /* In the first instance pass it to fstat */
941 // adebug("fd %ld ad %ld\n",fd,amigaos_get_file(fd));
942
943 if ((result = fstat(fd, statb) >= 0))
944 return result;
945
946/* Now we've got a file descriptor but we failed to stat it */
947/* Could be a nil: or could be a std#? */
948
949/* if get_default_file fails we had a dud fd so return failure */
950#if !defined(__CLIB2__)
951
952 fh = amigaos_get_file(fd);
953
954 /* if nil: return failure*/
955 if (fh == 0)
956 return -1;
957
958 /* Now compare with our process Input() Output() etc */
959 /* if these were regular files sockets or pipes we had already
960 * succeeded */
961 /* so we can guess they a character special console.... I hope */
962
963 struct ExamineData *data;
964 char name[120];
965 name[0] = '\0';
966
967 data = IDOS->ExamineObjectTags(EX_FileHandleInput, fh, TAG_END);
968 if (data != NULL)
969 {
970
971 IUtility->Strlcpy(name, data->Name, sizeof(name));
972
973 IDOS->FreeDosObject(DOS_EXAMINEDATA, data);
974 }
975
976 // adebug("ad %ld '%s'\n",amigaos_get_file(fd),name);
977 mode = S_IFCHR;
978
979 if (fh == IDOS->Input())
980 {
981 input = TRUE;
982 SET_FLAG(mode, S_IRUSR);
983 SET_FLAG(mode, S_IRGRP);
984 SET_FLAG(mode, S_IROTH);
985 }
986 else if (fh == IDOS->Output() || fh == IDOS->ErrorOutput())
987 {
988 input = FALSE;
989 SET_FLAG(mode, S_IWUSR);
990 SET_FLAG(mode, S_IWGRP);
991 SET_FLAG(mode, S_IWOTH);
992 }
993 else
994 {
995 /* we got a filehandle not handle by fstat or the above */
996 /* most likely it's NIL: but lets check */
997 struct ExamineData *exd = NULL;
998 if ((exd = IDOS->ExamineObjectTags(EX_FileHandleInput, fh,
999 TAG_DONE)))
1000 {
1001 BOOL isnil = FALSE;
1002 if (exd->Type ==
1003 (20060920)) // Ugh yes I know nasty.....
1004 {
1005 isnil = TRUE;
1006 }
1007 IDOS->FreeDosObject(DOS_EXAMINEDATA, exd);
1008 if (isnil)
1009 {
1010 /* yep we got NIL: */
1011 SET_FLAG(mode, S_IRUSR);
1012 SET_FLAG(mode, S_IRGRP);
1013 SET_FLAG(mode, S_IROTH);
1014 SET_FLAG(mode, S_IWUSR);
1015 SET_FLAG(mode, S_IWGRP);
1016 SET_FLAG(mode, S_IWOTH);
1017 }
1018 else
1019 {
1020 IExec->DebugPrintF(
1021 "unhandled filehandle in afstat()\n");
1022 return -1;
1023 }
1024 }
1025 }
1026
1027 memset(statb, 0, sizeof(statb));
1028
1029 statb->st_mode = mode;
1030
1031#endif
1032 return 0;
1033}
1034
1035BPTR amigaos_get_file(int fd)
1036{
1037 BPTR fh = (BPTR)NULL;
1038 if (!(fh = _get_osfhandle(fd)))
1039 {
1040 switch (fd)
1041 {
1042 case 0:
1043 fh = IDOS->Input();
1044 break;
1045 case 1:
1046 fh = IDOS->Output();
1047 break;
1048 case 2:
1049 fh = IDOS->ErrorOutput();
1050 break;
1051 default:
1052 break;
1053 }
1054 }
1055 return fh;
1056}