home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / SASC6571.LZX / examples / cback / schelp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-24  |  14.7 KB  |  436 lines

  1. /*
  2.     SAS/C® Background Example
  3.     SAS/C Help System Hot-Key Example
  4.     version 6.50   1993
  5.     
  6.     Copyright (c) 1993 SAS Institute, Inc, Cary, NC USA
  7.     All Rights Reserved
  8.  
  9.     This is a program which demonstrates how to write a background process which
  10.     employs a hot-key.  This program will pop up the main interface to the
  11.     SAS/C Help System when control-Help is pressed. 
  12.  
  13.     You should compile this program with the following options:
  14.  
  15.                NOSTACKCHECK
  16.                STRUCTUREEQUIVALENCE
  17.                LINK
  18.                STARTUP=cback
  19.  
  20.     NOSTACKCHECK is suggested because the function handlerStuff can be called
  21.     from a task other than this program.  It would be required if the function
  22.     was not declared with the __interrupt keyword.  This is discussed in more
  23.     detail at the function's definition.
  24.  
  25.     STRUCTUREEQUIVALENCE is not required, but it does circumvent several
  26.     warnings that would otherwise be produced.
  27.  
  28.     STARTUP=cback tells slink to link with the background startup code.  This
  29.     is required to produce a background process.  If you link in a separate step,
  30.     you must link with cback.o instead of c.o.
  31.  
  32.     You may notice that this program does not open any AmigaDOS libraries.  Instead
  33.     it takes advantage of the fact that the version 6.0 compiler now opens
  34.     needed libraries for you.
  35.  
  36.     ****  IMPORTANT  ***
  37.     When running CPR on this program or other programs using __main, you
  38.     must perform the following 2 steps to avoid crashing the machine:
  39.     
  40.            1)  As soon as cpr is invoked, select Catch New Tasks from the
  41.                Options menu.  Catch New Tasks must be set to on.
  42.                
  43.            2)  Type 
  44.                     go __main
  45.                     
  46.                This places you at the beginning of your code.  If you say
  47.                go __main without setting Catch New Tasks to on, you will
  48.                probably crash the machine.  
  49.                
  50.      If you try to debug the input handler program HandlerInterface in this
  51.      program, you will probably crash your machine. 
  52.  
  53.      The schelp command takes the following forms:
  54.      
  55.                  schelp
  56.      
  57.      This command will load schelp as a background process, display a copyright
  58.      banner, and display the usage information.  If schelp is already loaded,
  59.      it will simply display the usage information.
  60.      
  61.                  schelp quit
  62.                  
  63.      This command will display a terminating message and unload schelp from
  64.      memory.            
  65.      
  66.                  schelp <command>
  67.                  
  68.      This command will replace the command currently tied to the control-Help
  69.      key with the command designated.  In order for the command to work, it 
  70.      must contain the full path to the command.            
  71.  
  72. */
  73.  
  74. /**************************  INCLUDES  ************************/
  75. #include <exec/types.h>
  76. #include <exec/nodes.h>
  77. #include <exec/lists.h>
  78. #include <exec/memory.h>
  79. #include <exec/interrupts.h>
  80. #include <exec/ports.h>
  81. #include <exec/libraries.h>
  82. #include <exec/io.h>
  83. #include <exec/tasks.h>
  84. #include <exec/execbase.h>
  85. #include <exec/devices.h>
  86. #include <devices/timer.h>
  87. #include <devices/input.h>
  88. #include <devices/inputevent.h>
  89. #include <intuition/intuition.h>
  90. #include <libraries/dos.h>
  91. #include <graphics/gfxmacros.h>
  92. #include <hardware/custom.h>
  93. #include <hardware/dmabits.h>
  94. #include <proto/dos.h>
  95. #include <proto/exec.h>
  96. #include <proto/intuition.h>
  97. #include <proto/graphics.h>
  98. #include <string.h>
  99. #include <stdlib.h>
  100.  
  101.  
  102.  
  103.  
  104. /**************************  CONSTANTS  ***********************/
  105. #define BANNER       "\x9B""0;33mSAS/C® Help\x9B""0m Copyright \xA9 1992-1993 SAS Institute, Inc.\n"
  106. #define BANNER1  "Usage: \x9B""1mschelp\x9B""0m [quit] [<command>]\nwhere\n\x9B""1mschelp\x9B""0m           allows you to hit cntrl-Help to pop up the SAS/C Help screen\n\x9B""1mschelp quit\x9B""0m      deletes schelp as a background process\n"
  107. #define BANNER2  "\x9B""1mschelp <command>\x9B""0m allows you to change the command executed when you hit cntrl-Help\n                   *** Include full path to the command\n"
  108. #define DEFCMD       "sc:c/amigaguide sc:help/sc_help.guide\0"
  109. #define DEFKEY       0x5F
  110. #define KILLMSG      "\x9B""1mSAS/C Help\x9B""0m Terminating\n"
  111. #define MAXCMD       200
  112. #define PORTNAME     "SASC_HELP.port"
  113.  
  114. static const char __version[] = "$VER: SASC_schelp 6.50 (26.08.93)";
  115.  
  116. /*********************** GLOBAL VARIABLES *********************/
  117. typedef struct
  118.    {
  119.    struct Task          *buddy;
  120.    ULONG                 helpsig;
  121.    short                 helpsignum;
  122.    short                 key;
  123.    } GLOBAL_DATA;
  124.  
  125. struct OURMSG {
  126.  struct Message msg_header;
  127.  short  quit;
  128.  char   cmd[MAXCMD];
  129.  };
  130.  
  131.  
  132. typedef void (*vfunc)();
  133.  
  134.  
  135. /**************************  PROTOTYPES  **********************/
  136. void clean_exit(struct IOStdReq *, struct Interrupt, GLOBAL_DATA,
  137.                 struct MsgPort *, BPTR, BPTR, struct MsgPort *,int);
  138.  
  139. struct InputEvent * __asm HandlerInterface(register __a0 struct InputEvent *,
  140.                                     register __a1 GLOBAL_DATA *);
  141.  
  142. struct IOStdReq *CreateIOReq(struct MsgPort *, int);
  143.  
  144. void DeleteIOReq(struct IOStdReq *);
  145.  
  146.  
  147.  
  148. /**********************  CBACK DECLARATIONS  ******************/
  149. long __stack = 4000;              /* Amount of stack space our task needs */
  150. char *__procname = "SAS/C® Help"; /* The name of the task to create       */
  151. long __priority = 20;             /* The priority to run the task at    */
  152. long __BackGroundIO = 1;          /* Flag indicating we want to send I/O to the
  153.                                      original shell.  We will print a banner.
  154.                                      NOTE:  This variable may also be called
  155.                                      _BackGroundIO.  Notice the single
  156.                                      underscore.                       */
  157. extern BPTR _Backstdout;          /* File handle pointing to originating shell
  158.                                      (standard output when run in background) */
  159.  
  160. /********************************************************************/
  161.  
  162. void __stdargs __main(char *command)
  163. {
  164.    struct OURMSG *msg, tmpmsg;
  165.    struct MsgPort *port;
  166.    int first_call = 0;
  167.  
  168.    char cmdstr[MAXCMD];
  169.    BPTR  nullfh1, nullfh2;
  170.    ULONG sig;
  171.    struct MsgPort     *inputDevPort;
  172.    struct IOStdReq    *inputRequestBlock;
  173.    struct Interrupt   handlerStuff;
  174.    GLOBAL_DATA global;
  175.  
  176.    global.helpsignum  = -1;
  177.    inputDevPort        = NULL;
  178.    inputRequestBlock   = NULL;
  179.    nullfh1 = nullfh2 = NULL;
  180.  
  181.    /* Check if this program is already loaded, and if not, create a port  */
  182.    if ((port = FindPort(PORTNAME)) == NULL)
  183.       {
  184.       /* Set flag indicating this is the first time the program's been called */
  185.       first_call = 1;
  186.  
  187.       /* Since this is the first call, open the port */
  188.       if ((port = CreatePort(PORTNAME,0)) == NULL)
  189.           clean_exit(inputRequestBlock, handlerStuff, global, inputDevPort,
  190.                 nullfh1, nullfh2, port, first_call);
  191.       }
  192.  
  193.  
  194.    /* Allocate memory for and partially set up the message this program
  195.       will send to itself.                                             */
  196.    if ((msg = (struct OURMSG *)
  197.               AllocMem(sizeof(struct OURMSG), MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  198.       clean_exit(inputRequestBlock, handlerStuff, global, inputDevPort,
  199.                  nullfh1, nullfh2, port, first_call);
  200.  
  201.    msg->msg_header.mn_Length = sizeof(struct OURMSG);
  202.    msg->quit = 0;
  203.    msg->cmd[0] = 0;
  204.  
  205.    /*  Set up the command to be executed to start SAS/C Help  */
  206.    strcpy(cmdstr, DEFCMD);
  207.  
  208.    /* If this program was run from a CLI, then output the banner
  209.       and process any parameters */
  210.    if (command && *command)
  211.       {
  212.       /* Write the copyright banner if this is the first time the program
  213.          was called.                                                     */
  214.       if (first_call && _Backstdout)
  215.          Write(_Backstdout, BANNER, sizeof(BANNER));
  216.  
  217.       /* Skip to a parameter if one exists */
  218.       while(*command != ' ')
  219.          command++;
  220.       while(*command == ' ')
  221.          command++;
  222.  
  223.  
  224.       /* Evaluate the parameter */
  225.       if (!stricmp(command, "QUIT\n"))
  226.          {
  227.          msg->quit = 1;
  228.          if (_Backstdout)
  229.             Write(_Backstdout, KILLMSG, sizeof(KILLMSG));
  230.          }
  231.  
  232.       /*  If all that is left is a carriage return, print out the usage message */
  233.       else if ((*command < ' ') && _Backstdout)
  234.          {
  235.          Write(_Backstdout, BANNER1, sizeof(BANNER1));
  236.          Write(_Backstdout, BANNER2, sizeof(BANNER2));
  237.          }
  238.       /* Put the rest of the command into the command string to be executed  */
  239.       else
  240.          {
  241.          strcpy(msg->cmd, command);
  242.          msg->cmd[strlen(command)-1] = 0;  /* wipe out the EOL character */
  243.          }
  244.       }
  245.  
  246.    /*  Send the message with instructions on actions to SAS/C Help's port  */
  247.    PutMsg (port,(struct Message *) msg);
  248.  
  249.    /*  If this is the first time this program is called, set up the input
  250.        handler, etc.   */
  251.    if (!first_call)
  252.       clean_exit(inputRequestBlock, handlerStuff, global, inputDevPort,
  253.                 nullfh1, nullfh2, port, first_call);
  254.  
  255.    /* Close _Backstdout so that the original window can go away */
  256.    if (_Backstdout)
  257.       Close(_Backstdout);
  258.  
  259.    _Backstdout = 0;
  260.  
  261.  
  262.    /* set the input and output streams to 0 so execute doen't complain */
  263.    nullfh1 = Open("NIL:", MODE_NEWFILE);
  264.    nullfh2 = Open("NIL:", MODE_NEWFILE);
  265.  
  266.    if (((inputDevPort = CreatePort(0,0)) == NULL)  ||
  267.  
  268.       ((inputRequestBlock =
  269.           CreateIOReq(inputDevPort, sizeof(struct IOStdReq))) == NULL)  ||
  270.  
  271.       ((global.helpsignum = AllocSignal(-1)) == -1)  ||
  272.  
  273.       OpenDevice("input.device",0,(struct IORequest *)inputRequestBlock,0))
  274.  
  275.       clean_exit(inputRequestBlock, handlerStuff, global, inputDevPort,
  276.                 nullfh1, nullfh2, port, first_call);
  277.  
  278.    /*  Set up stuff for input handler  */
  279.    handlerStuff.is_Data = (APTR) &global;
  280.    handlerStuff.is_Code = (vfunc) HandlerInterface;
  281.    handlerStuff.is_Node.ln_Pri = 51;
  282.  
  283.    /*  Set up global data to be used by input handler  */
  284.    global.buddy = FindTask(0);
  285.    global.helpsig  = 1 << global.helpsignum;
  286.    global.key = DEFKEY;
  287.  
  288.    inputRequestBlock->io_Command = IND_ADDHANDLER;
  289.    inputRequestBlock->io_Data    = (APTR)&handlerStuff;
  290.  
  291.    DoIO((struct IORequest *)inputRequestBlock);
  292.  
  293.    for(;;)         /* FOREVER */
  294.       {
  295.       sig = Wait( global.helpsig | (1 << port->mp_SigBit) );
  296.  
  297.       /* Check contents of message and quit or change the command to be
  298.          executed                                                     */
  299.       if (sig & (1 << port->mp_SigBit))
  300.          {
  301.          while ((msg = (struct OURMSG *)GetMsg(port)) != NULL)
  302.             {
  303.             tmpmsg = *msg;
  304.             ReplyMsg ( (struct Message *) msg);
  305.             if (tmpmsg.quit)
  306.                clean_exit(inputRequestBlock, handlerStuff, global,
  307.                           inputDevPort, nullfh1, nullfh2, port, first_call);
  308.             if (tmpmsg.cmd[0])
  309.                strcpy(cmdstr, msg->cmd);
  310.             }
  311.          }
  312.  
  313.       /*  Execute the command  */
  314.       if (sig & global.helpsig)
  315.          {
  316.          (void)Execute(cmdstr,nullfh1,nullfh2);
  317.          }
  318.       }
  319. }
  320.  
  321. /********************************************************************/
  322.  
  323. /*  Clean up and exit */
  324. void clean_exit(struct IOStdReq *inputRequestBlock, struct Interrupt
  325.      handlerStuff, GLOBAL_DATA global, struct MsgPort *inputDevPort,
  326.      BPTR nullfh1, BPTR nullfh2, struct MsgPort * port, int first_call)
  327. {
  328.    if(_Backstdout)
  329.       Close(_Backstdout);
  330.  
  331.    if (inputRequestBlock != NULL)
  332.       {
  333.       if (inputRequestBlock->io_Device != NULL)
  334.          {
  335.          inputRequestBlock->io_Command = IND_REMHANDLER;
  336.          inputRequestBlock->io_Data = (APTR)&handlerStuff;
  337.          DoIO((struct IORequest *)inputRequestBlock);
  338.  
  339.          CloseDevice((struct IORequest *)inputRequestBlock);
  340.          }
  341.       DeleteIOReq(inputRequestBlock);
  342.       }
  343.    if (global.helpsignum != -1)   
  344.        FreeSignal(global.helpsignum);
  345.    if (inputDevPort != NULL)       
  346.        DeletePort(inputDevPort);
  347.    if (first_call && (port != NULL)) 
  348.        DeletePort(port);
  349.    if (nullfh1)  
  350.        Close(nullfh1);
  351.    if (nullfh2)  
  352.        Close(nullfh2);
  353.  
  354.    exit(0);
  355. }
  356.  
  357.  
  358.  
  359. /************************************************************************/
  360.  
  361. /* This routine is the input handler function.  It is put into the input
  362.    handler list at a priority above Intuition's so that it can check
  363.    all input for the SAS/C Help key sequence.                           */
  364.  
  365. /* Note the use of the __interrupt keyword below.  This is used to   */
  366. /* prohibit the generation of stack-checking or stack-extension code */
  367. /* if the module is compiled with the STACKCHECK or STACKEXT options.*/
  368. /* (STACKCHECK is the default).  Because this function is called     */
  369. /* directly from input.device, it will be using input.device's stack */
  370. /* and not the program's stack; hence code that relies on using the  */
  371. /* program's stack must be disabled.                                 */
  372.  
  373. struct InputEvent * __saveds __interrupt __asm HandlerInterface(
  374.                      register __a0 struct InputEvent *event,
  375.                      register __a1 GLOBAL_DATA *gptr)
  376. {
  377.    register struct InputEvent *cur_event, *last_event;
  378.  
  379.    /* Step through the event list, checking for SAS/C Help key sequence  */
  380.    for (cur_event = event, last_event = NULL; cur_event != NULL;
  381.                    cur_event = cur_event->ie_NextEvent)
  382.       {
  383.       if ((cur_event->ie_Class == IECLASS_RAWKEY)    &&
  384.           (cur_event->ie_Code  == gptr->key)         &&
  385.           (cur_event->ie_Qualifier & IEQUALIFIER_CONTROL))
  386.          {
  387.          /*  This event was our key sequence, so take it off of the event chain */
  388.          if (last_event == NULL)
  389.             event = cur_event->ie_NextEvent;
  390.          else
  391.             event = last_event->ie_NextEvent = cur_event->ie_NextEvent;
  392.  
  393.          /* Notify the SAS/C Help task to pop up the help window */
  394.          Signal(gptr->buddy, gptr->helpsig);
  395.          }
  396.       else
  397.          last_event = cur_event;
  398.  
  399.       }
  400.    /* Return the pointer to the event */
  401.    return(event);
  402. }
  403.  
  404.  
  405. /************************************************************************/
  406.  
  407.  
  408. struct IOStdReq *CreateIOReq(struct MsgPort *port, int size)
  409. {
  410.    struct IOStdReq *ioReq;
  411.  
  412.    if ((ioReq = (struct IOStdReq *)
  413.                 AllocMem(size, MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
  414.       {
  415.       ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  416.       ioReq->io_Message.mn_Node.ln_Pri  = 0;
  417.       ioReq->io_Message.mn_Length       = size;
  418.       ioReq->io_Message.mn_ReplyPort    = port;
  419.       }
  420.    return(ioReq);
  421. }
  422.  
  423.  
  424. /************************************************************************/
  425.  
  426.  
  427.  
  428. void DeleteIOReq (struct IOStdReq *ioReq)
  429. {
  430.    ioReq->io_Message.mn_Node.ln_Type = 0xff;
  431.    ioReq->io_Device = (struct Device *) -1;
  432.    ioReq->io_Unit = (struct Unit *) -1;
  433.  
  434.    FreeMem( (char *)ioReq, ioReq->io_Message.mn_Length);
  435. }
  436.