home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Texteditors / GoldED Tools / Mirror / source / main.c
Encoding:
C/C++ Source or Header  |  1996-09-27  |  19.6 KB  |  695 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.5 (" __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. Ignore opening brackets preceeded by '/' (ASCII 92, TeX
  371.  style construction used to insert a bracket into text). Set <pending> to TRUE
  372.  if current character hasn't yet been inserted.
  373.  
  374.  \} ............ ignored      (TEX constant)
  375.  \\} ........... not ignored  (TEX bracket)
  376.  
  377. */
  378.  
  379. BOOL
  380. MatchingBracket(apiMsg, settings, examine, pending)
  381.  
  382. UWORD  examine;
  383. BOOL   pending;
  384. struct APIMessage *apiMsg;
  385. struct Settings   *settings;
  386. {
  387.     UBYTE *known;
  388.     WORD   step;
  389.  
  390.     for (step = 1, known = settings->Twins; *known; ++known, step = -step) {
  391.  
  392.         if (examine == *known) {
  393.  
  394.             WORD   column;
  395.             UBYTE *current;
  396.             BOOL   isTEX;
  397.  
  398.             struct EditConfig *config = apiMsg->api_Config;
  399.  
  400.             column  = config->Column;
  401.             current = config->CurrentBuffer;
  402.  
  403.             if ((column > 0) && (current[column - 1] == 92)) {
  404.  
  405.                 if ((column > 1) && (current[column - 2] == 92))
  406.                     isTEX = FALSE;
  407.                 else
  408.                     isTEX = TRUE;
  409.             }
  410.             else
  411.                 isTEX = FALSE;
  412.  
  413.             if (isTEX == FALSE) {
  414.  
  415.                 WORD   len, level, count, distance;
  416.                 BOOL   success, inString;
  417.                 ULONG  line;
  418.                 UBYTE  twin;
  419.  
  420.                 inString = FALSE;
  421.                 success  = FALSE;
  422.  
  423.                 line     = config->Line;
  424.                 len      = config->CurrentLen;
  425.  
  426.                 twin     = *(known + step);
  427.                 count    = 0;
  428.                 level    = (pending) ? 0 : -1;
  429.                 distance = settings->Range;
  430.  
  431.                 for (distance = 0; distance <= settings->Range; ++distance) {
  432.  
  433.                     while ((column >= 0) && (column < len)) {
  434.  
  435.                         UBYTE *next = current + column;
  436.  
  437.                         if ((*next == 34) || (*next == 39))
  438.  
  439.                             inString = !inString;
  440.  
  441.                         else if (!inString) {
  442.                             
  443.                             if ((column > 0) && (*(next - 1) == 92)) {
  444.  
  445.                                 if ((column > 1) && (*(next - 2) == 92))
  446.                                     isTEX = FALSE;
  447.                                 else
  448.                                     isTEX = TRUE;
  449.                             }
  450.                             else
  451.                                 isTEX = FALSE;
  452.  
  453.                             if (!isTEX) {
  454.  
  455.                                 if (*next == twin) {
  456.  
  457.                                     if (level)
  458.                                         --level;
  459.  
  460.                                     else {
  461.  
  462.                                         success = TRUE;
  463.                                         break;
  464.                                     }
  465.                                 }
  466.                                 else if (*next == *known) {
  467.  
  468.                                     ++level;
  469.                                     ++count;
  470.                                 }
  471.                             }
  472.                         }
  473.  
  474.                         column += step;
  475.                     }
  476.  
  477.                     if (success) {
  478.  
  479.                         BOOL adjacent = FALSE;
  480.  
  481.                         if (line == config->Line) {
  482.  
  483.                             if (pending)
  484.                                 adjacent = ((step == -1) && (config->Column + step == column)) || ((step == 1) && (column == config->Column));
  485.                             else
  486.                                 adjacent = (column == (config->Column + step));
  487.                         }
  488.  
  489.                         if (adjacent)
  490.  
  491.                             apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  492.  
  493.                         else {
  494.  
  495.                             if ((distance == 0) && ((config->Marker == BLOCKMODE_NONE) || ((line == config->BlockStartY) && (line == config->BlockEndY))))
  496.  
  497.                                 apiMsg->api_Refresh = API_REFRESH_LINE;
  498.  
  499.                             else if (config->Marker == BLOCKMODE_NONE)
  500.  
  501.                                 apiMsg->api_Refresh = API_REFRESH_MARKER;
  502.                             else
  503.                                 apiMsg->api_Refresh = API_REFRESH_DISPLAY;
  504.  
  505.                             config->BlockStartX = config->BlockEndX = column;
  506.                             config->BlockStartY = config->BlockEndY = line;
  507.  
  508.                             config->Marker = BLOCKMODE_CHAR;
  509.                         }
  510.  
  511.                         return(TRUE);
  512.                     }
  513.                     else {
  514.  
  515.                         line    += step;
  516.                         inString = FALSE;
  517.  
  518.                         if ((line >= 0) && (line < config->Lines)) {
  519.  
  520.                             current = (config->TextNodes + line)->Text;
  521.                             len     = (config->TextNodes + line)->Len;
  522.  
  523.                             column = (step == -1) ? len - 1 : 0;
  524.                         }
  525.                         else                             // no matching bracket
  526.                             break;
  527.                     }
  528.                 }
  529.  
  530.                 apiMsg->api_Refresh |= API_REFRESH_NOMARKER;
  531.  
  532.                 break;
  533.             }
  534.         }
  535.     }
  536.  
  537.     return(FALSE);
  538. }
  539.  
  540.  
  541. ///
  542. /// "misc"
  543.  
  544. /* ------------------------------- NoUserBlock ---------------------------------
  545.  
  546.  Return TRUE if there is no user-defined block, i.e. either no block at all or a
  547.  marked bracket only (possibly marked by us).
  548.  
  549. */
  550.  
  551. BOOL
  552. NoUserBlock(config, settings)
  553.  
  554. struct EditConfig *config;
  555. struct Settings   *settings;
  556. {
  557.     return((config->Marker == BLOCKMODE_NONE) || FindMarkedBracket(config, settings));
  558. }
  559.  
  560.  
  561. /* -------------------------------- IsABracket ---------------------------------
  562.  
  563.  Check whether character is a bracket
  564.  
  565. */
  566.  
  567. BOOL
  568. IsABracket(letter, settings)
  569.  
  570. UBYTE  letter;
  571. struct Settings *settings;
  572. {
  573.     UBYTE *known;
  574.  
  575.     for (known = settings->Twins; *known; ++known)
  576.         if (letter == *known)
  577.             return(TRUE);
  578.  
  579.     return(FALSE);
  580. }
  581.  
  582. /* ----------------------------- FindMarkedBracket -----------------------------
  583.  
  584.  Return TRUE if a single bracket has been marked
  585.  
  586. */
  587.  
  588. BOOL
  589. FindMarkedBracket(config, settings)
  590.  
  591. struct EditConfig *config;
  592. struct Settings   *settings;
  593. {
  594.     if (config->Marker == BLOCKMODE_CHAR) {
  595.  
  596.         if (config->BlockStartY == config->BlockEndY) {
  597.  
  598.             if (config->BlockStartX == config->BlockEndX) {
  599.  
  600.                 UWORD pos = config->BlockStartX;
  601.  
  602.                 if (config->BlockStartY == config->Line) {
  603.  
  604.                     if (pos < config->CurrentLen)
  605.                         return(IsABracket(config->CurrentBuffer[pos], settings));
  606.                 }
  607.                 else {
  608.  
  609.                     struct LineNode *lineNode = config->TextNodes + config->BlockStartY;
  610.  
  611.                     if (pos < lineNode->Len)
  612.                         return(IsABracket(lineNode->Text[config->BlockStartX], settings));
  613.                 }
  614.  
  615.             }
  616.  
  617.         }
  618.     }
  619.  
  620.     return(FALSE);
  621. }
  622.  
  623.  
  624.  
  625. ///
  626. /// "arexx"
  627.  
  628. /* ---------------------------------- SendRexxCommand -------------------------
  629.  
  630.  Send ARexx message & wait for answer. Return pointer to result or NULL.
  631.  
  632. */
  633.  
  634. ULONG *
  635. SendRexxCommand(port, cmd, replyPort, buffer)
  636.  
  637. char   *cmd, *port, *buffer;
  638. struct MsgPort *replyPort;
  639. {
  640.     struct MsgPort *rexxport;
  641.  
  642.     Forbid();
  643.  
  644.     if (rexxport = FindPort(port)) {
  645.  
  646.         struct RexxMsg *rexxMsg, *answer;
  647.  
  648.         if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
  649.  
  650.             if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
  651.  
  652.                 static ULONG result;
  653.  
  654.                 rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
  655.  
  656.                 PutMsg(rexxport, &rexxMsg->rm_Node);
  657.  
  658.                 do {
  659.                     
  660.                     WaitPort(replyPort);
  661.  
  662.                     if (answer = (struct RexxMsg *)GetMsg(replyPort))
  663.                         result = answer->rm_Result1;
  664.  
  665.                 } while (!answer);
  666.  
  667.                 Permit();
  668.  
  669.                 if (answer->rm_Result1 == RC_OK) {
  670.  
  671.                     if (answer->rm_Result2) {
  672.  
  673.                         if (buffer)
  674.                             strcpy(buffer, (char *)answer->rm_Result2);
  675.  
  676.                         DeleteArgstring((char *)answer->rm_Result2);
  677.                     }
  678.                 }
  679.  
  680.                 DeleteArgstring((char *)ARG0(answer));
  681.  
  682.                 DeleteRexxMsg(answer);
  683.  
  684.                 return(&result);
  685.             }
  686.         }
  687.     }
  688.  
  689.     Permit();
  690.  
  691.     return(NULL);
  692. }
  693.  
  694. ///
  695.