home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d079 / cmd.lha / Cmd / Cmd.c next >
Encoding:
C/C++ Source or Header  |  1987-06-04  |  12.9 KB  |  483 lines

  1.  
  2. /* Cmd.c --- v1 --- Carolyn Scheppner  CBM  05/87
  3.  *
  4.  * Copyright (c) 1987  Commodore Business Machines - All Rights Reserved
  5.  *    This code may be freely non-commercially redistributed.
  6.  *
  7.  * Redirects exec serial or parallel device CMD_WRITEs to a file
  8.  *  (for the purpose of capturing printer output in a file)
  9.  * Built upon fragments of Read (author?) and NoFastMem (Andy Finkel)
  10.  *
  11.  * CLI Usage:  [run] cmd [-s] [-m] [-n] devicename filename
  12.  *   -s (Skip) skips any short initial write (usually a Reset if screendump)
  13.  *   -m (Multiple) causes cmd to remain installed for multiple files
  14.  *   -n (Notify) enables helpful progress messages 
  15.  *   devicename serial or parallel
  16.  *
  17.  * WB Usage:  Just doubleclick.
  18.  *            Specify the args in your icon's ToolTypes (use WB Info)
  19.  *            Built-in defaults are:
  20.  *               DEVICE=parallel
  21.  *               FILE=ram:CMD_file
  22.  *               SKIP=FALSE
  23.  *               MULTIPLE=FALSE
  24.  *               NOTIFY=FALSE
  25.  *
  26.  *   Note: On a screen dump, first CMD_WRITE is usually a printer RESET.
  27.  *         The printer device then delays long enough for the reset
  28.  *         to complete, to prevent the loss of subsequent output data.
  29.  *         When the dump is instead captured in a file, this delay
  30.  *         is of course lost.  If your printer driver outputs a reset
  31.  *         at the start of a dump (as ours do), use the -s (SKIP) option
  32.  *         to keep the initial CMD_WRITE out of the file.
  33.  *
  34.  * Sorry about the busywait synchronization of the device wedge
  35.  * and the main process.  The purpose was to avoid unnecessary
  36.  * meddling with the message structures and the device's signals.
  37.  *
  38.  * Linkage info (requires assembler module cmda):
  39.  *    FROM    LIB:Astartup.obj, cmd.o, cmda.o
  40.  *    TO      cmd
  41.  *    LIBRARY LIB:Amiga.lib,LIB:LC.lib
  42.  */
  43.  
  44. #include "exec/types.h" 
  45. #include "exec/memory.h" 
  46. #include "exec/io.h"
  47. #include "exec/libraries.h"
  48. #include "libraries/dos.h" 
  49. #include "libraries/dosextens.h"
  50. #include "workbench/startup.h"
  51. #include "workbench/workbench.h"
  52. #include "devices/serial.h" 
  53. #include "devices/parallel.h" 
  54.  
  55. #define TOUPPER(c)      ((c)>='a'&&(c)<='z'?(c)-'a'+'A':(c)) 
  56. #define HIGHER(x,y)     ((x)>(y)?(x):(y))
  57. #define INBUFLEN  40
  58. #define REQSIZE  120    /* should be big enough or any OpenDevice */
  59.  
  60. #define DEV_CLOSE    LIB_CLOSE
  61. #define DEV_EXPUNGE  LIB_EXPUNGE
  62. /*      DEV_BEGINIO  (-30)       defined in exec/io.h */
  63.  
  64. #define OPEN_SIG   SIGBREAKF_CTRL_E
  65. #define WRITE_SIG  SIGBREAKF_CTRL_F
  66. #define CLOSE_SIG  SIGBREAKF_CTRL_D
  67. #define BREAK_SIG  SIGBREAKF_CTRL_C
  68.  
  69. #define SHORT_WRITE (8L)
  70.  
  71. extern VOID  myBeginIO();  /* The assembler entry */
  72. extern VOID  myClose();    /* The assembler entry */
  73. extern VOID  myExpunge();  /* The assembler routine */
  74.  
  75. extern struct MsgPort *CreatePort(); 
  76. extern struct WBStartup *WBenchMsg;
  77.  
  78. ULONG  RealBeginIO, NewBeginIO;
  79. ULONG  RealClose,   NewClose;
  80. ULONG  RealExpunge, NewExpunge;
  81.  
  82. char *noMem      = "Out of memory\n";
  83. char *portName   = "cas_TMP_CMD_PORT";
  84. char *conSpec    = "CON:20/20/600/40/ CMD ";
  85.  
  86. char u1[]={"\nCLI Usage: [run] [-s] [-m] [-n] Cmd devicename filename\n"};
  87. char u2[]={"  devicename = serial or parallel\n"};
  88. char u3[]={"  -s = SKIP any short initial write (usually a reset if screendump)\n"};
  89. char u4[]={"  -m = installed for MULTIPLE files until Break or CTRL_C\n"};
  90. char u5[]={"  -n = enables NOTIFY (helpful progress messages)\n\n"};
  91. char u6[]={"WB Tooltypes: DEVICE, FILE, and booleans SKIP,MULTIPLE,NOTIFY\n"};
  92. char u7[]={"   Cancel installation for multiple files by reclicking\n\n"};
  93. char *us[7] = {u1,u2,u3,u4,u5,u6,u7};
  94. char *morehelp = "Type  cmd ?  for more help\n\n";
  95.  
  96. char *prevTaskName = NULL;
  97. char *outFileName, *deviceName;
  98. char mainTaskName[40];
  99. char wbDev[INBUFLEN], wbFile[INBUFLEN];
  100. char sbuf[120];
  101.  
  102. struct Device *TheDevice;
  103. struct Task   *otherTask, *mainTask;
  104.  
  105. struct IOStdReq *myReq, *ioR;
  106. struct MsgPort  *port; 
  107.  
  108.  
  109. LONG  wLen = 1, outFile = NULL;
  110. ULONG total = 0;
  111. ULONG IconBase = NULL;
  112. BOOL  Error1 = TRUE, Skip = FALSE, Multiple = FALSE, Notify = FALSE;
  113. BOOL  Done = FALSE, FromWb = FALSE, MainBusy = FALSE;
  114. int   reqcnt = 0, writecnt = 0, filecnt = 0; fnLen;
  115.  
  116.  
  117. VOID MyBeginIO(ior)
  118. struct IOStdReq *ior;
  119.    {
  120.    reqcnt += 1;
  121.    if(ior->io_Command == CMD_WRITE)
  122.       {
  123.       if(!writecnt)
  124.          {
  125.          while(MainBusy);
  126.          MainBusy = TRUE;
  127.          Signal(mainTask,OPEN_SIG);
  128.          while(MainBusy);
  129.          }
  130.  
  131.       if((!Skip)||(writecnt>0)||(ior->io_Length > SHORT_WRITE))
  132.          {
  133.          while(MainBusy);
  134.          MainBusy = TRUE;
  135.          ioR = ior;
  136.          Signal(mainTask,WRITE_SIG);  /* Signal write */
  137.          while(MainBusy);
  138.          }
  139.       writecnt += 1;
  140.       ior->io_Actual = ior->io_Length;
  141.       }
  142.    if(!(ior->io_Flags & IOF_QUICK))  ReplyMsg(ior);
  143.    }
  144.  
  145. VOID MyClose(ior)
  146. struct IOStdReq *ior;
  147.    {
  148.    /* Note - Exec has us in a forbid here */
  149.    if(reqcnt) /* Ignores DOS's initial Open/Close/Open */
  150.       {
  151.       Signal(mainTask,CLOSE_SIG);  /* Signal Close */
  152.       }
  153.    }
  154.  
  155. main(argc, argv) 
  156. UWORD argc; 
  157. TEXT *argv[]; 
  158.    { 
  159.    ULONG signals;
  160.    int k;
  161.  
  162.    FromWb = (argc==0) ? TRUE : FALSE;
  163.  
  164.    if(FromWb)
  165.       {
  166.       getWbArgs(WBenchMsg);
  167.       deviceName  = wbDev;
  168.       outFileName = wbFile;
  169.       }
  170.    else
  171.       {
  172.       if(strEqu(argv[1], "?"))  usageHelpExit();
  173.       if(argc<3) usageExit();
  174.  
  175.       for(k=1; argv[k][0]=='-'; k++)
  176.          {
  177.          if(argv[k][1] == 's')  Skip = TRUE;
  178.          if(argv[k][1] == 'm')  Multiple = TRUE;
  179.          if(argv[k][1] == 'n')  Notify = TRUE;
  180.          }
  181.       if(argc-k < 2)  usageExit();
  182.       deviceName  = argv[k++];
  183.       outFileName = argv[k];
  184.       }
  185.  
  186.    fnLen = strlen(outFileName); /* Used if Multiple extension added */
  187.  
  188.    /* Result will be mainTaskName = "cas_CMD_whatever.device"
  189.     *   with deviceName pointing to the eighth character
  190.     */
  191.    strcpy(&mainTaskName[0],"cas_CMD_");
  192.    strcpy(&mainTaskName[strlen(mainTaskName)],deviceName);
  193.    strcpy(&mainTaskName[strlen(mainTaskName)],".device");
  194.    deviceName = &mainTaskName[8];
  195.  
  196.    Forbid();
  197.    if(otherTask = (struct Task *)FindTask(mainTaskName))
  198.       {
  199.       Permit();
  200.       if(FromWb) Signal(otherTask,BREAK_SIG);
  201.       else printf("Device already redirected... exiting\n");
  202.       cleanexit();
  203.       }
  204.  
  205.    mainTask = (struct Task *)FindTask(NULL);
  206.    prevTaskName = mainTask->tc_Node.ln_Name;
  207.    mainTask->tc_Node.ln_Name = mainTaskName;
  208.    Permit();
  209.      
  210.    /* initialize */
  211.    if(!(port = CreatePort(portName, 0)))  cleanexit("Can't open port\n");
  212.  
  213.    myReq = (struct IOStdReq *)AllocMem(REQSIZE,MEMF_CLEAR|MEMF_PUBLIC);
  214.    if (!myReq)  cleanexit(noMem);
  215.  
  216.    myReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  217.    myReq->io_Message.mn_ReplyPort = port;
  218.  
  219.    if(OpenDevice(deviceName, 0, myReq, 0))
  220.       {
  221.       sprintf(sbuf,"Can't open %s\n",deviceName);
  222.       cleanexit(sbuf);
  223.       }
  224.    TheDevice = myReq->io_Device;
  225.  
  226.    /* Install device IO redirection */
  227.  
  228.    Forbid();
  229.    RealBeginIO = SetFunction(TheDevice, DEV_BEGINIO, myBeginIO);
  230.    RealClose   = SetFunction(TheDevice, DEV_CLOSE,   myClose);
  231.    RealExpunge = SetFunction(TheDevice, DEV_EXPUNGE, myExpunge);
  232.    Permit();
  233.  
  234.    /* Expunge disabled, CloseDevice so another can open it */
  235.    CloseDevice(myReq);
  236.  
  237.    if(Notify)
  238.       {
  239.       sprintf(sbuf,"Cmd redirection of %s installed\n",deviceName);
  240.       message(sbuf);
  241.       }
  242.  
  243.    while(!Done)
  244.       {
  245.       signals = Wait(OPEN_SIG|WRITE_SIG|CLOSE_SIG|BREAK_SIG);
  246.  
  247.       if(signals & OPEN_SIG)   /* Open */
  248.          {
  249.          if(!outFile)   /* No output file currently open */
  250.             {
  251.             if(Multiple)  /* If Multiple, add .n extension to filename */
  252.                {
  253.                filecnt++;
  254.                sprintf(&outFileName[fnLen],".%ld",filecnt);
  255.                }
  256.              /* open output file */
  257.             outFile = Open(outFileName, MODE_NEWFILE);
  258.             wLen = 1;
  259.             total = 0;
  260.             Error1 = TRUE;
  261.  
  262.             if(Notify)
  263.                {
  264.                sprintf(sbuf,"Redirecting %s to %s\n",
  265.                          deviceName,outFileName);
  266.                message(sbuf);
  267.                }
  268.  
  269.             }
  270.          }
  271.  
  272.       if(signals & WRITE_SIG)   /* Write */
  273.          {
  274.          if((outFile)&&(wLen > -1))
  275.             {
  276.             wLen = Write(outFile,ioR->io_Data,ioR->io_Length);
  277.             if(wLen > -1) total += wLen;
  278.             }
  279.          else if(Error1)
  280.             {
  281.             message("Cmd file error: Cancel device output\n");
  282.             Error1 = FALSE;
  283.             }
  284.          }
  285.  
  286.       if(signals & (CLOSE_SIG|BREAK_SIG))
  287.          {
  288.          /* Close file now so user can copy even if something is wrong */
  289.          /* Null the handle - to prevent Write or re-Close */
  290.          if(!Multiple)  signals |= BREAK_SIG;
  291.          if(outFile)
  292.             {
  293.             Close(outFile);
  294.             outFile = NULL;
  295.             writecnt = 0;
  296.             reqcnt = 0;
  297.             if((!Multiple)||(Notify))
  298.                {
  299.                sprintf(sbuf,"Redirected %ld bytes from %s to %s\n",
  300.                           total,deviceName,outFileName);
  301.                message(sbuf);
  302.                }
  303.             }
  304.          }
  305.  
  306.       if(signals & BREAK_SIG)
  307.          {
  308.          while(!Done)
  309.             {
  310.             /* Wait till we can reopen the device */
  311.             while(OpenDevice(deviceName, 0L, myReq, 0L))  Delay(50L);
  312.  
  313.             /* If it's been re-loaded, we can leave            */
  314.             /* Shouldn't be possible since we disabled Expunge */
  315.             if((ULONG)myReq->io_Device != (ULONG)TheDevice)
  316.                {
  317.                Done = TRUE;
  318.                }
  319.             else
  320.                {
  321.                Forbid();
  322.  
  323.                NewBeginIO = SetFunction(TheDevice, DEV_BEGINIO, RealBeginIO);
  324.                NewClose   = SetFunction(TheDevice, DEV_CLOSE,   RealClose);
  325.                NewExpunge = SetFunction(TheDevice, DEV_EXPUNGE, RealExpunge);
  326.  
  327.                if((NewBeginIO != (ULONG)myBeginIO)
  328.                    ||(NewClose != (ULONG)myClose)
  329.                      ||(NewExpunge != (ULONG)myExpunge))
  330.                   {
  331.                   /* Someone else has changed the vectors */
  332.                   /* We put theirs back - can't exit yet  */
  333.                   SetFunction(TheDevice, DEV_BEGINIO, NewBeginIO);                  SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  334.                   SetFunction(TheDevice, DEV_CLOSE,   NewClose);                  SetFunction(TheDevice, DEV_CLOSE  , NewClose);
  335.                   SetFunction(TheDevice, DEV_EXPUNGE, NewExpunge);
  336.                   }
  337.                else
  338.                   {
  339.                   Done = TRUE;
  340.                   }
  341.                Permit();
  342.                }
  343.             CloseDevice(myReq);
  344.             if(!Done)  message("Vectors have changed - can't restore\n");
  345.             }
  346.          }
  347.       MainBusy = FALSE;
  348.       }
  349.  
  350.    sprintf(sbuf,"\nCmd redirection of %s removed\n", deviceName);
  351.    cleanexit(sbuf);
  352.    }
  353.  
  354.  
  355. /* Cleanup and exits */
  356.  
  357. usageHelpExit()
  358.    { 
  359.    int k;
  360.    for(k=0; k<7; k++) printf(us[k]);
  361.    exit(RETURN_OK);
  362.    } 
  363.  
  364. usageExit()
  365.    { 
  366.    printf(u1);
  367.    printf(morehelp);
  368.    exit(RETURN_OK);
  369.    } 
  370.  
  371. cleanexit(s)
  372.    char  *s;
  373.    {
  374.    message(s);
  375.    cleanup();
  376.    exit(RETURN_OK);
  377.    }
  378.  
  379. cleanup()
  380.    {
  381.    if(myReq)   FreeMem(myReq,REQSIZE);
  382.    if(port)    DeletePort(port);
  383.    if(outFile) Close(outFile);
  384.  
  385.    Forbid();
  386.    if(prevTaskName) mainTask->tc_Node.ln_Name = prevTaskName;
  387.    Permit();
  388.    }
  389.  
  390.  
  391. message(s)
  392. char *s;
  393.    {
  394.    LONG con;
  395.  
  396.    if((!FromWb)&&(*s)) printf(s);
  397.    if((FromWb)&&(*s)&&(con = Open(conSpec,MODE_OLDFILE)))
  398.       {
  399.       Write(con,s,strlen(s));
  400.       Delay(120L);
  401.       Close(con);
  402.       }
  403.    }
  404.  
  405.  
  406. getWbArgs(wbMsg)
  407. struct WBStartup *wbMsg;
  408.    {
  409.    struct WBArg  *wbArg;
  410.    struct DiskObject *diskobj;
  411.    char **toolarray;
  412.    char *s;
  413.  
  414.    /* Defaults */
  415.    strcpy(wbDev,"parallel");
  416.    strcpy(wbFile,"ram:CMD_file");
  417.    Skip = FALSE;
  418.    Multiple = FALSE;
  419.    Notify = FALSE;
  420.  
  421.    wbArg = wbMsg->sm_ArgList;
  422.  
  423.    if((IconBase = OpenLibrary("icon.library", 0)))
  424.       {
  425.       diskobj=(struct DiskObject *)GetDiskObject(wbArg->wa_Name);
  426.       if(diskobj)
  427.          {
  428.          toolarray = (char **)diskobj->do_ToolTypes;
  429.  
  430.          if(s=(char *)FindToolType(toolarray,"DEVICE"))  strcpy(wbDev,s);
  431.          if(s=(char *)FindToolType(toolarray,"FILE"))    strcpy(wbFile,s);
  432.          if(s=(char *)FindToolType(toolarray,"SKIP"))
  433.             {
  434.             if(strEqu(s,"TRUE"))  Skip = TRUE;
  435.             }
  436.          if(s=(char *)FindToolType(toolarray,"MULTIPLE"))
  437.             {
  438.             if(strEqu(s,"TRUE"))  Multiple = TRUE;
  439.             }
  440.          if(s=(char *)FindToolType(toolarray,"NOTIFY"))
  441.             {
  442.             if(strEqu(s,"TRUE"))  Notify = TRUE;
  443.             }
  444.          FreeDiskObject(diskobj);
  445.          }
  446.       CloseLibrary(IconBase);
  447.       }
  448.    }
  449.  
  450.  
  451. /* String functions */
  452.  
  453. strEqu(p, q) 
  454. TEXT *p, *q; 
  455.    { 
  456.    while(TOUPPER(*p) == TOUPPER(*q))
  457.       {
  458.       if (*(p++) == 0)  return(TRUE);
  459.       ++q; 
  460.       }
  461.    return(FALSE);
  462.    } 
  463.  
  464. strlen(s)
  465. char *s;
  466.    {
  467.    int i = 0;
  468.    while(*s++) i++;
  469.    return(i);
  470.    }
  471.  
  472. strcpy(to,from)
  473. char *to, *from;
  474.    {
  475.    do
  476.       {
  477.       *to++ = *from;
  478.       }
  479.    while(*from++);
  480.    }
  481.  
  482. /* end */
  483.