[BACK]Return to amiga.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gnuplot

Annotation of OpenXM_contrib/gnuplot/amiga.c, Revision 1.1

1.1     ! maekawa     1: /* $Id: amiga.c,v 1.3 1998/03/22 22:31:17 drd Exp $ */
        !             2:
        !             3: /* GNUPLOT - amiga.c */
        !             4:
        !             5: /*[
        !             6:  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
        !             7:  *
        !             8:  * Permission to use, copy, and distribute this software and its
        !             9:  * documentation for any purpose with or without fee is hereby granted,
        !            10:  * provided that the above copyright notice appear in all copies and
        !            11:  * that both that copyright notice and this permission notice appear
        !            12:  * in supporting documentation.
        !            13:  *
        !            14:  * Permission to modify the software is granted, but not the right to
        !            15:  * distribute the complete modified source code.  Modifications are to
        !            16:  * be distributed as patches to the released version.  Permission to
        !            17:  * distribute binaries produced by compiling modified sources is granted,
        !            18:  * provided you
        !            19:  *   1. distribute the corresponding source modifications from the
        !            20:  *    released version in the form of a patch file along with the binaries,
        !            21:  *   2. add special version identification to distinguish your version
        !            22:  *    in addition to the base release version number,
        !            23:  *   3. provide your name and address as the primary contact for the
        !            24:  *    support of your modified version, and
        !            25:  *   4. retain our contact information in regard to use of the base
        !            26:  *    software.
        !            27:  * Permission to distribute the released version of the source code along
        !            28:  * with corresponding source modifications in the form of a patch file is
        !            29:  * granted with same provisions 2 through 4 for binary distributions.
        !            30:  *
        !            31:  * This software is provided "as is" without express or implied warranty
        !            32:  * to the extent permitted by applicable law.
        !            33: ]*/
        !            34:
        !            35: /*
        !            36:  * amiga.c
        !            37:  *
        !            38:  * Written by Carsten Steger <stegerc@informatik.tu-muenchen.de>
        !            39:  *
        !            40:  * Popen and pclose have the same semantics as their UNIX counterparts.
        !            41:  *
        !            42:  * Additionally, they install an exit trap that closes all open pipes,
        !            43:  * should the program terminate abnormally.
        !            44:  */
        !            45:
        !            46:
        !            47: #include <stdio.h>
        !            48: #include <ios1.h>
        !            49: #include <error.h>
        !            50: #include <string.h>
        !            51: #include <stdlib.h>
        !            52:
        !            53: #include <exec/types.h>
        !            54: #include <dos/dos.h>
        !            55: #include <dos/dosextens.h>
        !            56: #include <dos/dostags.h>
        !            57: #include <proto/exec.h>
        !            58: #include <proto/dos.h>
        !            59:
        !            60: #ifdef PIPES  /* dont bother if pipes are not being used elsewhere */
        !            61:
        !            62: /* Maximum number of open pipes. If this is set to a number > 10, the code
        !            63:  * that constructs the pipe names in popen () will have to be modified.
        !            64:  */
        !            65: #define MAX_OPEN_PIPES 10
        !            66:
        !            67: /* We need at least this Dos version to work. */
        !            68: #define DOS_VERSION 37
        !            69:
        !            70:
        !            71: /* This data structure is sent to the child process with sm_Cmd set to the
        !            72:  * command to be executed. When the child is done it sets sm_RetCode to
        !            73:  * the return code of the executed command.
        !            74:  */
        !            75: struct StartupMessage {
        !            76:   struct Message sm_Msg;
        !            77:   LONG sm_RetCode;
        !            78:   UBYTE *sm_Cmd;
        !            79: };
        !            80:
        !            81: /* We keep track of the open pipe through this data structure. */
        !            82: struct PipeFileDescriptor {
        !            83:   FILE *pfd_File;
        !            84:   struct StartupMessage pfd_Msg;
        !            85: };
        !            86:
        !            87:
        !            88: /* Needed to check for the required Dos version. */
        !            89: extern struct DosLibrary *DOSBase;
        !            90:
        !            91: /* This data structure keeps track of the pipes that are still open. */
        !            92: static struct PipeFileDescriptor OpenPipes[MAX_OPEN_PIPES];
        !            93:
        !            94: /* The address of the process that calls popen or pclose. */
        !            95: static struct Process *ThisProcess;
        !            96:
        !            97: /* Are we called for the first time? */
        !            98: static LONG FirstCall = TRUE;
        !            99:
        !           100:
        !           101: /* Prototypes for the functions below. */
        !           102: FILE *popen (const char *command, const char *mode);
        !           103: int pclose (FILE *stream);
        !           104: static void CleanUpPipes (void);
        !           105: static int __saveds ChildEntry (void);
        !           106:
        !           107:
        !           108: FILE *popen (command, mode)
        !           109: const char *command;
        !           110: const char *mode;
        !           111: {
        !           112:   UBYTE PipeName[16];
        !           113:   ULONG ProcAddress;
        !           114:   UBYTE HexDigit;
        !           115:   UBYTE *NextChar;
        !           116:   struct CommandLineInterface *ThisCli;
        !           117:   struct PipeFileDescriptor *PipeToUse;
        !           118:   LONG PipeNumToUse;
        !           119:   LONG ChildPipeMode;
        !           120:   BPTR ChildPipe;
        !           121:   FILE *ParentPipe;
        !           122:   struct Process *ChildProcess;
        !           123:   struct TagItem NewProcTags[8] = {
        !           124:     {NP_Entry, (Tag) ChildEntry},
        !           125:     {NP_Cli, TRUE},
        !           126:     {NP_StackSize, 4096},
        !           127:     {NP_Input, NULL},
        !           128:     {NP_Output, NULL},
        !           129:     {NP_CloseInput, FALSE},
        !           130:     {NP_CloseOutput, FALSE},
        !           131:     {TAG_DONE, 0}
        !           132:   };
        !           133:
        !           134:   /* Test whether we're using the right Dos version. */
        !           135:   if (DOSBase->dl_lib.lib_Version < DOS_VERSION) {
        !           136:     errno = EPIPE;
        !           137:     return NULL;
        !           138:   }
        !           139:
        !           140:   /* If we're called for the first time, install exit trap and do some
        !           141:    * initialisation stuff.
        !           142:    */
        !           143:   if (FirstCall) {
        !           144:     /* Initialise pipe file descriptor table. */
        !           145:     memset (OpenPipes, 0, sizeof (OpenPipes));
        !           146:
        !           147:     /* Install our exit trap. */
        !           148:     if (atexit (CleanUpPipes) != 0) {
        !           149:       errno = EPIPE;
        !           150:       return NULL;
        !           151:     }
        !           152:     FirstCall = FALSE;
        !           153:   }
        !           154:
        !           155:   /* If we don't know our process' address yet, we should get it now. */
        !           156:   if (ThisProcess == NULL)
        !           157:     ThisProcess = (struct Process *) FindTask (NULL);
        !           158:
        !           159:   /* Get our Cli structure. */
        !           160:   ThisCli = Cli ();
        !           161:
        !           162:   /* Now try to find an empty slot in the pipe file descriptor table.
        !           163:    * Return NULL if no slot is available.
        !           164:    */
        !           165:   for (PipeNumToUse = 0; PipeNumToUse < MAX_OPEN_PIPES; PipeNumToUse++)
        !           166:     if (OpenPipes[PipeNumToUse].pfd_File == NULL) break;
        !           167:   if (PipeNumToUse >= MAX_OPEN_PIPES) {
        !           168:     errno = EMFILE;
        !           169:     return NULL;
        !           170:   }
        !           171:   PipeToUse = &OpenPipes[PipeNumToUse];
        !           172:
        !           173:   /* Check if the specified mode is valid. */
        !           174:   if (strcmp (mode, "r") == 0)
        !           175:     ChildPipeMode = MODE_NEWFILE;
        !           176:   else if (strcmp (mode, "w") == 0)
        !           177:     ChildPipeMode = MODE_OLDFILE;
        !           178:   else {
        !           179:     errno = EINVAL;
        !           180:     return NULL;
        !           181:   }
        !           182:
        !           183:   /* Make a unique file name for the pipe that we are about to open. The
        !           184:    * file name has the following format: "PIPE:XXXXXXXX_Y", where
        !           185:    * XXXXXXXX is the address of our process in hex, Y is the number of the
        !           186:    * slot in the pipe descriptor table that we will use. The code is
        !           187:    * equivalent to
        !           188:    * sprintf (PipeNameWriter, "PIPE:%08lX_%1d", ThisProcess, PipeNumToUse);
        !           189:    * but it doesn't need sprintf and therefore makes programs that don't
        !           190:    * use printf a lot shorter.
        !           191:    */
        !           192:   strcpy (PipeName, "PIPE:00000000_0");
        !           193:   NextChar = PipeName + 12;
        !           194:   ProcAddress = (ULONG) ThisProcess;
        !           195:   while (ProcAddress != 0) {
        !           196:     HexDigit = (UBYTE) ProcAddress & 0xf;
        !           197:     HexDigit = HexDigit < 10 ? HexDigit + '0' : HexDigit - 10 + 'A';
        !           198:     *NextChar-- = HexDigit;
        !           199:     ProcAddress >>= 4;
        !           200:   }
        !           201:   /* If MAX_OPEN_PIPES > 10, this will have to be modified. */
        !           202:   PipeName[14] = ((UBYTE) PipeNumToUse) + '0';
        !           203:
        !           204:   /* Create tags for the child process. */
        !           205:   if (ThisProcess->pr_CLI)
        !           206:     NewProcTags[2].ti_Data = ThisCli->cli_DefaultStack << 2;
        !           207:   else
        !           208:     NewProcTags[2].ti_Data = ThisProcess->pr_StackSize;
        !           209:
        !           210:   /* Open both ends of the pipe. The child's side is opened with Open (),
        !           211:    * while the parent's side is opened with fopen ().
        !           212:    */
        !           213:   ChildPipe = Open (PipeName, ChildPipeMode);
        !           214:   ParentPipe = fopen (PipeName, mode);
        !           215:   if (ChildPipeMode == MODE_NEWFILE) {
        !           216:     NewProcTags[3].ti_Data = Input ();
        !           217:     NewProcTags[4].ti_Data = ChildPipe;
        !           218:     NewProcTags[5].ti_Data = FALSE;
        !           219:     NewProcTags[6].ti_Data = TRUE;
        !           220:   } else {
        !           221:     NewProcTags[3].ti_Data = ChildPipe;
        !           222:     NewProcTags[4].ti_Data = Output ();
        !           223:     NewProcTags[5].ti_Data = TRUE;
        !           224:     NewProcTags[6].ti_Data = FALSE;
        !           225:   }
        !           226:   if (ChildPipe == NULL || ParentPipe == NULL) {
        !           227:     errno = EPIPE;
        !           228:     goto cleanup;
        !           229:   }
        !           230:
        !           231:   /* Now generate a entry in the pipe file descriptor table. */
        !           232:   PipeToUse->pfd_Msg.sm_Cmd = malloc (strlen (command) + 1);
        !           233:   if (PipeToUse->pfd_Msg.sm_Cmd == NULL) {
        !           234:     errno = ENOMEM;
        !           235:     goto cleanup;
        !           236:   }
        !           237:   strcpy (PipeToUse->pfd_Msg.sm_Cmd, command);
        !           238:   PipeToUse->pfd_Msg.sm_Msg.mn_ReplyPort = CreateMsgPort ();
        !           239:   if (PipeToUse->pfd_Msg.sm_Msg.mn_ReplyPort == NULL) {
        !           240:     errno = ENOMEM;
        !           241:     goto cleanup;
        !           242:   }
        !           243:   PipeToUse->pfd_Msg.sm_Msg.mn_Node.ln_Type = NT_MESSAGE;
        !           244:   PipeToUse->pfd_Msg.sm_Msg.mn_Node.ln_Pri = 0;
        !           245:   PipeToUse->pfd_Msg.sm_Msg.mn_Length = sizeof (struct StartupMessage);
        !           246:   PipeToUse->pfd_File = ParentPipe;
        !           247:
        !           248:   /* Now create the child process. */
        !           249:   ChildProcess = CreateNewProc (NewProcTags);
        !           250:   if (ChildProcess == NULL) {
        !           251:     errno = ENOMEM;
        !           252:     goto cleanup;
        !           253:   }
        !           254:
        !           255:   /* Pass the startup message to the child process. */
        !           256:   PutMsg (&ChildProcess->pr_MsgPort, (struct Message *) &PipeToUse->pfd_Msg);
        !           257:
        !           258:   /* This is the normal exit point for the function. */
        !           259:   return ParentPipe;
        !           260:
        !           261:   /* This code is only executed if there was an error. In this case the
        !           262:    * allocated resources must be freed. The code is actually clearer (at
        !           263:    * least in my opinion) and more concise by using goto than by using a
        !           264:    * function (global variables or function parameters needed) or a lot
        !           265:    * of if-constructions (code gets blown up unnecessarily).
        !           266:    */
        !           267: cleanup:
        !           268:   if (PipeToUse->pfd_Msg.sm_Msg.mn_ReplyPort == NULL)
        !           269:     DeleteMsgPort (PipeToUse->pfd_Msg.sm_Msg.mn_ReplyPort);
        !           270:   if (ParentPipe)
        !           271:     fclose (ParentPipe);
        !           272:   if (ChildPipe)
        !           273:     Close (ChildPipe);
        !           274:   return NULL;
        !           275: }
        !           276:
        !           277:
        !           278: int pclose (stream)
        !           279: FILE *stream;
        !           280: {
        !           281:   LONG PipeToClose;
        !           282:
        !           283:   /* Test whether we're using the right Dos version. */
        !           284:   if (DOSBase->dl_lib.lib_Version < DOS_VERSION) {
        !           285:     errno = EPIPE;
        !           286:     return -1;
        !           287:   }
        !           288:
        !           289:   /* Test whether this is the first call to this module or not. If so,
        !           290:    * pclose has been called before popen and we return with an error
        !           291:    * because the initialisation has yet to be done.
        !           292:    */
        !           293:   if (FirstCall) {
        !           294:     errno = EBADF;
        !           295:     return -1;
        !           296:   }
        !           297:
        !           298:   /* Search for the correct table entry and close the associated file. */
        !           299:   for (PipeToClose = 0; PipeToClose < MAX_OPEN_PIPES; PipeToClose++)
        !           300:     if (OpenPipes[PipeToClose].pfd_File == stream) break;
        !           301:   if (PipeToClose >= MAX_OPEN_PIPES) {
        !           302:     errno = EBADF;
        !           303:     return -1;
        !           304:   }
        !           305:   fclose (stream);
        !           306:
        !           307:   /* Now wait for the child to terminate and get its exit status. */
        !           308:   WaitPort (OpenPipes[PipeToClose].pfd_Msg.sm_Msg.mn_ReplyPort);
        !           309:   OpenPipes[PipeToClose].pfd_File = NULL;
        !           310:
        !           311:   /* Free the allocates resources. */
        !           312:   DeleteMsgPort (OpenPipes[PipeToClose].pfd_Msg.sm_Msg.mn_ReplyPort);
        !           313:   free (OpenPipes[PipeToClose].pfd_Msg.sm_Cmd);
        !           314:
        !           315:   return OpenPipes[PipeToClose].pfd_Msg.sm_RetCode;
        !           316: }
        !           317:
        !           318:
        !           319: static void CleanUpPipes ()
        !           320: {
        !           321:   LONG Count;
        !           322:   FILE *Pipe;
        !           323:
        !           324:   /* Close each open pipe. */
        !           325:   for (Count = 0; Count < MAX_OPEN_PIPES; Count++) {
        !           326:     Pipe = OpenPipes[Count].pfd_File;
        !           327:     if (Pipe != NULL)
        !           328:       pclose (Pipe);
        !           329:   }
        !           330: }
        !           331:
        !           332:
        !           333: static int __saveds ChildEntry ()
        !           334: {
        !           335:   struct Process *ChildProc;
        !           336:   struct StartupMessage *StartUpMessage;
        !           337:   LONG ReturnCode;
        !           338:   struct DosLibrary *DOSBase;
        !           339:   struct TagItem SysTags[3] = {
        !           340:     {SYS_Asynch, FALSE},
        !           341:     {SYS_UserShell, TRUE},
        !           342:     {TAG_DONE, 0}
        !           343:   };
        !           344:
        !           345:   /* We need to open this library, because we don't inherit it from our
        !           346:    * parent process.
        !           347:    */
        !           348:   DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", DOS_VERSION);
        !           349:
        !           350:   /* Get the childs process structure. */
        !           351:   ChildProc = (struct Process *) FindTask (NULL);
        !           352:
        !           353:   /* Wait for the startup message from the parent. */
        !           354:   WaitPort (&ChildProc->pr_MsgPort);
        !           355:   StartUpMessage = (struct StartupMessage *) GetMsg (&ChildProc->pr_MsgPort);
        !           356:
        !           357:   /* Now run the command and return the result. */
        !           358:   if (DOSBase != NULL)
        !           359:     ReturnCode = System (StartUpMessage->sm_Cmd, SysTags);
        !           360:   else
        !           361:     ReturnCode = 10000;
        !           362:   StartUpMessage->sm_RetCode = ReturnCode;
        !           363:
        !           364:   /* Tell the parent that we are done. */
        !           365:   ReplyMsg ((struct Message *) StartUpMessage);
        !           366:
        !           367:   if (DOSBase)
        !           368:     CloseLibrary ((struct Library *) DOSBase);
        !           369:
        !           370:   return 0;
        !           371: }
        !           372:
        !           373: #endif /* PIPES */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>