home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / old / ckermit4e / ckmkey.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  22KB  |  832 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 <ctype.h>
  30.  
  31. #include "ckmdef.h"        /* Common Mac module definitions */
  32. #include "ckmres.h"        /* resource defs */
  33.  
  34.  
  35. /* KSET This structure tells for which key / modifier combinations */
  36. /* there is a special macro declaration. */
  37. /* MSET This structure holds all macrokey definitons in a packed */
  38. /* form. To be useful it has to be unpacked into a macrodefs     */
  39. /* structure. */
  40.  
  41. hmacrodefs macroshdl;
  42.  
  43. char keytable[512];
  44.  
  45.  
  46.  
  47. /****************************************************************************/
  48. /* Look for a macrodefinition for theCode and return its table index if */
  49. /* found or -1 if not found */
  50. /****************************************************************************/
  51. short
  52. FindMacro (theCode)
  53. short theCode;
  54. {
  55.     short i;
  56.     short num;
  57.     macrodefs *macros;
  58.  
  59.     macros = *macroshdl;
  60.  
  61.     num = macros->numOfMacros;
  62.     for (i = 0; (i < num) && (macros->mcr[i].code != theCode); i++);
  63.  
  64.     if (i >= num)
  65.     return (-1);
  66.     else
  67.     return (i);
  68. }                /* FindMacro */
  69.  
  70.  
  71.  
  72. /****************************************************************************/
  73. /* Set theCode at theIndex to -1 which means this entry is empty. Release */
  74. /* the memory block occupied to save the macrostring if necessary */
  75. /****************************************************************************/
  76. DeleteMacro (theIndex)
  77. short theIndex;
  78. {
  79.     macrodefs *macros;
  80.  
  81.     macros = *macroshdl;
  82.  
  83.     macros->mcr[theIndex].code = -1;
  84.     if (macros->mcr[theIndex].len > 4)    /* release memory block if there is
  85.                      * one */
  86.     DisposPtr ((Ptr) macros->mcr[theIndex].macro);
  87. }                /* DeleteMacro */
  88.  
  89.  
  90.  
  91. /****************************************************************************/
  92. /* Add a new macro table entry at the end and return its index */
  93. /****************************************************************************/
  94. short
  95. NewMacro ()
  96. {
  97.     macrodefs *macros;
  98.     long hsize;
  99.     short num;
  100.  
  101.     macros = *macroshdl;
  102.     macros->numOfMacros++;
  103.     num = macros->numOfMacros;
  104.  
  105.     hsize = GetHandleSize ((Handle) macroshdl);
  106.     if ((num * sizeof (macrorec) + MacroBaseSize) > hsize) {
  107.     /* allocate room for 10 more definitions */
  108.     HUnlock ((Handle) macroshdl);
  109.     SetHandleSize ((Handle) macroshdl, hsize + 10 * sizeof (macrorec));
  110.     HLock ((Handle) macroshdl);
  111.     }
  112.     /* init the code field to -1 (empty) */
  113.     macros = *macroshdl;
  114.     macros->mcr[--num].code = -1;
  115.  
  116.     return (num);
  117. }                /* NewMacro */
  118.  
  119.  
  120.  
  121. /****************************************************************************/
  122. /* Enter theCode and theStr into the (empty!) entry at tabIndex. SetMacro  */
  123. /* does    not release a previously existing string. Do this with DeleteMacro */
  124. /* first. */
  125. /****************************************************************************/
  126. SetMacro (theIndex, theCode, theFlags, theStr)
  127. short theIndex;
  128. short theCode;
  129. char *theFlags;
  130. char *theStr;            /* PWP: note: this is now a Pascal string */
  131. {
  132.     macrodefs *macros;
  133.     short slen;
  134.     Ptr sptr;
  135.  
  136.     macros = *macroshdl;
  137.  
  138.     if (macros->mcr[theIndex].code != -1)    /* check for free entry */
  139.     printerr ("snh SetMacro", 0);
  140.  
  141.     macros->mcr[theIndex].code = theCode;
  142.     slen = theStr[0] + 1;    /* PWP: was ... = strlen(theStr); */
  143.     if (slen > 4) {
  144.     sptr = NewPtr (slen);
  145.     BlockMove (theStr, sptr, slen);    /* PWP: yes, we save the length too */
  146.     macros->mcr[theIndex].macro = (long) sptr;
  147.     } else
  148.     BlockMove (theStr, ¯os->mcr[theIndex].macro, slen);
  149.  
  150.     macros->mcr[theIndex].len = slen;
  151.     macros->mcr[theIndex].flags = *theFlags;
  152. }                /* SetMacro */
  153.  
  154.  
  155.  
  156. /****************************************************************************/
  157. /* Save theStr as macrostring for the code. Reuse any empty table entires */
  158. /****************************************************************************/
  159. InsertMacro (theCode, theFlags, theStr)
  160. short theCode;
  161. char *theFlags;
  162. char *theStr;            /* PWP: a Pascal string */
  163. {
  164.     short idx;
  165.  
  166.     HLock ((Handle) macroshdl);
  167.  
  168.     if (FindMacro (theCode) >= 0)    /* does the entry exist already */
  169.     printerr ("snh InsertMacro", 0);
  170.  
  171.     idx = FindMacro (-1);    /* look for a free entry */
  172.     if (idx < 0)        /* create a new free entry if none is
  173.                  * available */
  174.     idx = NewMacro ();
  175.     SetMacro (idx, theCode, theFlags, theStr);
  176.  
  177.     HUnlock ((Handle) macroshdl);
  178. }                /* InsertMacro */
  179.  
  180.  
  181.  
  182. /****************************************************************************/
  183. /* Remove the macro definition from the table and mark its entry as empty */
  184. /****************************************************************************/
  185. RemoveMacro (theCode)
  186. short theCode;
  187. {
  188.     short idx;
  189.  
  190.     HLock ((Handle) macroshdl);
  191.  
  192.     idx = FindMacro (theCode);    /* look for the entry */
  193.     if (idx >= 0)
  194.     DeleteMacro (idx);    /* delete it if we found it */
  195.     else
  196.     printerr ("snh RemoveMacro", 0);
  197.  
  198.     HUnlock ((Handle) macroshdl);
  199. }                /* RemoveMacro */
  200.  
  201.  
  202.  
  203. /****************************************************************************/
  204. /* Replace the macro definition in the table */
  205. /****************************************************************************/
  206. ReplaceMacro (theCode, theFlags, theStr)
  207. short theCode;
  208. char *theFlags;
  209. char *theStr;
  210. {
  211.     short idx;
  212.  
  213.     HLock ((Handle) macroshdl);
  214.  
  215.     idx = FindMacro (theCode);    /* look for the entry */
  216.     if (idx >= 0) {
  217.     DeleteMacro (idx);    /* delete it if we found it */
  218.     /* reuse it immediately */
  219.     SetMacro (idx, theCode, theFlags, theStr);
  220.     } else
  221.     printerr ("snh ReplaceMacro", 0);
  222.  
  223.     HUnlock ((Handle) macroshdl);
  224. }                /* ReplaceMacro */
  225.  
  226.  
  227.  
  228. /****************************************************************************/
  229. /* Get the macro string for theCode from the table */
  230. /****************************************************************************/
  231. GetMacro (theCode, theFlags, theStr)
  232. short theCode;
  233. char *theFlags;
  234. char *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 = ¯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 (s, flags)
  292. char *s;            /* PWP: takes a C string, returns a Pascal
  293.                  * string. */
  294. char *flags;
  295. {
  296.     register char *t, *b;
  297.     register int v, i;
  298.     char buf[256];
  299.  
  300.     *flags = '\0';        /* no flags set */
  301.  
  302.     if ((strcmp (s, "\\break") == 0) ||
  303.     (strcmp (s, "\\shortbreak") == 0)) {
  304.     *flags |= shortBreak;
  305.     return;
  306.     }
  307.     if (strcmp (s, "\\longbreak") == 0) {
  308.     *flags |= longBreak;
  309.     return;
  310.     }
  311.     *(s + 255) = '\0';
  312.     b = s;
  313.     t = buf;
  314.  
  315.     while (*s != '\0') {
  316.     if (*s != '\\')
  317.         *t = *s++;
  318.     else if isdigit(*++s) {        /* if \digits */
  319.         /* the current char was a backslash */
  320.         for (i = 0, v = 0; i < 3; i++) {
  321.         /* only do the first 3 digits: \0335 -> ^[5 */
  322.         if (!isdigit(*s))
  323.             break;
  324.         v = (8 * v) + (int) *s++ - (int) '0';
  325.         }
  326.         *t = (char) v % 256;
  327.     } else {
  328.         switch (*s) {
  329.           case 'b':    /* backspace */
  330.         *t = '\010';
  331.         break;
  332.  
  333.           case 't':    /* tab */
  334.         *t = '\011';
  335.         break;
  336.  
  337.           case 'n':    /* newline -- linefeed */
  338.         *t = '\012';
  339.         break;
  340.  
  341.           case 'f':    /* formfeed */
  342.         *t = '\014';
  343.         break;
  344.  
  345.           case 'r':    /* return */
  346.         *t = '\015';
  347.         break;
  348.  
  349.           case '^':    /* \^c --> control-C */
  350.         s++;
  351.         if (*s == '?')
  352.             *t = '\177';/* special case */
  353.         else
  354.             *t = (*s & 037);
  355.         break;
  356.  
  357.           default:
  358.         *t = *s;
  359.         }
  360.         s++;
  361.     }
  362.     t++;
  363.     }
  364.     b[0] = (char) (t - buf);    /* PWP: the length */
  365.     BlockMove (buf, &b[1], b[0]);    /* copy the new string in */
  366. }                /* EncodeString */
  367.  
  368.  
  369.  
  370. /****************************************************************************/
  371. /* Decode the pascal string into a C string with '\' notation */
  372. /****************************************************************************/
  373. DecodeString (s, flags)
  374. char *s;            /* takes a Pascal string, returns a C string */
  375. char flags;            /* PWP: note! not a pointer */
  376. {
  377.     register unsigned char ch;
  378.     register char *tp;
  379.     char numStr[4];
  380.     char t[400];        /* PWP: actually, this probably won't
  381.                  * overflow 256, but be safe */
  382.     register int i, j;
  383.  
  384.     if (flags & shortBreak) {
  385.     strcpy (s, "\\break");
  386.     return;
  387.     }
  388.     if (flags & longBreak) {
  389.     strcpy (s, "\\longbreak");
  390.     return;
  391.     }
  392.     tp = t;
  393.     for (i = 1; i <= s[0]; i++) {    /* PWP: step through a Pascal string */
  394.     ch = s[i];
  395.     if ((ch < ' ') || (ch > 126)) {
  396.         *tp++ = '\\';
  397.         j = (long) ch & 0377;    /* mask of sign extension */
  398.         *tp++ = (j / 0100) + '0';    /* 64s digit */
  399.         j &= 077;
  400.         *tp++ = (j / 010) + '0';    /* 8s digit */
  401.         j &= 07;
  402.         *tp++ = j + '0';    /* 1s digit */
  403.     } else if (ch == '\\') {
  404.         *tp++ = '\\';
  405.         *tp++ = '\\';
  406.     } else
  407.         *tp++ = ch;
  408.     }
  409.     *tp = '\0';
  410.     t[255] = '\0';        /* be extra safe */
  411.     strcpy (s, t);        /* copy it into place */
  412. }                /* DecodeString */
  413.  
  414.  
  415.  
  416. #define KeyPressed 2        /* dummy item. returned when a key is pressed */
  417. #define myKeyCodeMask 0x7F00
  418. #define keyModifierMask 0x1F00
  419. short lastCode;
  420.  
  421. /****************************************************************************/
  422. /* return KeyPressed and TRUE if a keyevent happened */
  423. /****************************************************************************/
  424. pascal Boolean
  425. keyfilter (theDialog, theEvent, itemHit)
  426. DialogPtr theDialog;
  427. EventRecord *theEvent;
  428. short *itemHit;
  429. {
  430.     Boolean retVal;
  431.     char modstr[45];
  432.     char theChar[3];
  433.     char codeStr[5];
  434.  
  435.     retVal = (theEvent->what == keyDown);
  436.     if (retVal) {
  437.     *itemHit = KeyPressed;
  438.  
  439.     /* show modifiers pressed */
  440.     *modstr = '\0';
  441.     if (theEvent->modifiers & shiftKey)
  442.         strcat (modstr, " shift");
  443.     if (theEvent->modifiers & alphaLock)
  444.         strcat (modstr, " lock");
  445.     if (theEvent->modifiers & optionKey)
  446.         strcat (modstr, " option");
  447.  
  448. #ifndef controlKey
  449. #define controlKey 4096        /* PWP: hack for beta MPW C */
  450. #endif
  451.  
  452.     if (theEvent->modifiers & controlKey)
  453.         strcat (modstr, " control");
  454.     if (theEvent->modifiers & cmdKey)
  455.         strcat (modstr, " command");
  456.  
  457.     strcpy (theChar, "  ");
  458.     *(theChar + 1) = (theEvent->message & charCodeMask);
  459.     strcat (modstr, theChar);
  460.  
  461.     lastCode = ((theEvent->message & myKeyCodeMask) >> 8) +
  462.         ((theEvent->modifiers & keyModifierMask) >> 1);
  463.     NumToString (lastCode, codeStr);
  464.     strcat (modstr, "  (");
  465.     strcat (modstr, codeStr);
  466.     strcat (modstr, ")");
  467.  
  468.     if (BitTst (&keytable, lastCode))
  469.         strcat (modstr, " bound to:");
  470.     else
  471.         strcat (modstr, " [unbound]");
  472.  
  473.     SetIText (gethdl (KY_MODIFIER, theDialog), modstr);
  474.     }
  475.     return (retVal);
  476. }                /* keyfilter */
  477.  
  478.  
  479.  
  480. #define HelpBtn 3
  481.  
  482. /****************************************************************************/
  483. /* runs the set key macros dialog */
  484. /****************************************************************************/
  485. keymacros ()
  486. {
  487.     DialogPtr macrodlg;
  488.     DialogPtr macro2dlg;
  489.     short itemhit;
  490.     int i;
  491.     char keystr[256];
  492.     char flags;
  493.  
  494.     macrodlg = GetNewDialog (KEYBOXID, NILPTR, (WindowPtr) - 1);
  495.  
  496.     for (;;) {
  497.     SetIText (gethdl (KY_MODIFIER, macrodlg), "Press the key to program");
  498.     ModalDialog (keyfilter, &itemhit);
  499.  
  500.     switch (itemhit) {
  501.       case OKBtn:        /* finish up */
  502.         DisposDialog (macrodlg);    /* finished with the dialog */
  503.         return;        /* return */
  504.  
  505.       case KeyPressed:    /* fall in from above */
  506.         macro2dlg = GetNewDialog (KEY2BOXID, NILPTR, (WindowPtr) - 1);
  507.         circleOK(macro2dlg);
  508.  
  509.         /* display the current macrostring if there is one */
  510.         if (BitTst (&keytable, lastCode)) {
  511.         GetMacro (lastCode, &flags, keystr);
  512.         DecodeString (keystr, flags);    /* decode invisible
  513.                          * characters */
  514.         SetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  515.         }
  516.         itemhit = 0;
  517.         while (itemhit == 0) {
  518.         ModalDialog (NILPROC, &itemhit);
  519.  
  520.         switch (itemhit) {
  521.           case OKBtn:    /* finish up */
  522.             GetIText (gethdl (KY_TEXT, macro2dlg), keystr);
  523.             EncodeString (keystr, flags);    /* encode '\'
  524.                              * expressions */
  525.             if (BitTst (&keytable, lastCode))
  526.             if (strlen (keystr) > 0)
  527.                 ReplaceMacro (lastCode, flags, keystr);
  528.             else {
  529.                 RemoveMacro (lastCode);
  530.                 BitClr (&keytable, lastCode);
  531.             }
  532.             else if (strlen (keystr) > 0) {
  533.             InsertMacro (lastCode, flags, keystr);
  534.             BitSet (&keytable, lastCode);
  535.             }
  536.           case QuitBtn:
  537.             DisposDialog (macro2dlg);    /* finished with the dialog */
  538.             break;
  539.  
  540.           case KY_HELP:
  541.             itemhit = Alert (ALERT_HELP, NILPROC);
  542.  
  543.           default:
  544.             itemhit = 0;
  545.         }
  546.         }
  547.     }
  548.     }
  549. }                /* keymacros */
  550.  
  551.  
  552.  
  553. modrec modtable[NUMOFMODS];
  554.  
  555. /****************************************************************************/
  556. /* handle the modifier dialog */
  557. /****************************************************************************/
  558. keymoddialog ()
  559. {
  560.     DialogPtr moddlg;
  561.     short itemhit;
  562.     modrec tmodtable[NUMOFMODS];/* temporary copy of modtable */
  563.     short i;
  564.     short ignType;
  565.     Handle ignHdl;
  566.     Rect box;
  567.     char theStr[256];
  568.     GrafPtr savePort;
  569.  
  570.     GetPort (&savePort);
  571.  
  572.     moddlg = GetNewDialog (MODBOXID, NILPTR, (WindowPtr) - 1);
  573.     circleOK(moddlg);
  574.     SetPort (moddlg);
  575.  
  576.     for (i = 0; i < NUMOFMODS; i++)
  577.     tmodtable[i] = modtable[i];    /* make a temporary copy */
  578.  
  579.     /* draw the gray lines */
  580.     for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  581.     GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  582.     FillRect (&box, qd.gray);
  583.     }
  584.  
  585.     /* set the texts in the edit fields */
  586.     for (i = 0; i < NUMOFMODS; i++) {
  587.     /* PWP: these are saved as pascal strings now... */
  588.     theStr[0] = 0;        /* be double extra safe */
  589.     BlockMove (&tmodtable[i].prefix, theStr, (tmodtable[i].prefix[0] + 1));
  590.     DecodeString (theStr, (char) 0);
  591.     SetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  592.     }
  593.  
  594.     /* set the checkboxes according to the bits set */
  595.     for (i = MOD_CHK1; i <= MOD_CHKL; i++)
  596.     SetCtlValue (getctlhdl (i, moddlg),
  597.              (tmodtable[(i - MOD_CHK1) / 9].modbits &
  598.               (1 << ((i - MOD_CHK1) % 9))) ? btnOn : btnOff);
  599.  
  600.     /* loop till ok or cancel is pressed */
  601.     for (;;) {
  602.     ModalDialog (NILPROC, &itemhit);
  603.     if (itemhit == OKBtn) {
  604.         for (i = 0; i < NUMOFMODS; i++) {
  605.         GetIText (gethdl (i + MOD_PRF1, moddlg), theStr);
  606.         EncodeString (theStr);
  607.         if ((unsigned) (theStr[0]) > 19) /* Limit the length of
  608.                           * the thing */
  609.             theStr[0] = 19;
  610.         BlockMove (theStr, &tmodtable[i].prefix, 20);
  611.         }
  612.  
  613.         /* write the temporary copy back */
  614.         for (i = 0; i < NUMOFMODS; i++)
  615.         modtable[i] = tmodtable[i];
  616.     }
  617.     if ((itemhit == OKBtn) || (itemhit == QuitBtn)) {
  618.         DisposDialog (moddlg);    /* finished with the dialog */
  619.         SetPort (savePort);
  620.         return;
  621.     }
  622.     if (itemhit == MOD_HELP) {
  623.         itemhit = Alert (ALERT_MODHELP, NILPROC);
  624.         /* draw the gray lines again */
  625.         for (i = MOD_LIN1; i <= MOD_LINL; i++) {
  626.         GetDItem (moddlg, i, &ignType, &ignHdl, &box);
  627.         FillRect (&box, qd.gray);
  628.         }
  629.     }
  630.     if (itemhit <= MOD_CHKL) {    /* is it a check box ? */
  631.         tmodtable[(itemhit - MOD_CHK1) / 9].modbits
  632.         ^= (1 << ((itemhit - MOD_CHK1) % 9));
  633.         SetCtlValue (getctlhdl (itemhit, moddlg),
  634.              (tmodtable[(itemhit - MOD_CHK1) / 9].modbits &
  635.               (1 << ((itemhit - MOD_CHK1) % 9))) ? btnOn : btnOff);
  636.     }
  637.     }
  638. }                /* keymoddialog */
  639.  
  640.  
  641.  
  642. /****************************************************************************/
  643. /* load and unpack the key macro tables */
  644. /****************************************************************************/
  645. loadkset ()
  646. {
  647.     Handle ktab;
  648.     char *k;
  649.     int i;
  650.  
  651.     /* load the bit table */
  652.     ktab = GetResource (KSET_TYPE, KSVER);
  653.  
  654.     if (ktab == (Handle) NIL)
  655.     printerr ("Could not load the key macros (KSET) [old version?]", 0);
  656.  
  657.     if ((ktab == (Handle) NIL) || (GetHandleSize (ktab) == 0)) {
  658.     /* init the keytable with zeroes if ktab is empty or not available */
  659.     /* ktab is empty in the resource fork of the program itself */
  660.     k = keytable;
  661.     for (i = 1; i <= sizeof (keytable); i++)
  662.         *k++ = '\0';
  663.     return;
  664.     }
  665.     HLock (ktab);
  666.     BlockMove (*ktab, &keytable, sizeof (keytable));
  667.     HUnlock (ktab);
  668.     ReleaseResource (ktab);
  669. }                /* loadkset */
  670.  
  671.  
  672.  
  673. /****************************************************************************/
  674. /* load and unpack the key macro table */
  675. /****************************************************************************/
  676. loadmset ()
  677. {
  678.     short i;
  679.     short idx;
  680.     short num;
  681.     short theCode;
  682.     Handle mtab;
  683.     char *src;
  684.     char flags;
  685.  
  686.     DisposeMacros ();        /* release all macro strings */
  687.  
  688.     /* load the bit table */
  689.     mtab = GetResource (MSET_TYPE, KMVER);
  690.  
  691.     if (mtab == (Handle) NIL) {
  692.     printerr ("Could not load the key macros (MSET) [old version?]", 0);
  693.     return;
  694.     }
  695.     HLock (mtab);
  696.     HLock ((Handle) macroshdl);
  697.     src = *mtab;
  698.  
  699.     /* load the modifier information */
  700.     BlockMove (src, &modtable, sizeof (modtable));
  701.     src += sizeof (modtable);
  702.  
  703.     /* get the number of macro key definitions */
  704.     BlockMove (src, &num, sizeof (num));
  705.     src += sizeof (num);
  706.  
  707.     for (i = 0; i < num; i++) {
  708.     /* Get the code */
  709.     BlockMove (src, &theCode, sizeof (theCode));
  710.     src += sizeof (theCode);
  711.  
  712.     /* Get the flags */
  713.     flags = *src++;
  714.  
  715.     /* Get the string */
  716.     /* p2cstr(src);  -- PWP: it allready is a pascal string! */
  717.     idx = NewMacro ();    /* create a new free entry */
  718.     SetMacro (idx, theCode, &flags, src);
  719.     src += src[0] + 1;    /* PWP: was strlen */
  720.     }
  721.  
  722.     HUnlock ((Handle) macroshdl);
  723.     HUnlock (mtab);
  724.     ReleaseResource (mtab);
  725. }                /* loadmset */
  726.  
  727.  
  728.  
  729. /****************************************************************************/
  730. /* save the key macro bit table */
  731. /****************************************************************************/
  732. savekset ()
  733. {
  734.     Handle ktab;
  735.     char *k;
  736.     int i;
  737.  
  738.     ktab = NewHandle (sizeof (keytable));
  739.  
  740.     if (ktab == (Handle) NIL) {
  741.     printerr ("Could not save the key macros (KSET)", 0);
  742.     return;
  743.     }
  744.     HLock (ktab);
  745.     BlockMove (&keytable, *ktab, sizeof (keytable));
  746.     HUnlock (ktab);
  747.     AddResource (ktab, KSET_TYPE, KSVER, "");
  748. }                /* savekset */
  749.  
  750.  
  751.  
  752. /****************************************************************************/
  753. savemset ()
  754. /****************************************************************************/
  755. /* pack and save the key macro table */
  756. {
  757.     short i;
  758.     short num;
  759.     short leng;
  760.     short count;
  761.     short theCode;
  762.     int totalLen;
  763.     char *dest;
  764.     Ptr src;
  765.     Handle mtab;
  766.     macrodefs *macros;
  767.  
  768.     HLock ((Handle) macroshdl);
  769.     macros = *macroshdl;
  770.  
  771.     num = macros->numOfMacros;
  772.     totalLen = 0;
  773.     count = 0;
  774.  
  775.     /* calculate the sum of the string lengths of all active table entries */
  776.     for (i = 0; i < num; i++)
  777.     if (macros->mcr[i].code != -1) {
  778.         totalLen += macros->mcr[i].len;
  779.         count++;
  780.     };
  781.  
  782.     /* add the length for keycode and length  */
  783.     /* information and the number of entries  */
  784.     totalLen += count * (sizeof (macrorec) - sizeof (long)) + MacroBaseSize;
  785.     mtab = NewHandle (totalLen);
  786.     if (mtab == (Handle) NIL) {
  787.     printerr ("Could not save the key macros (MSET)", 0);
  788.     return;
  789.     }
  790.     HLock (mtab);
  791.     dest = *mtab;
  792.  
  793.     /* save the modifier information */
  794.     BlockMove (&modtable, dest, sizeof (modtable));
  795.     dest += sizeof (modtable);
  796.  
  797.     /* save the number of key macros */
  798.     BlockMove (&num, dest, sizeof (num));
  799.     dest += sizeof (num);
  800.  
  801.     /* save the whole rest of the table */
  802.     for (i = 0; i < num; i++) {
  803.     theCode = macros->mcr[i].code;
  804.     if (theCode != -1) {
  805.         /* save the code number */
  806.         BlockMove (&theCode, dest, sizeof (theCode));
  807.         dest += sizeof (theCode);
  808.  
  809.         /* save the flags */
  810.         leng = macros->mcr[i].len;
  811.         *dest++ = macros->mcr[i].flags;
  812.  
  813.         /* save the string length (1 byte!) */
  814.         /* PWP: nope! it's allready a Pascal string */
  815.         /* *dest++ = macros->mcr[i].len; */
  816.  
  817.         /* save the macro string */
  818.         if (leng > 4)
  819.         src = macros->mcr[i].macro;
  820.         else
  821.         src = ¯os->mcr[i].macro;
  822.         BlockMove (src, dest, leng);
  823.         dest += leng;
  824.     }
  825.     }
  826.  
  827.     HUnlock (mtab);
  828.     HUnlock ((Handle) macroshdl);
  829.  
  830.     AddResource (mtab, MSET_TYPE, KMVER, "");
  831. }                /* savemset */
  832.