home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / MacPerl 5.1.3 / Mac_Perl_513_src / MacPerl5 / MPHelp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-11  |  9.6 KB  |  449 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPHelp.c            -    Various helpful functions
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C
  6.  
  7. $Log: MPHelp.c,v $
  8. Revision 1.1  1994/02/27  23:01:10  neeri
  9. Initial revision
  10.  
  11. Revision 0.2  1993/09/08  00:00:00  neeri
  12. Corrected some misunderstandings of dbm
  13.  
  14. Revision 0.1  1993/08/17  00:00:00  neeri
  15. Use Application directory
  16.  
  17. *********************************************************************/
  18.  
  19. #include "MPHelp.h"
  20. #include "MPConsole.h"
  21. #include "MPUtils.h"
  22. #include "MPEditor.h"
  23.  
  24. #include <Menus.h>
  25. #include <Balloons.h>
  26. #include <ToolUtils.h>
  27. #include <TFileSpec.h>
  28. #include <ndbm.h>
  29. #include <ctype.h>
  30. #include <PLStringFuncs.h>
  31. #include <Folders.h>
  32. #include <fcntl.h>
  33. #include <ioctl.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36.  
  37. static void MetaHelp(StringPtr msg, StringPtr m1, StringPtr m2, StringPtr m3) 
  38. {
  39.     SetCursor(&qd.arrow);
  40.     ParamText(msg, m1, m2, m3);
  41.      Alert(ErrorAlert, nil);
  42. }
  43.  
  44. static MenuHandle    gHelpMenus[20];
  45. static Handle        gHelpURLs[20];
  46. static DBM *         gHelpIndex = nil;
  47. static Boolean        gHasHelp    =    true;
  48.  
  49. void InitHelpIndex()
  50. {
  51.     int            depth       =     0;
  52.     int            curIndex    =    0;
  53.     int            nextIndex=     0;
  54.     MenuHandle    curMenu;
  55.     char *        menu;
  56.     char *        scan;
  57.     char *         next;
  58.     datum         key;
  59.     datum         data;
  60.     Str255        contrib;
  61.     int            menuStack[10];
  62.  
  63.     AppendMenu(myMenus[helpM], "\p-(");
  64.  
  65.     if (!gHelpIndex)
  66.         goto whyNoHelp;
  67.         
  68.     key.dptr     = " MENU";
  69.     key.dsize    = 5;
  70.     data             = dbm_fetch(gHelpIndex, key);
  71.     
  72.     if (!data.dptr)
  73.         goto whyNoHelp;
  74.     
  75.     curMenu                 =    gHelpMenus[curIndex = nextIndex++] = myMenus[helpM];
  76.     menuStack[depth]     =     curIndex;
  77.     PtrToHand("\n\n\n\n\n\n\n\n\n\n", &gHelpURLs[curIndex], CountMItems(curMenu));
  78.     for (menu = data.dptr; depth>=0; menu = next+1) {
  79.         next = strchr(menu, '\n');
  80.         if (menu == next) 
  81.             if (!depth--)
  82.                 break;
  83.             else    {
  84.                 curIndex =     menuStack[depth];
  85.                 curMenu    =    gHelpMenus[curIndex];
  86.                 continue;
  87.             }
  88.         scan             =     strchr(menu, '\t');
  89.         contrib[0]    =    scan - menu;
  90.         memcpy(contrib+1, menu, contrib[0]);
  91.         AppendMenu(curMenu, contrib);
  92.         PtrAndHand(scan+1, gHelpURLs[curIndex], next - scan);
  93.         if (*++scan == '!') {
  94.             curIndex =  nextIndex++;
  95.             gHelpMenus[curIndex] = NewMenu(kHierHelpMenu+curIndex, "\p");
  96.             SetItemCmd(curMenu, CountMItems(curMenu), 0x1B);
  97.             SetItemMark(curMenu, CountMItems(curMenu), kHierHelpMenu+curIndex);
  98.             curMenu = gHelpMenus[curIndex];
  99.             InsertMenu(curMenu, -1);
  100.             gHelpURLs[curIndex]    =    NewHandle(0);
  101.             menuStack[++depth]     =     curIndex;
  102.         }
  103.     }
  104.     return;
  105. whyNoHelp:
  106.     gHasHelp = false;
  107.     AppendMenu(myMenus[helpM], "\pEnabling online Help...");    
  108. }
  109.  
  110. void InitHelp()
  111. {
  112.     CInfoPBRec    info;
  113.     FSSpec BalloonPath;
  114.     
  115.     if (gHelpIndex || !gHasHelp)
  116.         return;
  117.         
  118.     BalloonPath.vRefNum     = gAppVol;
  119.     BalloonPath.parID        = gAppDir;
  120.     PLstrcpy(BalloonPath.name, (StringPtr) "\pMacPerl Help");
  121.  
  122.     if (!FSpCatInfo(&BalloonPath, &info)) 
  123.         if (gHelpIndex = dbm_open(FSp2FullPath(&BalloonPath), DBM_RDONLY, 0))
  124.             return;
  125.             
  126.     if (!FindFolder(
  127.             kOnSystemDisk, 
  128.             kPreferencesFolderType, 
  129.             false, 
  130.             &BalloonPath.vRefNum,
  131.             &BalloonPath.parID)
  132.         && !FSpCatInfo(&BalloonPath, &info) 
  133.     )     
  134.         gHelpIndex = dbm_open(FSp2FullPath(&BalloonPath), DBM_RDONLY, 0);
  135. }
  136.  
  137. void EndHelp()
  138. {
  139.     if (gHelpIndex) {
  140.         dbm_close(gHelpIndex);
  141.         
  142.         gHelpIndex = nil;
  143.     }
  144. }
  145.  
  146. void Explain(DPtr doc)
  147. {
  148.     TEHandle        te;
  149.     datum         key;
  150.     datum         data;
  151.     char *        text;
  152.     short            pos;
  153.     short            start;
  154.     short            restore = -1;
  155.     
  156.     InitHelp();
  157.     
  158.     if (!gHelpIndex) {
  159.         MetaHelp(
  160.             "\pTo enable online help, put the file \"MacPerl Help\" "
  161.             "in the same folder as the MacPerl application and "
  162.             "restart MacPerl.", (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  163.         return;
  164.     }
  165.  
  166.     if (doc) {
  167.         te = doc->theText;
  168.             
  169.         pos = (*te)->selEnd - (*te)->selStart;
  170.         HLock((*te)->hText);
  171.         text = *(*te)->hText;
  172.         start= (*te)->selStart;
  173.         if (pos) {
  174.             /* Trim spaces */
  175.             while (pos && isspace(text[start]))
  176.                 ++start, --pos;
  177.             while (pos && isspace(text[start+pos-1]))
  178.                 --pos;
  179.             if (text[start] == '$') 
  180.                 switch (text[start+pos]) {
  181.                 case '[':
  182.                     text[restore=start] = '@';
  183.                     break;
  184.                 case '{':
  185.                     text[restore=start] = '%';
  186.                     break;
  187.                 }
  188.         } else {
  189.             /* Intuit topic */
  190.             if (start && !isspace(text[start-1]) && !strchr("()[]{}", text[start-1]))
  191.                 --start;
  192.             pos = start;
  193.             if (isalpha(text[start]) || text[start] == '_' || text[start] == ':') {
  194.                 /* Identifier, scan to start && end */
  195.                 do {
  196.                     --start;
  197.                 } while (start && (isalpha(text[start]) || text[start] == '_' || text[start] == ':'));
  198.                 do {
  199.                     ++pos;
  200.                 } while (pos<te[0]->teLength && (isalpha(text[pos]) || text[pos] == '_' || text[pos] == ':'));
  201.                 switch (text[start]) {
  202.                 case '$':
  203.                     if (pos < te[0]->teLength)
  204.                         switch (text[pos]) {
  205.                         case '[':
  206.                             text[restore=start] = '@';
  207.                             break;
  208.                         case '{':
  209.                             text[restore=start] = '%';
  210.                             break;
  211.                         }
  212.                     /* Fall through */
  213.                 case '%':
  214.                 case '@':
  215.                     /* variable */
  216.                     break;
  217.                 case '^':
  218.                     if (start && text[start-1] == '$') {
  219.                         --start;
  220.                         break;
  221.                     }
  222.                     /* Fall through */
  223.                 default:
  224.                     /* procedure */
  225.                     ++start;
  226.                 }
  227.             } else {
  228.                 if (start)
  229.                     switch (text[start-1]) {
  230.                     case '$':
  231.                     case '@':
  232.                     case '%':
  233.                         --start;
  234.                         goto symbolic_variable;
  235.                     }
  236.                 switch (text[start]) {
  237.                 case '%':
  238.                     if (!isalnum(text[start+1]))
  239.                         break; /* Operator, not variable reference */
  240.                     /* Fall through */
  241.                 case '$':
  242.                 case '@':
  243. symbolic_variable:
  244.                     if (text[start+1] == '^')
  245.                         pos = start+3;
  246.                     else
  247.                         pos = start+2;
  248.                     break;
  249.                 default:
  250.                     pos = start+1;
  251.                     while (start) {
  252.                         switch (text[start-1]) {
  253.                         case '+':
  254.                         case '-':
  255.                         case '>':
  256.                         case '<':
  257.                         case '&':
  258.                         case '|':
  259.                         case '=':
  260.                         case '*':
  261.                         case '^':
  262.                             --start;
  263.                             continue;
  264.                         }
  265.                         break;
  266.                     }
  267.                     while (pos < te[0]->teLength) {
  268.                         switch (text[pos]) {
  269.                         case '+':
  270.                         case '-':
  271.                         case '>':
  272.                         case '<':
  273.                         case '&':
  274.                         case '|':
  275.                         case '=':
  276.                         case '*':
  277.                         case '^':
  278.                             ++pos;
  279.                             continue;
  280.                         }
  281.                         break;
  282.                     }
  283.                 }
  284.             }
  285.             pos -= start;
  286.         }
  287.         if (!pos)
  288.             HUnlock((*te)->hText);
  289.     } else 
  290.         pos = 0;
  291.         
  292.     if (!pos) {
  293.         MetaHelp("\pYou didn't select any text to look up.",
  294.                     (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  295.  
  296.         EndHelp();
  297.         
  298.         return;
  299.     }
  300.     
  301.     key.dptr = text+start;
  302.     key.dsize = pos;
  303.     data = dbm_fetch(gHelpIndex, key);
  304.     if (restore > -1)
  305.         text[restore] = '$';
  306.     HUnlock((*te)->hText);
  307.     EndHelp();
  308.     
  309.     if (!data.dptr) {
  310.         Str255    keyStr;
  311.         
  312.         keyStr[0] = key.dsize;
  313.         memcpy(keyStr+1, key.dptr, key.dsize);
  314.         
  315.         MetaHelp("\pUnfortunately, I can't give you any help for \"",
  316.                     keyStr, (StringPtr) "\p\"", (StringPtr) "\p");
  317.     } else {
  318.         TESetSelect(start, start+pos, te);
  319.         LaunchHelpURL(data.dptr, data.dsize);
  320.     }
  321. }    
  322.  
  323. void LaunchHelpURL(char * urlPtr, int urlLen)
  324. {
  325.     int        len;
  326.     char        urlBuf[300];
  327.     char *    url = urlBuf+8;
  328.     char *    end;
  329.  
  330.     strcpy(urlBuf+1, "Helper•");
  331.     if (*urlPtr == '!')
  332.         return;     /* False positive */
  333.     if ((!strncmp(urlPtr, "file:", 5) && urlPtr[5] != '/')
  334.      || (!strncmp(urlPtr, "pod:", 4) && urlPtr[4] != '/')    
  335.     ) {
  336.         char *     path;
  337.         char *    urlPath;
  338.         FSSpec     here;
  339.         
  340.         here.vRefNum     = gAppVol;
  341.         here.parID        = gAppDir;
  342.         
  343.         FSpUp(&here);
  344.         *strchr(urlPtr, ':') = 0;
  345.         strcpy(url, urlPtr);
  346.         strcat(url, ":///");
  347.         urlLen -= strlen(urlPtr)+1;
  348.         urlPtr += strlen(urlPtr)+1;
  349.         urlPtr[-1] = ':';
  350.         urlPath    = url+strlen(url);
  351.         for (path = FSp2FullPath(&here); *path; path++)
  352.             switch (*path) {
  353.             case ':':    /* Translate directory separators */
  354.                 *urlPath++ = '/';
  355.                 break;
  356.             case '<':    /* Encode dangerous characters */
  357.             case '>':    
  358.             case '+':
  359.             case '\"':
  360.             case '*':
  361.             case '%':
  362.             case '&':
  363.             case '/':
  364.             case '(':
  365.             case ')':
  366.             case '=':
  367.             case '?':
  368.             case '\'':
  369.             case '`':
  370.             case '^':
  371.             case '$':
  372.             case '#':
  373.             case ' ':
  374.                 sprintf(urlPath, "%%%02X", *path);
  375.                 urlPath += 3;
  376.                 break;
  377.             default:
  378.                 *urlPath++ = *path;
  379.                 break;
  380.             }
  381.         if (urlPath[-1] != '/')
  382.             *urlPath++ = '/';
  383.         memcpy(urlPath, urlPtr, urlLen);
  384.         len = urlPath - url + urlLen;
  385.     } else {
  386.         memcpy(url, urlPtr, urlLen);
  387.         len = urlLen;
  388.     }
  389.     
  390.     if (end = (char *) memchr(url, ':', len)) {
  391.         urlBuf[0] = end-urlBuf-1;
  392.         FindHelper((StringPtr) urlBuf, nil, true);
  393.     }
  394.         
  395.     if (gICInstance) {
  396.         long         selStart     = 0;
  397.         long         selEnd     = len;
  398.         
  399.         if (!ICLaunchURL(gICInstance, "\p", url, len, &selStart, &selEnd)) 
  400.             return;
  401.         else {
  402.             ICAttr    attr;
  403.             long        size            =    0;
  404.  
  405.             if (end) {
  406.             
  407.                 if(ICGetPref(gICInstance, (StringPtr) urlBuf, &attr, nil, &size) == icPrefNotFoundErr) {
  408.                     SetCursor(&qd.arrow);
  409.                     url[-1] = urlBuf[0]-7;
  410.                     ParamText((StringPtr)(url-1), (StringPtr)"\p", (StringPtr)"\p", (StringPtr)"\p");
  411.                      if (Alert(HelperAlert, nil) == 1) {
  412.                         url[-1] = '•';
  413.                         ICEditPreferences(gICInstance, (StringPtr) urlBuf);
  414.                     }
  415.                     return;
  416.                 }
  417.             }
  418.         }
  419.     }
  420.     MetaHelp("\pFailed to launch help viewer. "
  421.                 "Please make sure that you have Internet Config 1.2b3 or later "
  422.                 "installed set up a valid WWW viewer as the helper for both "
  423.                 "“http” and the “file”.",
  424.                 (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  425. }
  426.  
  427. void DoHelp(short menu, short item) 
  428. {
  429.     if (gHasHelp) {
  430.         Handle    urls = gHelpURLs[menu];
  431.         char *    url;
  432.         char *    urlEnd;
  433.     
  434.         if (!urls)        /* False alarm from MenuChoice */
  435.             return;
  436.  
  437.         HLock(urls);
  438.         for (url = *urls; --item && url; url = strchr(url, '\n')+1);
  439.         if (url && (urlEnd = strchr(url, '\n')))
  440.             LaunchHelpURL(url, urlEnd - url);
  441.         HUnlock(urls);
  442.     } else
  443.         MetaHelp(
  444.             "\pTo enable online help, put the file \"MacPerl Help\" "
  445.             "in the same folder as the MacPerl application and "
  446.             "restart MacPerl.", (StringPtr) "\p", (StringPtr) "\p", (StringPtr) "\p");
  447. }
  448.  
  449.