home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / fish / disks / d1100.lha / Programs / Mirror / source / main.c
Encoding:
C/C++ Source or Header  |  1995-02-18  |  18.3 KB  |  659 lines

  1. /* -----------------------------------------------------------------------------
  2.  
  3.  Mirror API client, ©1995 Dietmar Eilert. Dice:
  4.  
  5.  dcc main.c -// -proto -mi -l reqtoolssr.lib -r -2.0 -o ram:mirror
  6.  
  7.   ------------------------------------------------------------------------------
  8. */
  9.  
  10. /// "includes"
  11.  
  12. #define Prototype extern
  13.  
  14. #include <exec/exec.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <dos/dos.h>
  19. #include <dos/dostags.h>
  20. #include <dos/rdargs.h>
  21. #include <intuition/intuition.h>
  22. #include <utility/tagitem.h>
  23. #include <workbench/startup.h>
  24. #include <rexx/errors.h>
  25. #include <rexx/rxslib.h>
  26. #include <clib/exec_protos.h>
  27. #include <clib/dos_protos.h>
  28. #include <clib/intuition_protos.h>
  29. #include <clib/rexxsyslib_protos.h>
  30. #include <clib/alib_protos.h>
  31. #include <clib/reqtools_protos.h>
  32.  
  33. #include "golded:api/include/golded.h"
  34.  
  35. struct Settings {
  36.  
  37.     UWORD  Range;                                    // range of lines to be considered
  38.     BOOL   Online;                                   // scanner online ?
  39.     UBYTE  Twins[255];                               // characters to look for
  40. };
  41.  
  42. Prototype void   main(int, char **);
  43. Prototype int    wbmain(struct WBStartup *);
  44. Prototype void   HandleAPI(char *, struct Settings *);
  45. Prototype ULONG *SendRexxCommand(char *, char *, struct MsgPort *, char *);
  46. Prototype BOOL   MatchingBracket(struct APIMessage *, struct Settings *, UWORD, BOOL);
  47. Prototype void   Dispatch(struct APIMessage *, struct Settings *);
  48. Prototype LONG   CommandMatch(ULONG *, struct APIMessage *, struct Settings *);
  49. Prototype BOOL   IsABracket(UBYTE, struct Settings *);
  50. Prototype BOOL   FindMarkedBracket(struct EditConfig *, struct Settings *);
  51. Prototype BOOL   NoUserBlock(struct EditConfig *, struct Settings *);
  52.  
  53. // globals
  54.  
  55. struct Library *ReqToolsBase;
  56.  
  57. ///
  58. /// "main"
  59.  
  60. int
  61. wbmain(struct WBStartup *startup)
  62. {
  63.     if (ReqToolsBase = OpenLibrary("reqtools.library", 37)) {
  64.  
  65.         rtEZRequestTags("No executable - to be used as API client", "OK", NULL, NULL, TAG_DONE);
  66.  
  67.         CloseLibrary(ReqToolsBase);
  68.     }
  69. }
  70.  
  71. void
  72. main(int argc, char **argv)
  73. {
  74.     static UBYTE version[] = "$VER: Mirror 1.3 (" __COMMODORE_DATE__ ")";
  75.  
  76.     ULONG argArray[] = { 0, 0, 0, 0, 0 };
  77.  
  78.     struct RDArgs *rdArgs;
  79.  
  80.     if (rdArgs = ReadArgs("H=HOST/K/A,RANGE/N,ONLINE/S,OFFLINE/S,TWINS/K", argArray, NULL)) {
  81.  
  82.         struct Settings settings = { 30, TRUE, "(){}[]" };
  83.  
  84.         if (argArray[1])                             // RANGE/N
  85.             settings.Range = *(ULONG *)argArray[1];
  86.  
  87.         if (argArray[2])
  88.             settings.Online = TRUE;                  // ONLINE/S
  89.  
  90.         if (argArray[3])
  91.             settings.Online = FALSE;                 // OFFLINE/S
  92.  
  93.         if (argArray[4])                             // TWINS/K
  94.             strcpy(settings.Twins, (char *)argArray[4]);
  95.  
  96.         HandleAPI((UBYTE *)argArray[0], &settings);
  97.  
  98.         FreeArgs(rdArgs);
  99.     }
  100.  
  101.     exit(0);
  102. }
  103.  
  104. ///
  105. /// "api management"
  106.  
  107. /* --------------------------------- HandleAPI ---------------------------------
  108.  
  109.  Register with GoldED & handle incoming API messages.
  110.  
  111. */
  112.  
  113. void
  114. HandleAPI(host, settings)
  115.  
  116. char            *host;
  117. struct Settings *settings;
  118. {
  119.     struct MsgPort *apiPort, *rexxPort;
  120.  
  121.     if (apiPort = CreateMsgPort()) {
  122.  
  123.         if (rexxPort = CreateMsgPort()) {
  124.  
  125.             UBYTE command[255];
  126.             ULONG *result;
  127.  
  128.             sprintf(command, "API PORT=%ld CLASS=%ld", apiPort, API_CLASS_ROOT | API_CLASS_KEY | API_CLASS_REXX);
  129.  
  130.             if (result = SendRexxCommand(host, command, rexxPort, NULL)) {
  131.  
  132.                 if (*result == RC_OK) {
  133.  
  134.                     BOOL active = TRUE;
  135.  
  136.                     do {
  137.  
  138.                         struct APIMessage *apiMsg, *nextMsg;
  139.  
  140.                         while (!(apiMsg = (struct APIMessage *)GetMsg(apiPort)))
  141.                             WaitPort(apiPort);
  142.  
  143.                         do {
  144.  
  145.                             for (nextMsg = apiMsg; nextMsg; nextMsg = nextMsg->api_Next) {
  146.  
  147.                                 if (nextMsg->api_State == API_STATE_NOTIFY) {
  148.  
  149.                                     switch (nextMsg->api_Class) {
  150.  
  151.                                         case API_CLASS_ROOT:
  152.  
  153.                                             switch (nextMsg->api_Action) {
  154.  
  155.                                                 case API_ACTION_DIE:
  156.  
  157.                                                     active = FALSE;
  158.                                                     break;
  159.  
  160.                                                 case API_ACTION_INTRODUCE:
  161.  
  162.                                                     static struct TagItem tags[] = {
  163.  
  164.                                                         API_Client_Name,      "Mirror",
  165.                                                         API_Client_Copyright, "Mirror ©1995 Dietmar Eilert",
  166.                                                         API_Client_Purpose,   "Online bracket highlighting",
  167.                                                         API_Client_Template,  "MIRROR CHECK/S,RANGE/N,ONLINE/S,OFFLINE/S",
  168.                                                         TAG_DONE
  169.                                                     };
  170.  
  171.                                                     nextMsg->api_Data = tags;
  172.                                                     break;
  173.  
  174.                                                 default:
  175.  
  176.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  177.                                             }
  178.  
  179.                                             break;
  180.  
  181.                                         case API_CLASS_KEY:
  182.  
  183.                                             switch (nextMsg->api_Action) {
  184.  
  185.                                                 case API_ACTION_VANILLAKEY:
  186.  
  187.                                                     if ((settings->Online) && NoUserBlock(apiMsg->api_Config, settings)) {
  188.  
  189.                                                         if (IsABracket((UBYTE)nextMsg->api_Data, settings) && MatchingBracket(nextMsg, settings, (UBYTE)nextMsg->api_Data, TRUE))
  190.  
  191.                                                             break;
  192.  
  193.                                                         else if (FindMarkedBracket(nextMsg->api_Config, settings))
  194.  
  195.                                                             apiMsg->api_Refresh |=  API_REFRESH_NOMARKER;
  196.                                                     }
  197.                                                     break;
  198.  
  199.                                                 default:
  200.  
  201.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  202.                                             }
  203.                                             break;
  204.  
  205.                                         case API_CLASS_REXX:
  206.  
  207.                                             switch (nextMsg->api_Action) {
  208.  
  209.                                                 case API_ACTION_COMMAND:
  210.  
  211.                                                     Dispatch(nextMsg, settings);
  212.                                                     break;
  213.  
  214.                                                 default:
  215.  
  216.                                                     nextMsg->api_Error = API_ERROR_UNKNOWN;
  217.                                             }
  218.                                             break;
  219.  
  220.                                         default:
  221.  
  222.                                             nextMsg->api_Error = API_ERROR_UNKNOWN;
  223.                                     }
  224.                                 }
  225.                             }
  226.  
  227.                             ReplyMsg((struct Message *)apiMsg);
  228.  
  229.                         } while (apiMsg = (struct APIMessage *)GetMsg(apiPort));
  230.  
  231.                     } while (active);
  232.                 }
  233.             }
  234.  
  235.             DeleteMsgPort(rexxPort);
  236.         }
  237.  
  238.         DeleteMsgPort(apiPort);
  239.     }
  240. }
  241.  
  242.  
  243. ///
  244. /// "arexx class"
  245.  
  246. /* --------------------------------- Dispatch ----------------------------------
  247.  
  248.  Dispatch incoming command: examine command string (command part is uppercase
  249.  already), look for handler function related to command, parse arguments (if 
  250.  command supports arguments), call handler.
  251.  
  252. */
  253.  
  254. void
  255. Dispatch(apiMsg, settings)
  256.  
  257. struct Settings   *settings;
  258. struct APIMessage *apiMsg;
  259. {
  260.     struct RDArgs *rdArgs, *args;
  261.  
  262.     if (rdArgs = AllocDosObject(DOS_RDARGS, NULL)) {
  263.  
  264.         static char buffer[1024];
  265.  
  266.         // table of supported commands, associated handlers & template strings
  267.  
  268.         static struct parser { char *command; LONG (*handler)(ULONG *, struct APIMessage *, struct Settings *); char *template; } parser[] = {
  269.  
  270.             "MIRROR", (APTR)CommandMatch, "CHECK/S,RANGE/N,ONLINE/S,OFFLINE/S,AUTOHIDE/S,TWINS/K",
  271.              NULL
  272.         };
  273.  
  274.         ULONG n, argArray[] = { 0, 0, 0, 0, 0, 0 };
  275.  
  276.         struct APIRexxNotify *notify = (struct APIRexxNotify *)apiMsg->api_Data;
  277.  
  278.         // make LF-terminated copy of command string (required by dos/readArgs):
  279.  
  280.         strcpy(buffer, notify->arn_Command);
  281.         strcat(buffer, "\12");
  282.  
  283.         for (n = 0; parser[n].command; ++n) {
  284.  
  285.             if (!memcmp(buffer, parser[n].command, strlen(parser[n].command))) {
  286.  
  287.                 char *arguments = buffer + strlen(parser[n].command);
  288.  
  289.                 rdArgs->RDA_Source.CS_Buffer = arguments;
  290.                 rdArgs->RDA_Source.CS_Length = strlen(arguments);
  291.                 rdArgs->RDA_Source.CS_CurChr = 0;
  292.                 rdArgs->RDA_DAList           = NULL;
  293.                 rdArgs->RDA_Buffer           = NULL;
  294.  
  295.                 if (parser[n].template) {
  296.  
  297.                     if (args = ReadArgs(parser[n].template, argArray, rdArgs)) {
  298.  
  299.                         notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, settings);
  300.  
  301.                         FreeArgs(args);
  302.                     }
  303.                     else {
  304.  
  305.                         static UBYTE errorText[81];
  306.  
  307.                         notify->arn_RC           = RC_WARN;
  308.                         notify->arn_CommandError = errorText;
  309.  
  310.                         Fault(IoErr(), "IoErr()", errorText, 80);
  311.                     }
  312.                 }
  313.                 else
  314.                     notify->arn_RC = (*parser[n].handler)(argArray, apiMsg, settings);
  315.             }
  316.         }
  317.  
  318.         FreeDosObject(DOS_RDARGS, rdArgs);
  319.     }
  320. }
  321.  
  322. /* -------------------------------- CommandMatch -------------------------------
  323.  
  324.  Highlight matching bracket
  325.  
  326.  template: CHECK/S,RANGE/N,ONLINE/S,OFFLINE/S,AUTOHIDE/S,TWINS/K
  327.  
  328. */
  329.  
  330. LONG
  331. CommandMatch(argArray, apiMsg, settings)
  332.  
  333. ULONG  *argArray;
  334.  
  335. struct APIMessage *apiMsg;
  336. struct Settings   *settings;
  337. {
  338.     UBYTE letter = apiMsg->api_Config->CurrentBuffer[apiMsg->api_Config->Column];
  339.  
  340.     apiMsg->api_State = API_STATE_CONSUMED;
  341.  
  342.     if (argArray[5])                                 // TWINS/K
  343.         strcpy(settings->Twins, (char *)argArray[5]);
  344.  
  345.     if (argArray[0] && IsABracket(letter, settings) && NoUserBlock(apiMsg->api_Config, settings))
  346.  
  347.         MatchingBracket(apiMsg, settings, letter, FALSE);
  348.  
  349.     else if (argArray[4] && FindMarkedBracket(apiMsg->api_Config, settings))
  350.  
  351.         apiMsg->api_Refresh |= API_REFRESH_NOMARKER; // AUTOHIDE/S
  352.  
  353.     if (argArray[1])                                 // RANGE/N
  354.         settings->Range = *(ULONG *)argArray[1];
  355.  
  356.     if (argArray[2])
  357.         settings->Online = TRUE;                     // ONLINE/S
  358.  
  359.     if (argArray[3])                                 // OFFLINE/S
  360.         settings->Online = FALSE;
  361.  
  362.     return(RC_OK);
  363. }
  364.  
  365. ///
  366. /// "online check"
  367.  
  368. /* ------------------------------- MatchingBracket --------------------------------
  369.  
  370.  Find matching bracket. Only <distance> lines  are  considered.  Ignore  opening
  371.  brackets  preceeded  by  '/' (ASCII 92, TeX style construction used to insert a
  372.  bracket into text). Set <pending> to TRUE if current character hasn't yet  been
  373.  inserted.
  374.  
  375. */
  376.  
  377. BOOL
  378. MatchingBracket(apiMsg, settings, examine, pending)
  379.  
  380. UWORD  examine;
  381. BOOL   pending;
  382. struct APIMessage *apiMsg;
  383. struct Settings   *settings;
  384. {
  385.     UBYTE *current, *known;
  386.     WORD   column, step, len;
  387.     BOOL   success, inString;
  388.     ULONG  line;
  389.  
  390.     struct EditConfig *config = apiMsg->api_Config;
  391.  
  392.     inString = FALSE;
  393.     success  = FALSE;
  394.     known    = settings->Twins;
  395.  
  396.     line     = config->Line;
  397.     column   = config->Column;
  398.     len      = config->CurrentLen;
  399.     current  = config->CurrentBuffer;
  400.  
  401.     for (step = 1; *known; ++known, step = -step) {
  402.  
  403.         if ((examine == *known) && ((column == 0) || (current[column - 1] != 92))) {
  404.  
  405.             WORD level, count, distance;
  406.             char twin;
  407.  
  408.             twin     = *(known + step);
  409.             count    = 0;
  410.             level    = (pending) ? 0 : -1;
  411.             distance = settings->Range;
  412.  
  413.             for (distance = 0; distance <= settings->Range; ++distance) {
  414.  
  415.                 while ((column >= 0) && (column < len)) {
  416.  
  417.                     char *next = current + column;
  418.  
  419.                     if ((*next == 34) || (*next == 39))
  420.  
  421.                         inString = !inString;
  422.  
  423.                     else if (!inString) {
  424.                         
  425.                         if ((*next == twin) && !(column && (*(next - 1) == 92))) {
  426.  
  427.                             if (level)
  428.                                 --level;
  429.  
  430.                             else {
  431.  
  432.                                 success = TRUE;
  433.                                 break;
  434.                             }
  435.                         }
  436.                         else if ((*next == *known) && !(column && (*(next - 1) == 92))) {
  437.  
  438.                             ++level;
  439.                             ++count;
  440.                         }
  441.                     }
  442.  
  443.                     column += step;
  444.                 }
  445.  
  446.                 if (success) {
  447.  
  448.                     BOOL adjacent = FALSE;
  449.  
  450.                     if (line == config->Line) {
  451.  
  452.                         if (pending)
  453.                             adjacent = ((step == -1) && (config->Column + step == column)) || ((step == 1) && (column == config->Column));
  454.                         else
  455.                             adjacent = (column == (config->Column + step));
  456.                     }
  457.  
  458.                     if (adjacent)
  459.  
  460.                         apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  461.  
  462.                     else {
  463.  
  464.                         if ((distance == 0) && ((config->Marker == BLOCKMODE_NONE) || ((line == config->BlockStartY) && (line == config->BlockEndY))))
  465.  
  466.                             apiMsg->api_Refresh = API_REFRESH_LINE;
  467.                         else
  468.                             apiMsg->api_Refresh = API_REFRESH_DISPLAY;
  469.  
  470.                         config->BlockStartX = config->BlockEndX = column;
  471.                         config->BlockStartY = config->BlockEndY = line;
  472.  
  473.                         config->Marker = BLOCKMODE_CHAR;
  474.                     }
  475.  
  476.                     return(TRUE);
  477.                 }
  478.                 else {
  479.  
  480.                     line    += step;
  481.                     inString = FALSE;
  482.  
  483.                     if ((line >= 0) && (line < config->Lines)) {
  484.  
  485.                         current = (config->TextNodes + line)->Text;
  486.                         len     = (config->TextNodes + line)->Len;
  487.  
  488.                         column = (step == -1) ? len - 1 : 0;
  489.                     }
  490.                     else                             // no matching bracket
  491.                         break;
  492.                 }
  493.             }
  494.  
  495.             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  496.  
  497.             break;
  498.         }
  499.     }
  500.  
  501.     return(FALSE);
  502. }
  503.  
  504.  
  505. ///
  506. /// "misc"
  507.  
  508. /* ------------------------------- NoUserBlock ---------------------------------
  509.  
  510.  Return TRUE if there is no user-defined block, i.e. either no block at all or a
  511.  marked bracket only (possibly marked by us).
  512.  
  513. */
  514.  
  515. BOOL
  516. NoUserBlock(config, settings)
  517.  
  518. struct EditConfig *config;
  519. struct Settings   *settings;
  520. {
  521.     return((config->Marker == BLOCKMODE_NONE) || FindMarkedBracket(config, settings));
  522. }
  523.  
  524.  
  525. /* -------------------------------- IsABracket ---------------------------------
  526.  
  527.  Check whether character is a bracket
  528.  
  529. */
  530.  
  531. BOOL
  532. IsABracket(letter, settings)
  533.  
  534. UBYTE  letter;
  535. struct Settings *settings;
  536. {
  537.     UBYTE *known;
  538.  
  539.     for (known = settings->Twins; *known; ++known)
  540.         if (letter == *known)
  541.             return(TRUE);
  542.  
  543.     return(FALSE);
  544. }
  545.  
  546. /* ----------------------------- FindMarkedBracket -----------------------------
  547.  
  548.  Return TRUE if a single bracket has been marked
  549.  
  550. */
  551.  
  552. BOOL
  553. FindMarkedBracket(config, settings)
  554.  
  555. struct EditConfig *config;
  556. struct Settings   *settings;
  557. {
  558.     if (config->Marker == BLOCKMODE_CHAR) {
  559.  
  560.         if (config->BlockStartY == config->BlockEndY) {
  561.  
  562.             if (config->BlockStartX == config->BlockEndX) {
  563.  
  564.                 UWORD pos = config->BlockStartX;
  565.  
  566.                 if (config->BlockStartY == config->Line) {
  567.  
  568.                     if (pos < config->CurrentLen)
  569.                         return(IsABracket(config->CurrentBuffer[pos], settings));
  570.                 }
  571.                 else {
  572.  
  573.                     struct LineNode *lineNode = config->TextNodes + config->BlockStartY;
  574.  
  575.                     if (pos < lineNode->Len)
  576.                         return(IsABracket(lineNode->Text[config->BlockStartX], settings));
  577.                 }
  578.  
  579.             }
  580.  
  581.         }
  582.     }
  583.  
  584.     return(FALSE);
  585. }
  586.  
  587.  
  588.  
  589. ///
  590. /// "arexx"
  591.  
  592. /* ---------------------------------- SendRexxCommand -------------------------
  593.  
  594.  Send ARexx message & wait for answer. Return pointer to result or NULL.
  595.  
  596. */
  597.  
  598. ULONG *
  599. SendRexxCommand(port, cmd, replyPort, buffer)
  600.  
  601. char   *cmd, *port, *buffer;
  602. struct MsgPort *replyPort;
  603. {
  604.     struct MsgPort *rexxport;
  605.  
  606.     Forbid();
  607.  
  608.     if (rexxport = FindPort(port)) {
  609.  
  610.         struct RexxMsg *rexxMsg, *answer;
  611.  
  612.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  613.  
  614.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  615.  
  616.                 static ULONG result;
  617.  
  618.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  619.  
  620.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  621.  
  622.                 do {
  623.                     
  624.                     WaitPort(replyPort);
  625.  
  626.                     if (answer = (struct RexxMsg *)GetMsg(replyPort))
  627.                         result = answer->rm_Result1;
  628.  
  629.                 } while (!answer);
  630.  
  631.                 Permit();
  632.  
  633.                 if (answer->rm_Result1 == RC_OK) {
  634.  
  635.                     if (answer->rm_Result2) {
  636.  
  637.                         if (buffer)
  638.                             strcpy(buffer, (char *)answer->rm_Result2);
  639.  
  640.                         DeleteArgstring((char *)answer->rm_Result2);
  641.                     }
  642.                 }
  643.  
  644.                 DeleteArgstring((char *)ARG0(answer));
  645.  
  646.                 DeleteRexxMsg(answer);
  647.  
  648.                 return(&result);
  649.             }
  650.         }
  651.     }
  652.  
  653.     Permit();
  654.  
  655.     return(NULL);
  656. }
  657.  
  658. ///
  659.