home *** CD-ROM | disk | FTP | other *** search
-
- /* Cmd.c --- v4 --- Carolyn Scheppner CBM 07/87
- *
- * Copyright (c) 1987 Commodore Business Machines - All Rights Reserved
- * This code may be freely non-commercially redistributed.
- *
- * Redirects exec serial or parallel device CMD_WRITEs to a file
- * (for the purpose of capturing printer output in a file)
- * Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
- *
- * CLI Usage: [run] cmd [-s] [-m] [-n] devicename filename
- * -s (Skip) skips any short initial write (usually a Reset if screendump)
- * -m (Multiple) causes cmd to remain installed for multiple files
- * -n (Notify) enables helpful progress messages
- * devicename serial or parallel
- *
- * WB Usage: Just doubleclick.
- * Specify the args in your icon's ToolTypes (use WB Info)
- * Built-in defaults are:
- * DEVICE=parallel
- * FILE=ram:CMD_file
- * SKIP=FALSE
- * MULTIPLE=FALSE
- * NOTIFY=FALSE
- *
- * Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
- * The printer device then delays long enough for the reset
- * to complete, to prevent the loss of subsequent output data.
- * When the dump is instead captured in a file, this delay
- * is of course lost. If your printer driver outputs a reset
- * at the start of a dump (as ours do), use the -s (SKIP) option
- * to keep the initial CMD_WRITE out of the file.
- *
- * Sorry about the busywait synchronization of the device wedge
- * and the main process. The purpose was to avoid unnecessary
- * meddling with the message structures and the device's signals.
- * I had to add a conditional kludge in MyBeginIO to allow Cmd
- * to work with our HPLaser drivers which do PWrites within a Forbid
- * in their Close logic to print/eject last sheet, and also apparently
- * during their open logic if drivers are resident.
- *
- * v2 mods: changes to MyBeginIO for -1 and 0 length CMD_WRITES, usage
- * v3 mods: added buffering of small writes to speed file IO
- * v4 mods: Conditional kludges added to MyBeginIO for HPLaser
- * (if Forbidden, sneaks the data into main's write buffer)
- * (EXTRALEN added to wbuf size to allow extra room for this)
- * myWrite now doesn't Write if len = 0
- * MyClose now conditional on writecnt, not reqcnt
- *
- * Linkage info (requires assembler module cmda):
- * Compile with -v on LC2.
- * FROM LIB:Astartup.obj, cmd.o, cmda.o
- * TO cmd
- * LIBRARY LIB:Amiga.lib,LIB:LC.lib
- */
-
- #include "exec/types.h"
- #include "exec/memory.h"
- #include "exec/io.h"
- #include "exec/libraries.h"
- #include "exec/execbase.h"
- #include "libraries/dos.h"
- #include "libraries/dosextens.h"
- #include "workbench/startup.h"
- #include "workbench/workbench.h"
- #include "devices/serial.h"
- #include "devices/parallel.h"
-
- /* #define DEBUG */
-
- #define TOUPPER(c) ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c))
- #define HIGHER(x,y) ((x)>(y)?(x):(y))
-
- #define WBUFLEN 2048L
- #define EXTRALEN 256L
-
- #define INBUFLEN 40L
- #define REQSIZE 120L /* should be big enough or any OpenDevice */
-
- #define DEV_CLOSE LIB_CLOSE
- #define DEV_EXPUNGE LIB_EXPUNGE
- /* DEV_BEGINIO (-30) defined in exec/io.h */
-
- #define OPEN_SIG SIGBREAKF_CTRL_E
- #define WRITE_SIG SIGBREAKF_CTRL_F
- #define CLOSE_SIG SIGBREAKF_CTRL_D
- #define BREAK_SIG SIGBREAKF_CTRL_C
-
- #define SHORT_WRITE (8L)
-
- extern VOID myBeginIO(); /* The assembler entry */
- extern VOID myClose(); /* The assembler entry */
- extern VOID myExpunge(); /* The assembler routine */
-
- extern struct ExecBase *SysBase;
- extern struct MsgPort *CreatePort();
- extern struct WBStartup *WBenchMsg;
-
- ULONG RealBeginIO, NewBeginIO;
- ULONG RealClose, NewClose;
- ULONG RealExpunge, NewExpunge;
-
- char *noMem = "Out of memory\n";
- char *portName = "cas_TMP_CMD_PORT";
- char *conSpec = "CON:20/20/600/40/ CMD v4";
-
- char u1[]={"\nCLI Usage: [run] Cmd [-s] [-m] [-n] devicename filename\n"};
- char u2[]={" devicename = serial or parallel\n"};
- char u3[]={" -s = SKIP any short initial write (usually a reset if screendump)\
- n"};
- char u4[]={" -m = installed for MULTIPLE files until Break or CTRL_C\n"};
- char u5[]={" -n = enables NOTIFY (helpful progress messages)\n\n"};
- char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
- char u7[]={" Cancel installation for multiple files by reclicking\n\n"};
- char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
- char *morehelp = "Type cmd ? for more help\n\n";
-
- char *prevTaskName = NULL;
- char *outFileName, *deviceName;
- char mainTaskName[40];
- char wbDev[INBUFLEN], wbFile[INBUFLEN];
- char sbuf[120], *wbuf = 0;
-
- struct Device *TheDevice;
- struct Task *otherTask, *mainTask;
-
- struct IOStdReq *myReq, *ioR;
- struct MsgPort *port;
-
-
- LONG wLen = 1, outFile = NULL;
- ULONG total = 0;
- ULONG IconBase = NULL;
- BOOL Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
- BOOL Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
- int reqcnt = 0, writecnt = 0, filecnt = 0; fnLen, wi;
-
- char cprt[] =
- "Copyright (c) 1987 Commodore Business Machines All Rights Reserved";
-
- VOID MyBeginIO(ior)
- struct IOStdReq *ior;
- {
- BOOL Forbidden;
- char *data;
- int k;
-
- /* The code conditional on Forbidden is needed to work with
- * HPLaser drivers which PWrite during a Forbid in their Close
- * logic to print and eject last sheet, and also apparently
- * during the initial write if drivers are resident.
- */
- Forbidden = (SysBase->TDNestCnt >= 0) ? TRUE : FALSE;
-
- reqcnt += 1;
- if((ior->io_Command == CMD_WRITE)&&(ior->io_Length))
- {
- writecnt += 1;
-
- if(writecnt==1)
- {
- if(!Forbidden) while(MainBusy);
- MainBusy = TRUE;
- Signal(mainTask,OPEN_SIG);
- if(!Forbidden) while(MainBusy);
- }
-
- /* If device CMD_WRITE uses length -1, convert to actual length */
- if(ior->io_Length==-1) ior->io_Length = strlen(ior->io_Data);
-
- if((!Skip)||(writecnt>1)||(ior->io_Length > SHORT_WRITE))
- {
- /* This conditional kludge needed to work with HPLaser
- * drivers which PWrite during a Forbid in their
- * Close logic to print/eject last sheet
- */
- if(Forbidden)
- {
- if(ior->io_Length < (WBUFLEN + EXTRALEN - wi))
- {
- data = (char *)ior->io_Data;
- for(k=0; k<ior->io_Length; k++, wi++) wbuf[wi]=data[k];
- }
- }
- else
- {
- while(MainBusy);
- MainBusy = TRUE;
- ioR = ior;
- Signal(mainTask,WRITE_SIG); /* Signal write */
- while(MainBusy);
- }
- }
- ior->io_Actual = ior->io_Length;
- }
- if(!(ior->io_Flags & IOF_QUICK)) ReplyMsg(ior);
- }
-
-
- VOID MyClose(ior)
- struct IOStdReq *ior;
- {
- /* Note - Exec has us in a forbid here */
- if(writecnt) /* Ignores DOS's initial Open/Close/Open */
- {
- Signal(mainTask,CLOSE_SIG); /* Signal Close */
- }
- }
-
- main(argc, argv)
- UWORD argc;
- TEXT *argv[];
- {
- ULONG signals;
- int k;
-
- FromWb = (argc==0) ? TRUE : FALSE;
-
- if(FromWb)
- {
- getWbArgs(WBenchMsg);
- deviceName = wbDev;
- outFileName = wbFile;
- }
- else
- {
- if(strEqu(argv[1], "?")) usageHelpExit();
- if(argc<3) usageExit();
-
- for(k=1; argv[k][0]=='-'; k++)
- {
- if(argv[k][1] == 's') Skip = TRUE;
- if(argv[k][1] == 'm') Multiple = TRUE;
- if(argv[k][1] == 'n') Notify = TRUE;
- }
- if(argc-k < 2) usageExit();
- deviceName = argv[k++];
- outFileName = argv[k];
- }
-
- fnLen = strlen(outFileName); /* Used if Multiple extension added */
-
- /* Result will be mainTaskName = "cas_CMD_whatever.device"
- * with deviceName pointing to the eighth character
- */
- strcpy(&mainTaskName[0],"cas_CMD_");
- strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
- strcpy(&mainTaskName[strlen(mainTaskName)],".device");
- deviceName = &mainTaskName[8];
-
- Forbid();
- if(otherTask = (struct Task *)FindTask(mainTaskName))
- {
- Permit();
- if(FromWb) Signal(otherTask,BREAK_SIG);
- else printf("Device already redirected... exiting\n");
- cleanexit();
- }
-
- mainTask = (struct Task *)FindTask(NULL);
- prevTaskName = mainTask->tc_Node.ln_Name;
- mainTask->tc_Node.ln_Name = mainTaskName;
- Permit();
-
- /* initialize */
- if(!(wbuf = (char *)AllocMem(WBUFLEN+EXTRALEN,MEMF_PUBLIC|MEMF_CLEAR)))
- cleanexit("Can't allocate write buffer\n");
- wi = 0; /* index into wbuf */
-
- if(!(port = CreatePort(portName, 0))) cleanexit("Can't open port\n");
-
- myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
- if (!myReq) cleanexit(noMem);
-
- myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
- myReq->io_Message.mn_ReplyPort = port;
-
- if(OpenDevice(deviceName, 0, myReq, 0))
- {
- sprintf(sbuf,"Can't open %s\n",deviceName);
- cleanexit(sbuf);
- }
- TheDevice = myReq->io_Device;
-
- /* Install device IO redirection */
-
- Forbid();
- RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
- RealClose = SetFunction(TheDevice, DEV_CLOSE, myClose);
- RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
- Permit();
-
- /* Expunge disabled, CloseDevice so another can open it */
- CloseDevice(myReq);
-
- if(Notify)
- {
- sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
- message(sbuf);
- }
-
- while(!Done)
- {
- signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
-
- if(signals & OPEN_SIG) /* Open */
- {
- if(!outFile) /* No output file currently open */
- {
- if(Multiple) /* If Multiple, add .n extension to filename */
- {
- filecnt++;
- sprintf(&outFileName[fnLen],".%ld",filecnt);
- }
- /* open output file */
- outFile = Open(outFileName, MODE_NEWFILE);
- wLen = 1;
- total = 0;
- /* This moved due to sneak-into-buffer HP kludge */
- /* wi = 0; Init now at Alloc, and each Close */
- Error1 = TRUE;
-
- if(Notify)
- {
- sprintf(sbuf,"Redirecting %s to %s\n",
- deviceName,outFileName);
- message(sbuf);
- }
-
- }
- #ifdef DEBUG
- printf("Processed OPEN_SIG, file %s, handle $%lx\n",
- outFileName,outFile);
- #endif
- }
-
- if(signals & WRITE_SIG) /* Write */
- {
- if((outFile)&&(wLen > -1))
- {
- wLen = bufOrWrite(outFile,ioR->io_Data,ioR->io_Length);
- }
- else if(Error1)
- {
- message("Cmd file error: Cancel device output\n");
- Error1 = FALSE;
- }
- #ifdef DEBUG
- printf("Processed WRITE_SIG, ioLen %ld, wLen %ld, Error1 = %ld\n",
- ioR->io_Length, wLen, Error1);
- #endif
- }
-
- if(signals & (CLOSE_SIG|BREAK_SIG))
- {
- /* Close file now so user can copy even if something is wrong */
- /* Null the handle - to prevent Write or re-Close */
- if(!Multiple) signals |= BREAK_SIG;
- if(outFile)
- {
- /* Write buffer contents */
- if((wi>0)&&(wLen>-1)) wLen = myWrite(outFile,wbuf,wi);
- wi = 0; /* moved from Open logic */
-
- Forbid();
- Close(outFile);
- outFile = NULL;
- writecnt = 0;
- reqcnt = 0;
- Permit();
-
- if((!Multiple)||(Notify))
- {
- sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
- total,deviceName,outFileName);
- message(sbuf);
- }
- }
- #ifdef DEBUG
- printf("Processed CLOSE_SIG, total %ld\n", total);
- #endif
- }
-
- if(signals & BREAK_SIG)
- {
- #ifdef DEBUG
- printf("Got BREAK_SIG\n");
- #endif
- while(!Done)
- {
- /* Wait till we can reopen the device */
- while(OpenDevice(deviceName, 0L, myReq, 0L)) Delay(50L);
-
- /* If it's been re-loaded, we can leave */
- /* Shouldn't be possible since we disabled Expunge */
- if((ULONG)myReq->io_Device != (ULONG)TheDevice)
- {
- Done = TRUE;
- }
- else
- {
- Forbid();
-
- NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
- NewClose = SetFunction(TheDevice, DEV_CLOSE, RealClose);
- NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
-
- if((NewBeginIO != (ULONG)myBeginIO)
- ||(NewClose != (ULONG)myClose)
- ||(NewExpunge != (ULONG)myExpunge))
- {
- /* Someone else has changed the vectors */
- /* We put theirs back - can't exit yet */
- SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);
- SetFunction(TheDevice, DEV_CLOSE , NewClose);
- SetFunction(TheDevice, DEV_CLOSE, NewClose);
- SetFunction(TheDevice, DEV_CLOSE , NewClose);
- SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
- }
- else
- {
- Done = TRUE;
- }
- Permit();
- }
- CloseDevice(myReq);
- if(!Done) message("Vectors have changed - can't restore\n");
- }
- }
- MainBusy = FALSE;
- }
-
- sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
- cleanexit(sbuf);
- }
-
-
- /* Output buffering */
-
- bufOrWrite(fh,data,len)
- LONG fh;
- char *data;
- int len;
- {
- int k, wlen;
-
- wlen = len;
-
- /* If possible, just buffer the output data */
- if(len < WBUFLEN - wi)
- {
- for(k=0; k<len; k++, wi++) wbuf[wi] = data[k];
- }
- else
- {
- /* Else output any buffered data to the file */
- if(wi>0) wlen = myWrite(fh,wbuf,wi);
- wi = 0;
-
- /* Then either buffer or write out current request */
- if(wlen > -1)
- {
- if(len < WBUFLEN)
- {
- for(k=0; k<len; k++, wi++) wbuf[wi] = data[k];
- wlen = len;
- }
- else
- {
- wlen = myWrite(fh,data,len);
- }
- }
- }
- return(wlen);
- }
-
-
- /* myWrite also updates total */
- myWrite(fh,data,len)
- LONG fh;
- char *data;
- int len;
- {
- int wlen = 0;
-
- if(len)
- {
- wlen = Write(fh,data,len);
- if (wlen > -1) total += wlen;
- }
- return(wlen);
- }
-
-
- /* Cleanup and exits */
-
- usageHelpExit()
- {
- int k;
- for(k=0; k<7; k++) printf(us[k]);
- exit(RETURN_OK);
- }
-
- usageExit()
- {
- printf(u1);
- printf(morehelp);
- exit(RETURN_OK);
- }
-
- cleanexit(s)
- char *s;
- {
- message(s);
- cleanup();
- exit(RETURN_OK);
- }
-
- cleanup()
- {
- if(myReq) FreeMem(myReq,REQSIZE);
- if(port) DeletePort(port);
- if(outFile) Close(outFile);
- if(wbuf) FreeMem(wbuf,WBUFLEN+EXTRALEN);
-
- Forbid();
- if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
- Permit();
- }
-
-
- message(s)
- char *s;
- {
- LONG con;
-
- if((!FromWb)&&(*s)) printf(s);
- if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
- {
- Write(con,s,strlen(s));
- Delay(120L);
- Close(con);
- }
- }
-
-
- getWbArgs(wbMsg)
- struct WBStartup *wbMsg;
- {
- struct WBArg *wbArg;
- struct DiskObject *diskobj;
- char **toolarray;
- char *s;
-
- /* Defaults */
- strcpy(wbDev,"parallel");
- strcpy(wbFile,"ram:CMD_file");
- Skip = FALSE;
- Multiple = FALSE;
- Notify = FALSE;
-
- wbArg = wbMsg->sm_ArgList;
-
- if((IconBase = OpenLibrary("icon.library", 0)))
- {
- diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
- if(diskobj)
- {
- toolarray = (char **)diskobj->do_ToolTypes;
-
- if(s=(char *)FindToolType(toolarray,"DEVICE")) strcpy(wbDev,s);
- if(s=(char *)FindToolType(toolarray,"FILE")) strcpy(wbFile,s);
- if(s=(char *)FindToolType(toolarray,"SKIP"))
- {
- if(strEqu(s,"TRUE")) Skip = TRUE;
- }
- if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
- {
- if(strEqu(s,"TRUE")) Multiple = TRUE;
- }
- if(s=(char *)FindToolType(toolarray,"NOTIFY"))
- {
- if(strEqu(s,"TRUE")) Notify = TRUE;
- }
- FreeDiskObject(diskobj);
- }
- CloseLibrary(IconBase);
- }
- }
-
-
- /* String functions */
-
- strEqu(p, q)
- TEXT *p, *q;
- {
- while(TOUPPER(*p) == TOUPPER(*q))
- {
- if (*(p++) == 0) return(TRUE);
- ++q;
- }
- return(FALSE);
- }
-
- strlen(s)
- char *s;
- {
- int i = 0;
- while(*s++) i++;
- return(i);
- }
-
- strcpy(to,from)
- char *to, *from;
- {
- do
- {
- *to++ = *from;
- }
- while(*from++);
- }
-
- /* end */
-
-