oops.. only build it when it _is_ valid.
[AROS-Contrib.git] / regina / os_amiga.c
blob20464839424e4a6be3f8b798965ccdfc2a343380
1 #include "rexx.h"
3 #include <proto/alib.h>
4 #include <proto/exec.h>
5 #include <proto/dos.h>
6 #include <proto/utility.h>
7 #include <utility/tagitem.h>
8 #include <dos/dos.h>
9 #include <dos/dostags.h>
10 #include <dos/dosextens.h>
11 #include <exec/memory.h>
12 #include <exec/io.h>
13 #include <exec/lists.h>
14 #include <exec/nodes.h>
16 #include <assert.h>
17 #include <errno.h>
19 #include <stdlib.h>
21 #ifdef __AROS__
23 #define DEBUG 0
24 #include <aros/debug.h>
26 #else
28 #define D(x)
29 #ifndef BNULL
30 #define BNULL ((BPTR)NULL)
31 #endif
33 #endif
35 typedef struct {
36 const tsd_t *TSD;
37 struct Task *parent, *child;
38 BYTE psigbit, csigbit;
39 environment *parentenv;
40 const char *childcmd;
41 int retval;
42 } ChildInfo;
44 typedef enum {
45 PIPE_READ, PIPE_WRITE
46 } AmigaPipeType;
48 typedef struct {
49 AmigaPipeType type;
50 BPTR file;
51 } AmigaPipeInfo;
53 /* On amiga(-like) systems the pipe used for communicating
54 is asynchronous from itself and does not to be handled
55 by custom code.
57 static void *Amiga_create_async_info(const tsd_t *TSD)
59 D(bug("[Amiga_create_async_info] TSD=%p\n", TSD));
61 /* Amiga pipes are async */
62 return NULL;
65 static void Amiga_delete_async_info(void *async_info)
67 D(bug("[Amiga_delete_async_info] async_info=%p\n", async_info));
68 /* Amiga pipes are async */
71 /* Reset FHI_WAIT flag */
72 static void Amiga_reset_async_info(void *async_info)
74 D(bug("[Amiga_reset_async_info] async_info=%p\n", async_info));
75 /* Amiga pipes are async */
78 /* Mark handle to wait for it */
79 static void Amiga_add_async_waiter(void *async_info, int handle, int add_as_read_handle)
81 /* Amiga pipes are async */
84 /* For a subprocess connection on amiga a pipe will be opened
85 and both read and write ends will be stored.
86 Only a read or write handle will be returned depending on wether
87 this connection is input or output.
88 We can't just cast a BPTR to int in this function as on some archs
89 sizeof(int) < sizeof(void *).
91 static int Amiga_open_subprocess_connection(const tsd_t *TSD, environpart *ep)
93 AmigaPipeInfo *pipein, *pipeout;
94 int hndlin, hndlout;
96 D(bug("[Amiga_open_subprocess_connection] Entering\n"));
98 pipein = malloc(sizeof(AmigaPipeInfo));
99 if(pipein == NULL)
101 errno = ENOMEM;
102 return -1;
104 pipein->type = PIPE_READ;
105 pipein->file = BNULL;
107 pipeout = malloc(sizeof(AmigaPipeInfo));
108 if(pipeout == NULL)
110 errno = ENOMEM;
111 return -1;
113 pipeout->type = PIPE_WRITE;
114 pipeout->file = BNULL;
116 hndlin = __amiga_ptr2int(TSD, pipein);
117 hndlout = __amiga_ptr2int(TSD, pipeout);
118 if (hndlin == -1 || hndlout == -1)
120 free(pipein);
121 free(pipeout);
122 errno = ENOMEM;
123 return -1;
126 ep->hdls[0] = hndlin;
127 ep->hdls[1] = hndlout;
129 return 0;
132 /* First abort pending IOs, then close filehandle */
133 static int Amiga_close(int handle, void *async_info)
135 const tsd_t *TSD = GLOBAL_ENTRY_POINT();
136 AmigaPipeInfo *pipe = __amiga_getptr( TSD, handle );
138 D(bug("[Amiga_close] handle=%d\n", handle));
140 if(pipe->file != BNULL)
141 Close(pipe->file);
142 __amiga_clearptr(TSD, handle);
143 free(pipe);
145 return 0;
148 /* We don't have special filehandles */
149 static void Amiga_close_special( int handle )
151 assert( handle == -1 );
155 /* Amiga uses pipes so cannot restart file */
156 static void Amiga_restart_file(int handle)
158 assert( handle == -1 );
161 static void Amiga_unblock_handle(int *handle, void *async_info)
163 /* All handles are non-blocking on AROS => do nothing */
166 static int Amiga_read(int handle, void *buf, unsigned size, void *async_info)
168 const tsd_t *TSD = GLOBAL_ENTRY_POINT();
169 AmigaPipeInfo *pipe = __amiga_getptr( TSD, handle );
170 int retval;
172 D(bug("[Amiga_read] hndl=%d\n"));
174 assert(pipe->type == PIPE_READ);
175 assert(pipe->file != BNULL);
177 retval = Read( pipe->file, buf, size );
178 if( retval < 0 )
179 retval = -EACCES;
181 D(bug("[Amiga_read] retval=%d\n", retval));
183 return retval;
186 static int Amiga_write(int handle, const void *buf, unsigned size, void *async_info)
188 const tsd_t *TSD = GLOBAL_ENTRY_POINT();
189 AmigaPipeInfo *pipe = __amiga_getptr( TSD, handle );
190 int retval;
192 D(bug("[Amiga_write] hndl=%d\n"));
194 assert(pipe->type == PIPE_WRITE);
195 assert(pipe->file != BNULL);
197 retval = Write( pipe->file, buf, size );
198 if( retval < 0 )
199 retval = -EACCES;
201 D(bug("[Amiga_write] retval=%d\n", retval));
203 return retval;
207 static void Amiga_wait_async_info(void *async_info)
209 /* Amiga pipes are async */
212 GLOBAL_PROTECTION_VAR(startcommand)
213 static ChildInfo *childinfo;
215 static void StartCommand(void)
217 ChildInfo *info = childinfo;
218 char *cmd;
219 struct Library *UtilityBase;
220 struct DosLibrary *DOSBase;
222 D(bug("[Startcommand]: Entering\n"));
224 DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0);
226 info->child = FindTask(NULL);
227 info->csigbit = AllocSignal(-1);
228 cmd = AllocVec(strlen(info->childcmd)+1, MEMF_PUBLIC|MEMF_CLEAR);
229 strcpy(cmd, info->childcmd);
230 D(bug("[Startcommand]: cmd='%s'\n", cmd));
232 D(bug("[Startcommand]: Signaling parent\n"));
233 Signal(info->parent, 1<<info->psigbit);
234 D(bug("[Startcommand]: Waiting for parent\n"));
235 Wait(1<<info->csigbit);
236 FreeSignal(info->csigbit);
238 UtilityBase = OpenLibrary("utility.library", 0);
239 if (UtilityBase == NULL)
241 FreeVec(cmd);
242 info->retval = 20;
243 Signal(info->parent, 1<<info->psigbit);
244 CloseLibrary((struct Library *)DOSBase);
245 return;
248 info->retval = SystemTags(cmd, NP_Synchronous, TRUE, TAG_DONE, NULL);
249 D(bug("[Startcommand]: retval=%d\n", info->retval));
250 FreeVec(cmd);
252 CloseLibrary(UtilityBase);
254 D(bug("[Startcommand]: Signaling parent\n"));
255 Signal(info->parent, 1<<info->psigbit);
257 CloseLibrary((struct Library *)DOSBase);
260 static int Amiga_fork_exec(tsd_t *TSD, environment *env, const char *cmdline, int *rcode)
262 switch (env->subtype)
264 case SUBENVIR_PATH:
265 case SUBENVIR_COMMAND:
266 case SUBENVIR_SYSTEM:
268 ChildInfo *info = malloc( sizeof(ChildInfo) );
269 char buff[32];
270 int inhndl = env->input.hdls[1],
271 outhndl = env->output.hdls[0],
272 errhndl = env->error.hdls[0];
273 BPTR sub_input = BNULL, sub_output = BNULL, sub_error = BNULL;
274 BOOL close_input, close_output, close_error;
275 AmigaPipeInfo *pipe = NULL;
276 int proc;
277 struct Process *me = (struct Process *)FindTask(NULL);
279 D(bug("[Amiga_fork_exec]: Entering cmdline='%s'\n", cmdline));
281 if( info == NULL )
283 errno = ENOMEM;
284 return -1;
287 proc = __amiga_ptr2int( TSD, info );
288 D(bug("[Amiga_fork_exec]: Got proc=%d\n", proc));
289 if ( proc < 0 )
291 errno = ENOMEM;
292 free( info );
293 return -1;
296 info->psigbit = AllocSignal(-1);
297 if (info->psigbit < 0)
299 errno = ECHILD;
300 return -1;
302 info->parent = FindTask(NULL);
303 info->parentenv = env;
304 info->childcmd = cmdline;
306 if(inhndl != -1)
308 pipe = (AmigaPipeInfo *)__amiga_getptr(TSD, inhndl);
309 /* Regina will write into input of subcommand */
310 assert(pipe->type == PIPE_WRITE);
312 snprintf(buff, sizeof(buff), "PIPE:rexx-%p-in", me);
313 pipe->file = Open(buff, MODE_NEWFILE);
314 if (pipe->file != BNULL)
316 /* Input() of subcommand with read from pipe */
317 sub_input = Open(buff, MODE_OLDFILE);
318 if(sub_input == BNULL)
320 errno = ENOMEM;
321 Close(pipe->file);
322 pipe->file = BNULL;
323 return -1;
326 else
328 errno = EACCES;
329 return -1;
332 close_input = TRUE;
334 else
336 sub_input = Input();
337 close_input = FALSE;
340 if(outhndl != -1)
342 pipe = (AmigaPipeInfo *)__amiga_getptr(TSD, outhndl);
343 /* Regina will read output of subcommand */
344 assert(pipe->type == PIPE_READ);
346 snprintf(buff, sizeof(buff), "PIPE:rexx-%p-out", me);
347 /* Output() of subcommand will write in pipe */
348 sub_output = Open(buff, MODE_NEWFILE);
349 if (sub_output != BNULL)
351 pipe->file = Open(buff, MODE_OLDFILE);
352 if(pipe->file == BNULL)
354 errno = ENOMEM;
355 Close(pipe->file);
356 pipe->file = BNULL;
357 return -1;
360 else
362 errno = EACCES;
363 return -1;
366 close_output = TRUE;
368 else
370 sub_output = Output();
371 close_output = FALSE;
374 if(errhndl != -1)
376 pipe = (AmigaPipeInfo *)__amiga_getptr(TSD, errhndl);
377 /* Regina will read error output of subcommand */
378 assert(pipe->type == PIPE_READ);
380 snprintf(buff, sizeof(buff), "PIPE:rexx-%p-err", me);
381 /* Error() of subcommand will write in pipe */
382 sub_error = Open(buff, MODE_NEWFILE);
383 if (sub_error != BNULL)
385 pipe->file = Open(buff, MODE_OLDFILE);
386 if(pipe->file == BNULL)
388 errno = ENOMEM;
389 Close(pipe->file);
390 pipe->file = BNULL;
391 return -1;
394 else
396 errno = EACCES;
397 return -1;
400 close_error = TRUE;
402 else
404 sub_error = me->pr_CES;
405 close_error = FALSE;
408 THREAD_PROTECT(startcommand)
409 childinfo = info;
411 D(bug("[Amiga_fork_exec]: Starting command\n"));
413 CreateNewProcTags
415 NP_Entry, StartCommand,
416 NP_Input, sub_input, NP_CloseInput, close_input,
417 NP_Output, sub_output, NP_CloseOutput, close_output,
418 NP_Error, sub_error, NP_CloseError, close_error,
419 NP_Cli, TRUE,
420 TAG_DONE, NULL
422 D(bug("[Amiga_fork_exec]: Waiting child cache of info\n"));
423 Wait(1<<info->psigbit);
424 THREAD_UNPROTECT(startcommand)
425 D(bug("[Amiga_fork_exec]: Signaling child\n"));
426 Signal(info->child, 1<<info->csigbit);
428 D(bug("[Amiga_fork_exec]: Returning proc=%d\n", proc));
429 return proc;
431 break;
433 case SUBENVIR_REXX:
434 errno = ENOSYS;
435 return -1;
438 errno = ENOSYS;
439 return -1;
442 static int Amiga_wait(int process)
444 const tsd_t *TSD = GLOBAL_ENTRY_POINT();
445 ChildInfo *info = __amiga_getptr( TSD, process );
446 int retval;
448 D(bug("[Amiga_wait] Waiting for child\n"));
450 Wait( 1<<info->psigbit );
451 retval = info->retval;
452 FreeSignal( info->psigbit );
453 info->psigbit = -1;
454 __amiga_clearptr( TSD, process );
455 free( info );
457 D(bug("[Amiga_wait] retval=%d\n", retval));
459 return retval;
462 static void Amiga_init(void)
466 static int Amiga_setenv(const char *name, const char *value)
468 return setenv(name, value, 1);
471 #include "utsname.h"
473 static int Amiga_uname(struct regina_utsname *name)
475 strcpy( name->sysname, "AMIGA" );
476 sprintf( name->version, "%d", 0 );
477 sprintf( name->release, "%d", 0 );
478 strcpy( name->nodename, "standalone" );
479 #ifdef __PPC__
480 strcpy( name->machine, "ppc" );
481 #else
482 strcpy( name->machine, "i386" );
483 #endif
485 return 0;
488 OS_Dep_funcs __regina_OS_Amiga =
490 Amiga_init, /* init */
491 Amiga_setenv, /* setenv */
492 Amiga_fork_exec, /* fork_exec */
493 Amiga_wait, /* wait */
494 Amiga_open_subprocess_connection, /* open_subprocess_connection */
495 Amiga_unblock_handle, /* unblock_handle */
496 Amiga_restart_file, /* restart_file */
497 Amiga_close, /* close */
498 Amiga_close_special, /* close_special */
499 Amiga_read, /* read */
500 Amiga_write, /* write */
501 Amiga_create_async_info, /* create_async_info */
502 Amiga_delete_async_info, /* delete_async_info */
503 Amiga_reset_async_info, /* reset_async_info */
504 Amiga_add_async_waiter, /* add_async_waiter */
505 Amiga_wait_async_info, /* wait_async_info */
506 Amiga_uname /* uname */