home *** CD-ROM | disk | FTP | other *** search
- /*
- * HARCOPY.C copy CLI output to file as well as window.
- *
- * By Davide P. Cervone, Copywrite (c) 1987
- *
- * Based heavily on a source by Phillip Lindsay, (c) 1987 Commodore-Amiga, Inc.
- * You may use this source as long as this copywrite notice is left intact.
- */
-
- #include <exec/types.h>
- #include <exec/ports.h>
- #include <exec/semaphores.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <stdio.h>
-
- #ifdef MANX
- #include <functions.h>
- #endif
-
- /*
- * AmigaDOS uses task signal bit 8 for message signaling
- */
-
- #define ONE 1L
- #define DOS_SIGNAL 8
- #define DOS_MASK (ONE<<DOS_SIGNAL)
-
-
- /*
- * Cast a pointer to become a structure pointer
- */
-
- #define PTR(x,p) ((struct x *)(p))
-
-
- /*
- * AmigaDOS packet types we're interested in viewing
- */
-
- #define _ACTION_READ 82L
- #define _ACTION_WRITE 87L
-
-
- /*
- * Short-hand for the parts of the DosPacket
- */
-
- #define ARG1 pkt->dp_Arg1
- #define ARG2 pkt->dp_Arg2
- #define RES1 pkt->dp_Res1
-
-
- /*
- * Program functions
- */
-
- #define SHOW_USAGE 0
- #define START_HARDCOPY 1
- #define DO_MONITOR 2
- #define END_HARDCOPY 3
-
-
- /*
- * External routines and variables
- */
-
- extern LONG AllocSignal(), Wait();
- extern struct FileHandle *Open();
- extern struct Message *PacketWait(), *GetMsg();
- extern struct Process *FindTask();
- extern struct DosLibrary *DOSBase;
- extern void GetDateTime();
-
-
- /*
- * Our own variables
- */
-
- static char *version = "HARDCOPY v1.0, 4/25/87";
- static char *copywrite = "Copywrite (c) 1987 by Davide P. Cervone";
-
- struct MsgPort *thePort; /* the port we will be monitoring */
- struct Process *myProcess; /* pointer to our own process */
- struct Process *ChosenProcess; /* the process we are monitoring */
- ULONG WaitMask; /* the task signal mask */
- struct SignalSemaphore CanReturn = {0}; /* coordinates PacketWait */
- struct Message *theMessage; /* the message we received */
- APTR OldPktWait; /* the old pr_PktWait routine */
- APTR OldUserData; /* tc_UserData for monitored task */
-
-
- #ifdef MANX
- LONG PWait(); /* this is the ASM stub that calls PacketWait() */
- #else
- #define PWait PacketWait
- #endif
-
- #ifndef MANX
- Ctrl_C() /* Control-C Trap routine for Lattice */
- {
- return(0);
- }
- #endif
-
-
- /*
- * PacketWait()
- *
- * This is the routine placed in the pr_PktWait field of the monitored
- * precess. It is run asynchronously by the monitored process, and is
- * called whenever AmigaDOS does a taskwait(). PacketWait() waits for
- * a message to come in and then signals the monitoring task that one has
- * arrived. It then attempts to obtain the semaphore, which will not be
- * released by the monitoring process until it is finished printing the
- * contents of the packet.
- */
-
- struct Message *PacketWait()
- {
- #ifdef MANX
- /*
- * if MANX, make sure we can see our data
- */
- geta4();
- #endif
-
- SetSignal(FALSE,DOS_MASK);
-
- while(!(theMessage = GetMsg(thePort))) Wait(DOS_MASK);
-
- Signal(myProcess,WaitMask);
- ObtainSemaphore(&CanReturn);
- ReleaseSemaphore(&CanReturn);
-
- return(theMessage);
- }
-
-
- /*
- * printBUF()
- *
- * Prints a buffer to stdout.
- */
-
- void printBUF(buf,len)
- char *buf;
- int len;
- {
- short i;
- char outbuf[81];
-
- while (len > 0)
- {
- for (i=0; i<80 && len>0; i++,len--) outbuf[i] = *buf++;
- outbuf[i] = '\0';
- printf("%s",outbuf);
- }
- }
-
-
- /*
- * PrintPkt()
- *
- * For READ and WRITE packets to/from the CON: window, print the buffer
- * to stdout. We recognize CON: packets because ARG1 is zero (this is
- * a real kludge, but it seems to work, except we get an extra ENDCLI
- * if you run HARDCOPY, then EMACS, then spawn a new CLI, then type ENDCLI
- * to get back to EMACS. Can't figure that one out).
- */
-
- void PrintPkt(pkt)
- struct DosPacket *pkt;
- {
- switch(pkt->dp_Type)
- {
- case _ACTION_READ:
- if (ARG1 == 0) printBUF(ARG2,RES1);
- break;
-
- case _ACTION_WRITE:
- if (ARG1 == 0) printBUF(ARG2,RES1);
- break;
-
- default: /* Ignore anything else */
- break;
- }
- }
-
-
- /*
- * GetFunction()
- *
- * Check the command-line arguments to see that they are valid.
- * The legal possibilities are:
- *
- * TO <filename> To begin HARDCOPY to a file
- * END To end the HARDCOPY session
- * MONITOR <procID> To begin menitoring the process pointed to by
- * <procID>.
- */
-
- GetFunction(argc,argv)
- int argc;
- char *argv[];
- {
- int function = SHOW_USAGE;
-
- if (argc == 3 && stricmp(argv[1],"TO") == 0) function = START_HARDCOPY;
- else if (argc == 3 && strcmp(argv[1],"MONITOR") == 0 &&
- sscanf(argv[2],"%x",&ChosenProcess) == 1) function = DO_MONITOR;
- else if (argc == 2 && stricmp(argv[1],"END") == 0) function = END_HARDCOPY;
- return(function);
- }
-
-
- /*
- * SetupSignal()
- *
- * Allocate a signal to use for our inter-task communication, and
- * set up the mask for using it.
- */
-
- void SetupSignal(theSignal)
- LONG *theSignal;
- {
- *theSignal = AllocSignal(-ONE);
- if (*theSignal == -ONE)
- {
- printf("Can't Allocate a Task Signal.\n");
- exit(10);
- }
- WaitMask = (ONE << (*theSignal));
- }
-
-
- /*
- * SetupProcess()
- *
- * Copy the process' name, and get its Message port. Set our priority
- * higher than the monitored process so we will be able to react to its
- * signals, then set the pr_PktWait field to our PacketWiat() routine so
- * that we will be signalled when it receives a packet (save the old
- * pr_PktWait so we can put it back when we're through). Set the tc_UserData
- * field of the monitored processes Task structure to point to us, so that
- * the monitored process can signal us when it wants us to stop hardcopying.
- * Finally, send a signal to the monitored process to show that we are ready
- * to monitor it.
- */
-
- void SetupProcess(theProcess,name)
- struct Process *theProcess;
- char *name;
- {
- strcpy(name,theProcess->pr_Task.tc_Node.ln_Name);
- thePort = &theProcess->pr_MsgPort;
-
- Forbid();
- SetTaskPri(myProcess,(ULONG)(theProcess->pr_Task.tc_Node.ln_Pri + 1));
- OldPktWait = theProcess->pr_PktWait;
- theProcess->pr_PktWait = (APTR) PWait;
- OldUserData = PTR(Task,theProcess)->tc_UserData;
- PTR(Task,theProcess)->tc_UserData = (APTR) myProcess;
- Permit();
- Signal(theProcess,SIGBREAKF_CTRL_C);
- }
-
-
- /*
- * MonitorProcess()
- *
- * Wait for the monitored process to receive a message (our PacketWait()
- * function signals us via theSignal when it has received a message), then
- * print out the contents of the message. A semaphore is used to coordinate
- * this routine with the PacketWait() routine (which is run asynchonously
- * by the monitored process). Phillip Lindsay says "there are probably a
- * hundred better was of doing this. I just went with the first one [that]
- * came to mind." I couldn't think of a better one, so I still use it.
- * Since our process is running at a higher priority than the monitored one,
- * we should obtain the semaphore first. The other process will block until
- * we release it (when we are done printing the contents).
- */
-
- void MonitorProcess(name,theSignal)
- char *name;
- ULONG theSignal;
- {
- ULONG signals;
- struct DosPacket *thePacket;
-
- do
- {
- signals = Wait(SIGBREAKF_CTRL_C | WaitMask);
- ObtainSemaphore(&CanReturn);
- if (signals & WaitMask)
- {
- /*
- * PacketWait() signalled us so print the message it put in
- * theMessage.
- */
- thePacket = PTR(DosPacket,theMessage->mn_Node.ln_Name);
- PrintPkt(thePacket);
- }
- ReleaseSemaphore(&CanReturn);
- } while(!(signals & SIGBREAKF_CTRL_C));
- }
-
-
- /*
- * ClenUpProcess()
- *
- * Put everything back the way we found it, except that the monitored process
- * is still running our code...
- */
-
- void CleanUpProcess(theProcess)
- struct Process *theProcess;
- {
- Forbid();
- theProcess->pr_PktWait = OldPktWait;
- PTR(Task,theProcess)->tc_UserData = OldUserData;
- Permit();
- SetTaskPri(myProcess,0L);
- }
-
-
- /*
- * DoMonitor()
- *
- * Get a signal for our PacketWait code to use to signal us when a packet is
- * ready for us to look at. Get a semaphore so that we can make the
- * PacketWait() routine wait for us to finish with the packet before it
- * returns the message to the monitored process. Set up the process so
- * that it includes our PacketWait() code.
- *
- * Monitor the packet traffic, and print the I/O to the monitored CLI.
- * We wait for a signal from the PacketWait() routine, or for a
- * CTRL-C.
- *
- * When we get a CTRL-C, we are done monitoring, so we remove our
- * PacketWait() code, but the monitored process may still be in our
- * waiting code, so we wait for a CTRL-E to verify that we are free to
- * die (and remove the PacketWait code from memory).
- */
-
- void DoMonitor()
- {
- LONG TaskSignal;
- UBYTE ProcessName[81];
-
- myProcess = FindTask(NULL);
- if (ChosenProcess != NULL)
- {
- #ifndef MANX
- onbreak(&Ctrl_C); /* Turn off CTRL-C for Lattice: we do our own */
- #endif
-
- SetupSignal(&TaskSignal);
- InitSemaphore(&CanReturn);
- SetupProcess(ChosenProcess,ProcessName);
-
- MonitorProcess(ProcessName,TaskSignal);
-
- CleanUpProcess(ChosenProcess);
- Wait(SIGBREAKF_CTRL_E);
- FreeSignal(TaskSignal);
- }
- }
-
-
- /*
- * StartHardCopy()
- *
- * Creates the process that monitors the current process via a call to
- * Execute(). We execute a RUN command that runs HARDCOPY MONITOR and
- * passes a pointer to the current process as a parameter. When HARDCOPY
- * starts as the remote process, it looks up this parameter and monitors
- * that process. The output for HARDCOPY is re-directed to the file
- * that the user specified in the initial call to HARDCOPY.
- *
- * The spawned process will signal us with a CTRL-C when it is set up,
- * so wait for that signal. Finally, print out a message; this will
- * appear as the first thing in the output file.
- */
-
- void StartHardCopy(file)
- char *file;
- {
- char cmd[200],time[19];
- #define COMMAND "RUN <NIL: >NIL: HARDCOPY <NIL: >\"%s\" MONITOR 0x%X"
-
- sprintf(cmd,COMMAND,file,FindTask(NULL));
- if (!Execute(cmd,NULL,NULL))
- {
- printf("Can't create HARDCOPY process\n");
- } else {
- #ifndef MANX
- onbreak(&Ctrl_C); /* Turn off CTRL-C for Lattice: we do our own */
- #endif
- printf("Waiting for HARDCOPY monitor to start ...\n");
- printf("[Press CTRL-E if any errors are reported]\n");
- if (Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E) == SIGBREAKF_CTRL_E)
- {
- printf("\nUser signalled abort!\n\n");
- printf("To remove an unwanted HARDCOPY monitor process, first try\n");
- printf("giving the command HARDCOPY END. If that doesn't work,\n");
- printf("use STATUS to identify the process, and then use the BREAK\n");
- printf("command to send a CTRL-C and then a CTRL-E to the HARDCOPY\n");
- printf("monitor process.\n\n");
- } else {
- GetDateTime(time);
- printf("\nHARDCOPY v1.0 recorded on %s to file \"%s\"\n",
- time,file);
- printf("To end the HARDCOPY session and close the file, ");
- printf("type HARDCOPY END\n\n");
- }
- }
- }
-
-
- /*
- * EndHardCopy()
- *
- * Sends a CTRL-C and a CTRL-E to the monitoring HARDCOPY process, which
- * tell it to de-install the PacketWait() routine, and then die. The
- * monitoring process has stored its address in the UserData field of
- * our process' Task structure, so we know were to send the signals.
- */
-
- void EndHardCopy()
- {
- struct Process *MonitoringProcess;
-
- myProcess = FindTask(NULL);
- MonitoringProcess = PTR(Process,PTR(Task,myProcess)->tc_UserData);
- if (MonitoringProcess == NULL)
- {
- printf("No HARDCOPY process in progress\n");
- } else {
- Signal(MonitoringProcess,SIGBREAKF_CTRL_C);
- printf("HARDCOPY output complete.\n");
- Signal(MonitoringProcess,SIGBREAKF_CTRL_E);
- }
- }
-
- void main(argc,argv)
- int argc;
- char *argv[];
- {
- ChosenProcess = NULL;
- switch(GetFunction(argc,argv))
- {
- case SHOW_USAGE:
- printf("Usage: HARDCOPY TO <file>\n");
- printf(" or: HARDCOPY END\n");
- break;
-
- case START_HARDCOPY:
- StartHardCopy(argv[2]);
- break;
-
- case DO_MONITOR:
- DoMonitor();
- break;
-
- case END_HARDCOPY:
- EndHardCopy();
- break;
- }
- }
-
-
- /*
- * GetStrTime(time,date)
- *
- * translates the DateStamp stored in "date" into a character string and
- * copies it into the character string pointed to by "time", which should be
- * at least 19 characters long. GetStrTime properly accounts for leap years
- * every four years. Every four centuries, however, a leap day is supposed
- * to be skipped. AmigaDOS does not correctly interpret these non-leap
- * centuries, hence neither does GetStrTime. In the event that AmigaDOS is
- * ever corrected to fix this bug, you can remove the comment delimiters from
- * the line in GetStrTime that implements non-leap centuries. Unfortunately,
- * the year 2000 is a non-leap century, hence this bug may actually
- * come into play (if anyone still has Amigas in 14 years).
- */
-
- static int
- DaysIn[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
-
- static char
- *NameOf[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
- #define CENTURY (100 YEARS + 25 LEAPDAYS)
- #define FOURCENTURIES (400 YEARS + 99 LEAPDAYS)
- #define FOURYEARS (4 YEARS + 1 LEAPDAY)
- #define LEAPYEAR (1 YEARS + 1 LEAPDAY)
- #define LEAPDAYS
- #define LEAPDAY
- #define YEARS * 365
- #define YEAR 365
- #define FEBDAYS 59 /* days until the end of February */
-
- void GetStrTime(time,date)
- char time[19]; /* storage area for the return value */
- struct DateStamp *date; /* the DateStamp to convert */
- {
- int year,month,day,hour,minute,second;
-
- day = date->ds_Days + 78 YEARS + 20 LEAPDAYS;
- /* day += (day - FEBDAYS - CENTURY + FOURCENTURIES) / FOURCENTURIES; */
- year = 4 * (day/FOURYEARS) + 1900;
- day %= FOURYEARS;
- day += (day - FEBDAYS - 1 LEAPDAY) / YEAR;
- year += day / LEAPYEAR;
- day %= LEAPYEAR;
-
- for (month=1; day >= DaysIn[month]; month++);
- day = day - DaysIn[month-1] + 1;
-
- hour = date->ds_Minute / 60;
- minute = date->ds_Minute - hour*60;
- second = date->ds_Tick / TICKS_PER_SECOND;
-
- sprintf(time,"%02d-%3s-%02d %02d:%02d:%02d",
- day,NameOf[month],(year % 100),hour,minute,second);
- }
-
-
- /*
- * GetDateTime(str)
- *
- * Uses GetStrTime() to get the current date and time as a string.
- * "str" must be at least 19 characters long. See GetStrTime for
- * more information.
- */
-
- void GetDateTime(str)
- char *str;
- {
- struct DateStamp date;
-
- DateStamp(&date);
- GetStrTime(str,&date);
- }
-
-
- /*
- * This code stub has been known to save lives...
- */
-
- #if MANX
- #asm
- XREF _PacketWait
-
- XDEF _PWait
- _PWait:
- movem.l a2/a3/a4,-(sp)
- jsr _PacketWait
- movem.l (sp)+,a2/a3/a4
- rts
- #endasm
- #endif
-