home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit4f / ckmkey.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  24KB  |  943 lines

  1. /*
  2.  * CKMKEY.C
  3.  *
  4.  * This file contains all procedures and data related to the handling
  5.  * of key macros.
  6.  *
  7.  * Matthias Aebi, ECOFIN Research and Consulting, Ltd., Oct 1987
  8.  *
  9.  * Chaged 12/11/87 Paul Placeway @ Ohio State University: changed the
  10.  *  internal storage of a key macro from a C string to a Pascal string
  11.  *  (so that I could bind Control-Space to send ASCII NUL (0x00)
  12.  *
  13.  * Copyright (C) 1985, Trustees of Columbia University in the City of
  14.  * New York.  Permission is granted to any individual or institution to
  15.  * use, copy, or redistribute this software so long as it is not sold
  16.  * for profit, provided this copyright notice is retained.
  17.  *
  18.  */
  19.  
  20. #include "ckcdeb.h"        /* Kermit definitions */
  21. #include "ckcker.h"        /* Kermit definitions */
  22.  
  23. #define    __SEG__ ckmkey
  24. #include <resources.h>
  25. #include <events.h>
  26. #include <dialogs.h>
  27. #include <controls.h>
  28. #include <toolutils.h>
  29. #include <Memory.h>
  30. #include <ctype.h>
  31.  
  32. #include "ckmdef.h"        /* Common Mac module definitions */
  33. #include "ckmres.h"        /* resource defs */
  34.  
  35.  
  36. /* KSET This structure tells for which key / modifier combinations */
  37. /* there is a special macro declaration. */
  38. /* MSET This structure holds all macrokey definitons in a packed */
  39. /* form. To be useful it has to be unpacked into a macrodefs     */
  40. /* structure. */
  41.  
  42. hmacrodefs macroshdl;
  43.  
  44. char keytable[512];
  45.  
  46.  
  47.  
  48. /****************************************************************************/
  49. /* Look for a macrodefinition for theCode and return its table index if */
  50. /* found or -1 if not found */
  51. /****************************************************************************/
  52. short
  53. FindMacro (theCode)
  54. short theCode;
  55. {
  56.     short i;
  57.     short num;
  58.     macrodefs *macros;
  59.  
  60.     macros = *macroshdl;
  61.  
  62.     num = macros->numOfMacros;
  63.     for (i = 0; (i < num) && (macros->mcr[i].code != theCode); i++);
  64.  
  65.     if (i >= num)
  66.     return (-1);
  67.     else
  68.     return (i);
  69. }                /* FindMacro */
  70.  
  71.  
  72.  
  73. /****************************************************************************/
  74. /* Set theCode at theIndex to -1 which means this entry is empty. Release */
  75. /* the memory block occupied to save the macrostring if necessary */
  76. /****************************************************************************/
  77. DeleteMacro (theIndex)
  78. short theIndex;
  79. {
  80.     macrodefs *macros;
  81.  
  82.     macros = *macroshdl;
  83.  
  84.     macros->mcr[theIndex].code = -1;
  85.     if (macros->mcr[theIndex].len > 4)    /* release memory block if there is
  86.                      * one */
  87.     DisposPtr ((Ptr) macros->mcr[theIndex].macro);
  88. }                /* DeleteMacro */
  89.  
  90.  
  91.  
  92. /****************************************************************************/
  93. /* Add a new macro table entry at the end and return its index */
  94. /****************************************************************************/
  95. short
  96. NewMacro ()
  97. {
  98.     macrodefs *macros;
  99.     long hsize;
  100.     short num;
  101.  
  102.     macros = *macroshdl;
  103.     macros->numOfMacros++;
  104.     num = macros->numOfMacros;
  105.  
  106.     hsize = GetHandleSize ((Handle) macroshdl);
  107.     if ((num * sizeof (macrorec) + MacroBaseSize) > hsize) {
  108.     /* allocate room for 10 more definitions */
  109.     HUnlock ((Handle) macroshdl);
  110.     SetHandleSize ((Handle) macroshdl, hsize + 10 * sizeof (macrorec));
  111.     HLock ((Handle) macroshdl);
  112.     }
  113.     /* init the code field to -1 (empty) */
  114.     macros = *macroshdl;
  115.     macros->mcr[--num].code = -1;
  116.  
  117.     return (num);
  118. }                /* NewMacro */
  119.  
  120.  
  121.  
  122. /****************************************************************************/
  123. /* Enter theCode and theStr into the (empty!) entry at tabIndex. SetMacro  */
  124. /* does    not release a previously existing string. Do this with DeleteMacro */
  125. /* first. */
  126. /****************************************************************************/
  127. SetMacro (theIndex, theCode, theFlags, theStr)
  128. short theIndex;
  129. short theCode;
  130. char *theFlags;
  131. char *theStr;            /* PWP: note: this is now a Pascal string */
  132. {
  133.     macrodefs *macros;
  134.     short slen;
  135.     Ptr sptr;
  136.  
  137.     macros = *macroshdl;
  138.  
  139.     if (macros->mcr[theIndex].code != -1)    /* check for free entry */
  140.     printerr ("snh SetMacro", 0);
  141.  
  142.     macros->mcr[theIndex].code = theCode;
  143.     macros->mcr[theIndex].flags = *theFlags;
  144.     if (*theFlags) {    /* (PWP) save a bit of space: if flags, then no string */
  145.     macros->mcr[theIndex].macro = 0;
  146.     macros->mcr[theIndex].len = 1;
  147.     } else {
  148.     slen = theStr[0] + 1;    /* PWP: was ... = strlen(theStr); */
  149.     if (slen > 4) {
  150.         sptr = NewPtr (slen);
  151.         BlockMove (theStr, sptr, slen);    /* PWP: yes, we save the length too */
  152.         macros->mcr[theIndex].macro = (long) sptr;
  153.     } else {
  154.         BlockMove (theStr, ¯os->mcr[theIndex].macro, slen);
  155.     }
  156.     macros->mcr[theIndex].len = slen;
  157.     }
  158. }                /* SetMacro */
  159.  
  160.  
  161.  
  162. /****************************************************************************/
  163. /* Save theStr as macrostring for the code. Reuse any empty table entires */
  164. /****************************************************************************/
  165. InsertMacro (theCode, theFlags, theStr)
  166. short theCode;
  167. char *theFlags;
  168. char *theStr;            /* PWP: a Pascal string */
  169. {
  170.     short idx;
  171.  
  172.     HLock ((Handle) macroshdl);
  173.  
  174.     if (FindMacro (theCode) >= 0)    /* does the entry exist already */
  175.     printerr ("snh InsertMacro", 0);
  176.  
  177.     idx = FindMacro (-1);    /* look for a free entry */
  178.     if (idx < 0)        /* create a new free entry if none is
  179.                  * available */
  180.     idx = NewMacro ();
  181.     SetMacro (idx, theCode, theFlags, theStr);
  182.  
  183.     HUnlock ((Handle) macroshdl);
  184. }                /* InsertMacro */
  185.  
  186.  
  187.  
  188. /****************************************************************************/
  189. /* Remove the macro definition from the table and mark its entry as empty */
  190. /****************************************************************************/
  191. RemoveMacro (theCode)
  192. short theCode;
  193. {
  194.     short idx;
  195.  
  196.     HLock ((Handle) macroshdl);
  197.  
  198.     idx = FindMacro (theCode);    /* look for the entry */
  199.     if (idx >= 0)
  200.     DeleteMacro (idx);    /* delete it if we found it */
  201.     else
  202.     printerr ("snh RemoveMacro", 0);
  203.  
  204.     HUnlock ((Handle) macroshdl);
  205. }                /* RemoveMacro */
  206.  
  207.  
  208.  
  209. /****************************************************************************/
  210. /* Replace the macro definition in the table */
  211. /****************************************************************************/
  212. ReplaceMacro (theCode, theFlags, theStr)
  213. short theCode;
  214. char *theFlags;
  215. char *theStr;
  216. {
  217.     short idx;
  218.  
  219.     HLock ((Handle) macroshdl);
  220.  
  221.     idx = FindMacro (theCode);    /* look for the entry */
  222.     if (idx >= 0) {
  223.     DeleteMacro (idx);    /* delete it if we found it */
  224.     /* reuse it immediately */
  225.     SetMacro (idx, theCode, theFlags, theStr);
  226.     } else
  227.     printerr ("snh ReplaceMacro", 0);
  228.  
  229.     HUnlock ((Handle) macroshdl);
  230. }                /* ReplaceMacro */
  231.  
  232.  
  233.  
  234. /****************************************************************************/
  235. /* Get the macro string for theCode from the table */
  236. /****************************************************************************/
  237. GetMacro (theCode, theFlags, theStr)
  238. short theCode;
  239. char *theFlags;
  240. char *theStr;
  241. {
  242.     short idx;
  243.     macrodefs *macros;
  244.     short slen;
  245.     Ptr sptr;
  246.  
  247.     HLock ((Handle) macroshdl);
  248.     macros = *macroshdl;
  249.  
  250.     idx = FindMacro (theCode);    /* look for the entry */
  251.     if (idx >= 0) {
  252.     slen = macros->mcr[idx].len;
  253.  
  254.     if (slen > 4)
  255.         sptr = (Ptr) macros->mcr[idx].macro;
  256.     else
  257.         sptr = ¯os->mcr[idx].macro;
  258.  
  259.     BlockMove (sptr, theStr, slen);
  260.     /* *(theStr + slen) = '\0'; */
  261.  
  262.     *theFlags = macros->mcr[idx].flags;
  263.     } else
  264.     printerr ("snh GetMacro", theCode);
  265.  
  266.     HUnlock ((Handle) macroshdl);
  267. }                /* GetMacro */
  268.  
  269.  
  270.  
  271. /****************************************************************************/
  272. /* dipose all macro strings */
  273. /****************************************************************************/
  274. DisposeMacros ()
  275. {
  276.     short i;
  277.     short num;
  278.     macrodefs *macros;
  279.  
  280.     HLock ((Handle) macroshdl);
  281.     macros = *macroshdl;
  282.  
  283.     num = macros->numOfMacros;
  284.     for (i = 0; i < num; i++)
  285.     if (macros->mcr[i].code != -1)
  286.         DeleteMacro (i);
  287.  
  288.     macros->numOfMacros = 0;
  289.     HUnlock ((Handle) macroshdl);
  290. }                /* DisposeMacros */
  291.  
  292.  
  293.  
  294. /****************************************************************************/
  295. /* compress '\' expressions */
  296. /****************************************************************************/
  297. EncodeString (s, flags)
  298. char *s;            /* PWP: takes a C string, returns a Pascal
  299.                  * string. */
  300. char *flags;
  301. {
  302.     register char *t, *b;
  303.     register int v, i;
  304.     char buf[256];
  305.  
  306.     *flags = '\0';        /* no flags set */
  307.  
  308.     if ((strcmp (s, "\\break") == 0) ||
  309.     (strcmp (s, "\\shortbreak") == 0)) {
  310.     *flags = shortBreak;
  311.     return;
  312.     } else
  313.     if (strcmp (s, "\\longbreak") == 0) {
  314.     *flags = longBreak;
  315.     return;
  316.     } else
  317.     if (strcmp (s, "\\leftarrow") == 0) {
  318.     *flags = leftArrowKey;
  319.     return;
  320.     } else
  321.     if (strcmp (s, "\\rightarrow") == 0) {
  322.     *flags = rightArrowKey;
  323.     return;
  324.     } else
  325.     if (strcmp (s, "\\uparrow") == 0) {
  326.     *flags = upArrowKey;
  327.     return;
  328.     } else
  329.     if (strcmp (s, "\\downarrow") == 0) {
  330.     *flags = downArrowKey;
  331.     return;
  332.     } else
  333.     if (strcmp (s, "\\pf1") == 0) {
  334.     *flags = keypf1;
  335.     return;
  336.     } else
  337.     if (strcmp (s, "\\pf2") == 0) {
  338.     *flags = keypf2;
  339.     return;
  340.     } else
  341.     if (strcmp (s, "\\pf3") == 0) {
  342.     *flags = keypf3;
  343.     return;
  344.     } else
  345.     if (strcmp (s, "\\pf4") == 0) {
  346.     *flags = keypf4;
  347.     return;
  348.     } else
  349.     if (strcmp (s, "\\enter") == 0) {
  350.     *flags = keyenter;
  351.     return;
  352.     } else
  353.     if ((strncmp (s, "\\keypad", 7) == 0) && (s[8] == '\0')) {
  354.     if ((s[7] >= ',') && (s[7] <= '9')) {
  355.         *flags = keycomma + (s[7] - ',');
  356.     }
  357.     return;
  358.     }
  359.     *(s + 255) = '\0';
  360.     b = s;
  361.     t = buf;
  362.  
  363.     while (*s != '\0') {
  364.     if (*s != '\\')
  365.         *t = *s++;
  366.     else if isdigit(*++s) {        /* if \digits */
  367.         /* the current char was a backslash */
  368.         for (i = 0, v = 0; i < 3; i++) {
  369.         /* only do the first 3 digits: \0335 -> ^[5 */
  370.         if (!isdigit(*s))
  371.             break;
  372.         v = (8 * v) + (int) *s++ - (int) '0';
  373.         }
  374.         *t = (char) v % 256;
  375.     } else {
  376.         switch (*s) {
  377.           case 'b':    /* backspace */
  378.         *t = '\010';
  379.         break;
  380.  
  381.           case 't':    /* tab */
  382.         *t = '\011';
  383.         break;
  384.  
  385.           case 'n':    /* newline -- linefeed */
  386.         *t = '\012';
  387.         break;
  388.  
  389.           case 'f':    /* formfeed */
  390.         *t = '\014';
  391.         break;
  392.  
  393.           case 'r':    /* return */
  394.         *t = '\015';
  395.         break;
  396.  
  397.           case '^':    /* \^c --> control-C */
  398.         s++;
  399.         if (*s == '?')
  400.             *t = '\177';/* special case */
  401.         else
  402.             *t = (*s & 037);
  403.         break;
  404.  
  405.           default:
  406.         *t = *s;
  407.         }
  408.         s++;
  409.     }
  410.     t++;
  411.     }
  412.     b[0] = (char) (t - buf);    /* PWP: the length */
  413.     BlockMove (buf, &b[1], b[0]);    /* copy the new string in */
  414. }                /* EncodeString */
  415.  
  416.  
  417.  
  418. /****************************************************************************/
  419. /* Decode the pascal string into a C string with '\' notation */
  420. /****************************************************************************/
  421. DecodeString (s, flags)
  422. char *s;            /* takes a Pascal string, returns a C string */
  423. char flags;            /* PWP: note! not a pointer */
  424. {
  425.     register unsigned char ch;
  426.     register char *tp;
  427.     char numStr[4];
  428.     char t[400];        /* PWP: actually, this probably won't
  429.                  * overflow 256, but be safe */
  430.     register int i, j;
  431.  
  432.     switch (flags) {
  433.       case shortBreak:
  434.     strcpy (s, "\\break");
  435.     return;
  436.  
  437.       case longBreak:
  438.     strcpy (s, "\\longbreak");
  439.     return;
  440.  
  441.       case leftArrowKey:
  442.     strcpy (s, "\\leftarrow");
  443.     return;
  444.  
  445.       case rightArrowKey:
  446.     strcpy (s, "\\rightarrow");
  447.     return;
  448.     
  449.       case upArrowKey:
  450.     strcpy (s, "\\uparrow");
  451.     return;
  452.     
  453.       case downArrowKey:
  454.     strcpy (s, "\\downarrow");
  455.     return;
  456.     
  457.       case keypf1:
  458.       case keypf2:
  459.       case keypf3:
  460.       case keypf4:
  461.     strcpy (s, "\\pf");
  462.     s[3] = flags - keypf1 + '1';
  463.     s[4] = '\0';
  464.     return;
  465.     
  466.       case keyenter:
  467.     strcpy (s, "\\enter");
  468.     return;
  469.     
  470.       case keycomma:
  471.       case keyminus:
  472.       case keyperiod:
  473.       /* there is no keyslash */
  474.       case key0:
  475.       case key1:
  476.       case key2:
  477.       case key3:
  478.       case key4:
  479.       case key5:
  480.       case key6:
  481.       case key7:
  482.       case key8:
  483.       case key9:
  484.     strcpy (s, "\\keypad");
  485.     s[7] = flags - keycomma + ',';
  486.     s[8] = '\0';
  487.     return;
  488.     }
  489.  
  490.     tp = t;
  491.     for (i = 1; i <= s[0]; i++) {    /* PWP: step through a Pascal string */
  492.     ch = s[i];
  493.     if ((ch < ' ') || (ch > 126)) {
  494.         *tp++ = '\\';
  495.         j = (long) ch & 0377;    /* mask of sign extension */
  496.         *tp++ = (j / 0100) + '0';    /* 64s digit */
  497.         j &= 077;
  498.         *tp++ = (j / 010) + '0';    /* 8s digit */
  499.         j &= 07;
  500.         *tp++ = j + '0';    /* 1s digit */
  501.     } else if (ch == '\\') {
  502.         *tp++ = '\\';
  503.         *tp++ = '\\';
  504.     } else
  505.         *tp++ = ch;
  506.     }
  507.     *tp = '\0';
  508.     t[255] = '\0';        /* be extra safe */
  509.     strcpy (s, t);        /* copy it into place */
  510. }                /* DecodeString */
  511.  
  512.  
  513.  
  514. #define KeyPressed 2        /* dummy item. returned when a key is pressed */
  515. #define myKeyCodeMask 0x7F00
  516. #define keyModifierMask 0x1F00
  517. short lastCode;
  518.  
  519. /****************************************************************************/
  520. /* return KeyPressed and TRUE if a keyevent happened */
  521. /****************************************************************************/
  522. pascal Boolean
  523. keyfilter (theDialog, theEvent, itemHit)
  524. DialogPtr theDialog;
  525. EventRecord *theEvent;
  526. short *itemHit;
  527. {
  528.     Boolean retVal;
  529.     char modstr[45];
  530.     char theChar[3];
  531.     char codeStr[5];
  532.  
  533.     retVal = (theEvent->what == keyDown);
  534.     if (retVal) {
  535.     *itemHit = KeyPressed;
  536.  
  537.     /* show modifiers pressed */
  538.     *modstr = '\0';
  539.     if (theEvent->modifiers & shiftKey)
  540.         strcat (modstr, " shift");
  541.     if (theEvent->modifiers & alphaLock)
  542.         strcat (modstr, " lock");
  543.     if (theEvent->modifiers & optionKey)
  544.         strcat (modstr, " option");
  545.  
  546. #ifndef controlKey
  547. #define controlKey 4096        /* PWP: hack for beta MPW C */
  548. #endif
  549.  
  550.     if (theEvent->modifiers & controlKey)
  551.         strcat (modstr, " control");
  552.     if (theEvent->modifiers & cmdKey)
  553.         strcat (modstr, " command");
  554.  
  555.     strcpy (theChar, "  ");
  556.     *(theChar + 1) = (theEvent->message & charCodeMask);
  557.     strcat (modstr, theChar);
  558.  
  559.     lastCode = ((theEvent->message & myKeyCodeMask) >> 8) +
  560.         ((theEvent->modifiers & keyModifierMask) >> 1);
  561.     NumToString (lastCode, codeStr);
  562.     strcat (modstr, "  (");
  563.     strcat (modstr, codeStr);
  564.     strcat (modstr, ")");
  565.  
  566.     if (BitTst (keytable, lastCode))
  567.         strcat (modstr, " bound to:");
  568.     else
  569.         strcat (modstr, " [unbound]");
  570.  
  571.     SetIText (gethdl (KY_MODIFIER, theDialog), modstr);
  572.     }
  573.     return (retVal);
  574. }                /* keyfilter */
  575.  
  576.  
  577.  
  578. #define HelpBtn 3
  579.  
  580. /****************************************************************************/
  581. /* runs the set key macros dialog */
  582. /****************************************************************************/
  583. keymacros ()
  584. {
  585.     DialogPtr macrodlg;
  586.     DialogPtr macro2dlg;
  587.     short itemhit;
  588.     int i;
  589.     char keystr[256];
  590.     char flags;
  591.  
  592.     macrodlg = GetNewDialog (KEYBOXID, NILPTR, (WindowPtr) - 1);
  593.  
  594.     for (;;) {
  595.     SetIText (gethdl (KY_MODIFIER, macrodlg), "Press the key to program");
  596.     ModalDialog (keyfilter, &itemhit);
  597.  
  598.     switch (itemhit) {
  599.       case OKBtn:        /* finish up */
  600.         DisposDialog (macrodlg);    /* finished with the dialog */
  601.         return;        /* return */
  602.  
  603.       case KeyPressed:    /* fall in from above */
  604.         macro2dlg = GetNewDialog (KEY2BOXID, NILPTR, (WindowPtr) - 1);
  605.         circleOK(macro2dlg);
  606.  
  607.         /* display the current macrostring if there is one */
  608.         if (BitTst (keytable, lastCode)) {
  609.         GetMacro (lastCode, &flags, keystr);
  610.         DecodeString (keystr, flags);    /* decode invisible
  611.                          * characters */
  612.         SetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  613.         SelIText(macro2dlg, KY_TEXT, 0, 32767);
  614.         }
  615.         itemhit = 0;
  616.         while (itemhit == 0) {
  617.         ModalDialog (NILPROC, &itemhit);
  618.  
  619.         switch (itemhit) {
  620.           case OKBtn:    /* finish up */
  621.             GetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  622.             EncodeString (keystr, flags);    /* encode '\'
  623.                              * expressions */
  624.             if (BitTst (keytable, lastCode))
  625.             if (strlen (keystr) > 0)
  626.                 ReplaceMacro (lastCode, flags, keystr);
  627.             else {
  628.                 RemoveMacro (lastCode);
  629.                 BitClr (keytable, lastCode);
  630.             }
  631.             else if (strlen (keystr) > 0) {
  632.             InsertMacro (lastCode, flags, keystr);
  633.             BitSet (keytable, lastCode);
  634.             }
  635.           case QuitBtn:
  636.             DisposDialog (macro2dlg);    /* finished with the dialog */
  637.             break;
  638.  
  639.           case KY_HELP:
  640.             itemhit = Alert (ALERT_HELP, NILPROC);
  641.  
  642.           default:
  643.             itemhit = 0;
  644.         }
  645.         }
  646.     }
  647.     }
  648. }                /* keymacros */
  649.  
  650.  
  651.  
  652. modrec modtable[NUMOFMODS];
  653.  
  654. /****************************************************************************/
  655. /* handle the modifier dialog */
  656. /****************************************************************************/
  657. keymoddialog ()
  658. {
  659.     DialogPtr moddlg;
  660.     short itemhit;
  661.     modrec tmodtable[NUMOFMODS];/* temporary copy of modtable */
  662.     short i;
  663.     short ignType;
  664.     Handle ignHdl;
  665.     Rect box;
  666.     char theStr[256];
  667.     GrafPtr savePort;
  668.  
  669.     GetPort (&savePort);
  670.  
  671.     moddlg = GetNewDialog (MODBOXID, NILPTR, (WindowPtr) - 1);
  672.     circleOK(moddlg);
  673.     SetPort (moddlg);
  674.  
  675.     for (i = 0; i < NUMOFMODS; i++)
  676.     tmodtable[i] = modtable[i];    /* make a temporary copy */
  677.  
  678.     /* draw the gray lines */
  679.     for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  680.     GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  681.     FillRect (&box, qd.gray);
  682.     }
  683.  
  684.     /* set the texts in the edit fields */
  685.     for (i = 0; i < NUMOFMODS; i++) {
  686.     /* PWP: these are saved as pascal strings now... */
  687.     theStr[0] = 0;        /* be double extra safe */
  688.     BlockMove (tmodtable[i].prefix, theStr, (tmodtable[i].prefix[0] + 1));
  689.     DecodeString (theStr, (char) 0);
  690.     SetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  691.     }
  692.  
  693.     /* set the checkboxes according to the bits set */
  694.     for (i = MOD_CHK1; i <= MOD_CHKL; i++)
  695.     SetCtlValue (getctlhdl (i, moddlg),
  696.              (tmodtable[(i - MOD_CHK1) / 9].modbits &
  697.               (1 << ((i - MOD_CHK1) % 9))) ? btnOn : btnOff);
  698.  
  699.     /* loop till ok or cancel is pressed */
  700.     for (;;) {
  701.     ModalDialog (NILPROC, &itemhit);
  702.     if (itemhit == OKBtn) {
  703.         for (i = 0; i < NUMOFMODS; i++) {
  704.         GetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  705.         EncodeString (theStr);
  706.         if ((unsigned) (theStr[0]) > 19) /* Limit the length of
  707.                           * the thing */
  708.             theStr[0] = 19;
  709.         BlockMove (theStr, tmodtable[i].prefix, 20);
  710.         }
  711.  
  712.         /* write the temporary copy back */
  713.         for (i = 0; i < NUMOFMODS; i++)
  714.         modtable[i] = tmodtable[i];
  715.  
  716.         UpdateOptKey(1);        /* make Option key processing right */
  717.     }
  718.     if ((itemhit == OKBtn) || (itemhit == QuitBtn)) {
  719.         DisposDialog (moddlg);    /* finished with the dialog */
  720.         SetPort (savePort);
  721.         return;
  722.     }
  723.     if (itemhit == MOD_HELP) {
  724.         itemhit = Alert (ALERT_MODHELP, NILPROC);
  725.         /* draw the gray lines again */
  726.         for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  727.         GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  728.         FillRect (&box, qd.gray);
  729.         }
  730.     }
  731.     if (itemhit <= MOD_CHKL) {    /* is it a check box ? */
  732.         tmodtable[(itemhit - MOD_CHK1) / 9].modbits
  733.         ^= (1 << ((itemhit - MOD_CHK1) % 9));
  734.         SetCtlValue (getctlhdl (itemhit, moddlg),
  735.              (tmodtable[(itemhit - MOD_CHK1) / 9].modbits &
  736.               (1 << ((itemhit - MOD_CHK1) % 9))) ? btnOn : btnOff);
  737.     }
  738.     }
  739. }                /* keymoddialog */
  740.  
  741.  
  742.  
  743. /****************************************************************************/
  744. /* load and unpack the key macro tables */
  745. /****************************************************************************/
  746. loadkset ()
  747. {
  748.     Handle ktab;
  749.     char *k;
  750.     int i;
  751.     THz curZone;
  752.  
  753.     /* load the bit table */
  754.     ktab = GetResource (KSET_TYPE, KSVER);
  755.  
  756.     if (ktab == (Handle) NIL)
  757.     printerr ("Could not load the key macros (KSET) [old version?]", 0);
  758.  
  759.     if ((ktab == (Handle) NIL) || (GetHandleSize (ktab) == 0)) {
  760.     /* init the keytable with zeroes if ktab is empty or not available */
  761.     /* ktab is empty in the resource fork of the program itself */
  762.     k = keytable;
  763.     for (i = 1; i <= sizeof (keytable); i++)
  764.         *k++ = '\0';
  765.     return;
  766.     }
  767.     HLock (ktab);
  768.     BlockMove (*ktab, keytable, sizeof (keytable));
  769.     HUnlock (ktab);
  770.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  771.     SetZone(HandleZone(ktab));    /* "Toolbox Gotchas" */
  772.     ReleaseResource(ktab);
  773.     SetZone(curZone);
  774. }                /* loadkset */
  775.  
  776.  
  777.  
  778. /****************************************************************************/
  779. /* load and unpack the key macro table */
  780. /****************************************************************************/
  781. loadmset ()
  782. {
  783.     short i;
  784.     short idx;
  785.     short num;
  786.     short theCode;
  787.     Handle mtab;
  788.     char *src;
  789.     char flags;
  790.     THz curZone;
  791.  
  792.     DisposeMacros ();        /* release all macro strings */
  793.  
  794.     /* load the bit table */
  795.     mtab = GetResource (MSET_TYPE, KMVER);
  796.  
  797.     if (mtab == (Handle) NIL) {
  798.     printerr ("Could not load the key macros (MSET) [old version?]", 0);
  799.     return;
  800.     }
  801.     HLock (mtab);
  802.     HLock ((Handle) macroshdl);
  803.     src = *mtab;
  804.  
  805.     /* load the modifier information */
  806.     BlockMove (src, modtable, sizeof (modtable));
  807.     src += sizeof (modtable);
  808.  
  809.     UpdateOptKey(1);        /* make Option key processing right */
  810.  
  811.     /* get the number of macro key definitions */
  812.     BlockMove (src, &num, sizeof (num));
  813.     src += sizeof (num);
  814.  
  815.     for (i = 0; i < num; i++) {
  816.     /* Get the code */
  817.     BlockMove (src, &theCode, sizeof (theCode));
  818.     src += sizeof (theCode);
  819.  
  820.     /* Get the flags */
  821.     flags = *src++;
  822.  
  823.     /* Get the string */
  824.     /* p2cstr(src);  -- PWP: it allready is a pascal string! */
  825.     idx = NewMacro ();    /* create a new free entry */
  826.     SetMacro (idx, theCode, &flags, src);
  827.     src += src[0] + 1;    /* PWP: was strlen */
  828.     }
  829.  
  830.     HUnlock ((Handle) macroshdl);
  831.     HUnlock (mtab);
  832.     curZone = GetZone();        /* as per John Norstad's (Disinfectant) */
  833.     SetZone(HandleZone(mtab));    /* "Toolbox Gotchas" */
  834.     ReleaseResource(mtab);
  835.     SetZone(curZone);
  836. }                /* loadmset */
  837.  
  838.  
  839.  
  840. /****************************************************************************/
  841. /* save the key macro bit table */
  842. /****************************************************************************/
  843. savekset ()
  844. {
  845.     Handle ktab;
  846.     char *k;
  847.     int i;
  848.  
  849.     ktab = NewHandle (sizeof (keytable));
  850.  
  851.     if (ktab == (Handle) NIL) {
  852.     printerr ("Could not save the key macros (KSET)", 0);
  853.     return;
  854.     }
  855.     HLock (ktab);
  856.     BlockMove (keytable, *ktab, sizeof (keytable));
  857.     HUnlock (ktab);
  858.     AddResource (ktab, KSET_TYPE, KSVER, "");
  859. }                /* savekset */
  860.  
  861.  
  862.  
  863. /****************************************************************************/
  864. savemset ()
  865. /****************************************************************************/
  866. /* pack and save the key macro table */
  867. {
  868.     short i;
  869.     short num;
  870.     short leng;
  871.     short count;
  872.     short theCode;
  873.     int totalLen;
  874.     char *dest;
  875.     Ptr src;
  876.     Handle mtab;
  877.     macrodefs *macros;
  878.  
  879.     HLock ((Handle) macroshdl);
  880.     macros = *macroshdl;
  881.  
  882.     num = macros->numOfMacros;
  883.     totalLen = 0;
  884.     count = 0;
  885.  
  886.     /* calculate the sum of the string lengths of all active table entries */
  887.     for (i = 0; i < num; i++)
  888.     if (macros->mcr[i].code != -1) {
  889.         totalLen += macros->mcr[i].len;
  890.         count++;
  891.     };
  892.  
  893.     /* add the length for keycode and length  */
  894.     /* information and the number of entries  */
  895.     totalLen += count * (sizeof (macrorec) - sizeof (long)) + MacroBaseSize;
  896.     mtab = NewHandle (totalLen);
  897.     if (mtab == (Handle) NIL) {
  898.     printerr ("Could not save the key macros (MSET)", 0);
  899.     return;
  900.     }
  901.     HLock (mtab);
  902.     dest = *mtab;
  903.  
  904.     /* save the modifier information */
  905.     BlockMove (modtable, dest, sizeof (modtable));
  906.     dest += sizeof (modtable);
  907.  
  908.     /* save the number of key macros */
  909.     BlockMove (&num, dest, sizeof (num));
  910.     dest += sizeof (num);
  911.  
  912.     /* save the whole rest of the table */
  913.     for (i = 0; i < num; i++) {
  914.     theCode = macros->mcr[i].code;
  915.     if (theCode != -1) {
  916.         /* save the code number */
  917.         BlockMove (&theCode, dest, sizeof (theCode));
  918.         dest += sizeof (theCode);
  919.  
  920.         /* save the flags */
  921.         leng = macros->mcr[i].len;
  922.         *dest++ = macros->mcr[i].flags;
  923.  
  924.         /* save the string length (1 byte!) */
  925.         /* PWP: nope! it's allready a Pascal string */
  926.         /* *dest++ = macros->mcr[i].len; */
  927.  
  928.         /* save the macro string */
  929.         if (leng > 4)
  930.         src = (Ptr) macros->mcr[i].macro;   /* the address is stored here */
  931.         else
  932.         src = ¯os->mcr[i].macro;
  933.         BlockMove (src, dest, leng);
  934.         dest += leng;
  935.     }
  936.     }
  937.  
  938.     HUnlock (mtab);
  939.     HUnlock ((Handle) macroshdl);
  940.  
  941.     AddResource (mtab, MSET_TYPE, KMVER, "");
  942. }                /* savemset */
  943.