home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
038.lha
/
Hardcopy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-05-16
|
15KB
|
565 lines
/*
* 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