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

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