home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkhelp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  25.9 KB  |  1,023 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /***************************************************
  19.  *
  20.  * Routines to parse HTML help mapping file
  21.  */
  22.  
  23. #include "mkutils.h"
  24. #include "xp.h"
  25. #include "mkparse.h"
  26. #include "mkhelp.h"
  27. #include "xp_help.h"
  28. #include "xpgetstr.h"
  29. #include "libmocha.h"        /* For the onHelp handler */
  30. #include "prefapi.h"        /* For the onHelp handler */
  31. #include "fe_proto.h"
  32.  
  33. extern char * INTL_ResourceCharSet(void);
  34.  
  35. extern int MK_OUT_OF_MEMORY;
  36. extern int MK_CANT_LOAD_HELP_TOPIC;
  37.  
  38. #define DEFAULT_HELP_ID               "*"
  39. #define DEFAULT_HELP_PROJECT       "/help.hpf"      /* Note the inclusion of the initial slash */
  40. #define DEFAULT_HELP_WINDOW_NAME   "_HelpWindow"
  41. #define DEFAULT_HELP_WINDOW_HEIGHT 500
  42. #define DEFAULT_HELP_WINDOW_WIDTH  400
  43.  
  44. #define PREF_NSCP_HELP_URL           "http://help.netscape.com/nethelp/"    /* This must include the trailing slash */
  45. #define PREF_DEFAULT_HELP_LOC_ID   "general.help_source.site"    /* FIXME: Shouldn't this be defined somewhere else? */
  46. #define PREF_DEFAULT_HELP_URL_ID   "general.help_source.url"    /* FIXME: Shouldn't this be defined somewhere else? */
  47.  
  48. /* Tokens within the .hpf file to parse for */
  49.  
  50. #define ID_MAP_TOKEN "ID_MAP"
  51. #define END_ID_MAP_TOKEN "/ID_MAP"
  52. #define FRAME_GROUP_TOKEN "FRAME_GROUP"
  53. #define SRC_TOKEN "SRC"
  54. #define WINDOW_TOKEN "DEFAULT_WINDOW"
  55. #define END_FRAME_GROUP_TOKEN "/FRAME_GROUP"
  56. #define WINDOW_SIZE_TOKEN "WINDOW-SIZE"
  57. #define WINDOW_NAME_TOKEN "WINDOW-NAME"
  58. #define HELP_VERSION_TOKEN "NETHELP-VERSION"
  59. #define TARGET_TOKEN "TARGET"
  60.  
  61.  
  62. /* @@@ Global hack.  See below */
  63. PRIVATE URL_Struct * frame_content_for_pre_exit_routine=NULL;
  64.  
  65. typedef struct _HTMLHelpParseObj {
  66.     XP_Bool  in_id_mapping;
  67.     int32     window_width;
  68.     int32     window_height;
  69.     int         helpVersion;
  70.     char    *window_name;
  71.     char    *id_value;
  72.     char    *default_id_value;
  73.     char    *url_to_map_file;
  74.     char    *id;
  75.     char    *line_buffer;
  76.     int32    line_buffer_size;
  77.     char    *content_target;
  78.     XP_List *frame_group_stack;
  79. } HTMLHelpParseObj;
  80.  
  81. typedef struct {
  82.     char *address;
  83.     char *target;
  84. } frame_set_struct;
  85.  
  86.  
  87. PRIVATE void
  88. simple_exit(URL_Struct *URL_s, int status, MWContext *window_id)
  89. {
  90.     if(status != MK_CHANGING_CONTEXT)
  91.         NET_FreeURLStruct(URL_s);
  92. }
  93.  
  94.  
  95. PUBLIC void
  96. XP_NetHelp(MWContext *pContext, const char *topic)
  97. {
  98.     MWContext    *pActiveContext = NULL;
  99.     char        *pHelpURLString = NULL;
  100.  
  101.     /* Prepend the vendor name "netscape/" to all of our own topics */
  102.  
  103.     if (topic == NULL) {
  104.         pHelpURLString = XP_STRDUP("netscape/home");
  105.     } else {
  106.         pHelpURLString = (char *) XP_ALLOC(strlen(topic) + strlen("netscape/")+1);
  107.         if (!pHelpURLString) {
  108.             return;
  109.         }
  110.         XP_STRCPY(pHelpURLString, "netscape/");
  111.         XP_STRCPY(&(pHelpURLString[9]), topic);
  112.     }
  113.  
  114.     /* Now get the right context to load it from */
  115.  
  116.     if (pContext != NULL) {
  117.         pActiveContext = pContext;
  118.     } else {
  119.         pActiveContext = FE_GetNetHelpContext();
  120.     }
  121.  
  122.     NET_LoadNetHelpTopic(pActiveContext, pHelpURLString);    
  123.  
  124.     XP_FREEIF(pHelpURLString);
  125. }
  126.  
  127.  
  128. PUBLIC void
  129. NET_LoadNetHelpTopic(MWContext *pContext, const char *topic)
  130. {
  131.     char        *pNetHelpURLString;
  132.     URL_Struct    *pHelpURL;
  133.  
  134.     if (topic == NULL) {
  135.         return;
  136.     }
  137.     
  138.     /* Convert the fully-specified topic into a nethelp URL: */
  139.     
  140.     pNetHelpURLString = (char *) XP_ALLOC(strlen(topic) + strlen(NETHELP_URL_PREFIX)+1);
  141.     if (!pNetHelpURLString) {
  142.         return;
  143.     }
  144.     
  145.     XP_STRCPY(pNetHelpURLString, NETHELP_URL_PREFIX);
  146.     XP_STRCPY(&(pNetHelpURLString[strlen(NETHELP_URL_PREFIX)]), topic);
  147.     
  148.     pHelpURL = NET_CreateURLStruct(pNetHelpURLString, NET_NORMAL_RELOAD);
  149.  
  150.     if (!pHelpURL) {
  151.         return;
  152.     }
  153.  
  154.     NET_GetURL(pHelpURL, FO_PRESENT, pContext, simple_exit);
  155.  
  156.     XP_FREEIF(pNetHelpURLString);
  157.         
  158. }
  159.     
  160. PRIVATE void
  161. net_help_free_frame_group_struct(frame_set_struct *obj)
  162. {
  163.     XP_ASSERT(obj);
  164.     if(!obj)
  165.         return;
  166.     FREEIF(obj->address);
  167.     FREEIF(obj->target);
  168.     FREE(obj);
  169. }
  170.  
  171. /* load the HTML help mapping file and search for
  172.  * the id or text to load a specific document
  173.  */
  174. PUBLIC void
  175. NET_GetHTMLHelpFileFromMapFile(MWContext *context,
  176.                                char *map_file_url,
  177.                                char *id,
  178.                                char *search_text)
  179. {
  180.     URL_Struct *URL_s;
  181.  
  182.     XP_ASSERT(map_file_url && id);
  183.  
  184.     if(!map_file_url || !id)
  185.         return;
  186.  
  187.     URL_s = NET_CreateURLStruct(map_file_url, NET_DONT_RELOAD);
  188.  
  189.     if(!URL_s)
  190.         return;
  191.  
  192.     URL_s->fe_data = XP_STRDUP(id);
  193.  
  194.     NET_GetURL(URL_s, FO_CACHE_AND_LOAD_HTML_HELP_MAP_FILE, context, simple_exit);
  195. }
  196.  
  197. PRIVATE void
  198. net_get_default_help_URL(char **pHelpBase)
  199. {
  200.     int        success;
  201.     int32    helpType;
  202.     
  203.     if ((success = PREF_GetIntPref(PREF_DEFAULT_HELP_LOC_ID, &helpType))
  204.         == PREF_NOERROR) {
  205.  
  206.         switch (helpType) {
  207.  
  208.             case 0:        /* Netscape's help site: */
  209.                 StrAllocCopy(*pHelpBase, PREF_NSCP_HELP_URL);
  210.                 break;
  211.             case 1:        /* Internal installed location. */
  212.                 *pHelpBase = FE_GetNetHelpDir();
  213.                 break;
  214.             case 2:
  215.                 success = PREF_CopyCharPref(PREF_DEFAULT_HELP_URL_ID, pHelpBase);
  216.                 break;
  217.             default:
  218.                 success = PREF_ERROR;
  219.         }
  220.         /* ...any of the above might accidentally _not_ end with a '/'*/
  221.         if ((*pHelpBase) && ((*pHelpBase)[XP_STRLEN(*pHelpBase)-1]) != '/') {
  222.             StrAllocCat(*pHelpBase, "/");
  223.         }
  224.     }
  225.  
  226.     /* Fall back on the Netscape help site */
  227.  
  228.     if (success != PREF_NOERROR) {
  229.         StrAllocCopy(*pHelpBase, PREF_NSCP_HELP_URL);
  230.     }
  231.  
  232.     return;
  233. }
  234.  
  235. /* EA: NETHELP Begin */
  236.  /* Takes a nethelp: URL of the form
  237.      nethelp:vendor/component:topic[@location/[projectfile.hpf]]
  238.      
  239.      and separates into the mapping file, with which it replaces URL_s->address,
  240.      and a topic, which it places into URL_s->fe_data.
  241.      
  242.      If a fully specified location (one which includes a projectfile) is given,
  243.      the mapping file is set to that.  If the given location ends in a slash,
  244.      then it is taken to be a directory, and the vendor and component are
  245.      appended as directories before the default projectfile name, helpidx.hpf.
  246.      If no location is given, the default help location is prepended to the
  247.      vendor and component and "helpidx.hpf".
  248.      
  249.      Examples:
  250.      
  251.      nethelp:netscape/navigator:url@http://help.netscape.com/navigator/navhelp.hpf
  252.        - mapping file: http://help.netscape.com/navigator/navhelp.hpf
  253.      
  254.      nethelp:netscape/navigator:url@http://help.netscape.com/
  255.        - mapping file: http://help.netscape.com/netscape/navigator/help.hpf
  256.      
  257.      nethelp:netscape/navigator:url@http://help.netscape.com
  258.        - mapping file: http://help.netscape.com (this will result in an error)
  259.  
  260.       nethelp:netscape/navigator:url
  261.         - assuming the default help location were: C:\navigator\help
  262.         - mapping file: file:///C|/navigator/help/netscape/navigator/helpidx.hpf
  263.        
  264.       In all cases, the topic would be "url"
  265.       
  266.  */
  267.  
  268.  
  269. PUBLIC int
  270. NET_ParseNetHelpURL(URL_Struct *URL_s)
  271. {
  272.     /* this is a nethelp: URL
  273.      * first, see if it's local or remote by checking for the @ 
  274.      */
  275.     char *remote_addr_ptr = 0;
  276.     char *remote_addr=0;
  277.     char *topic_ptr = 0;
  278.     char *topic = 0;
  279.     char *scheme_specific = 0;
  280.     char *pCharacter;
  281.  
  282.     XP_Bool appendProjFile = FALSE;
  283.     
  284.     remote_addr_ptr = XP_STRCHR(URL_s->address, '@');
  285.     
  286.     if (!remote_addr_ptr) {
  287.         char *default_URL = 0;
  288.  
  289.         /* it's local, so we need to get the default, then append the project file */
  290.         net_get_default_help_URL(&default_URL);
  291.         
  292.         if (default_URL) {
  293.             StrAllocCopy(remote_addr, default_URL);
  294.             XP_FREE(default_URL);
  295.         }
  296.         
  297.         appendProjFile = TRUE;
  298.         
  299.     } else {
  300.         *remote_addr_ptr = '\0';
  301.         
  302.         StrAllocCopy(remote_addr, remote_addr_ptr+1);
  303.  
  304.         if (remote_addr && (remote_addr[XP_STRLEN(remote_addr)] == '/')) {
  305.         /* Check to see if the remote_addr ends in a slash.  If so, we
  306.            have some appending to do */
  307.  
  308.             appendProjFile = TRUE;
  309.         }
  310.     }
  311.  
  312.     if (!remote_addr) {
  313.         /* We've obviously run into some kind of a memory problem here. */
  314.         /* Time to bail */
  315.         return MK_OUT_OF_MEMORY;
  316.     }
  317.  
  318.     /* By now, the URL_s->address has been stripped of any location information */
  319.     /* First, remove the scheme, which is guaranteed to be there. */
  320.     
  321.     scheme_specific = XP_STRCHR(URL_s->address, ':') + 1;
  322.     
  323.     topic_ptr = XP_STRCHR(scheme_specific, ':');
  324.     
  325.     if (!topic_ptr) {
  326.         /* This is an error case, but we'll handle it anyway by defaulting to
  327.            the generic topic */
  328.            
  329.         StrAllocCopy(topic, DEFAULT_HELP_ID);
  330.     } else {
  331.         *topic_ptr = '\0';
  332.         StrAllocCopy(topic, topic_ptr+1);
  333.  
  334.     }        
  335.     
  336.     if (appendProjFile) {
  337.         /* Now the URL_s->address will contain only the vendor/component information */
  338.         
  339.         /* In an act of incredible lameness, we want to lowercase the
  340.            vendor/component, since we say that these will default to 
  341.            lower case in the spec.
  342.            
  343.            FIXME!: Note that this may not be correct for double-byte encoded
  344.            characters, but the Intl team was unable to come up with a good
  345.            solution here; in general, we probably won't have any issue, since
  346.            URLs themselves should be in an ASCII-encoding (?).
  347.         */
  348.  
  349.         pCharacter = scheme_specific;
  350.  
  351.         while (*pCharacter)
  352.         {
  353.             *pCharacter = (char) XP_TO_LOWER((unsigned int) *pCharacter);
  354.             pCharacter++;
  355.         }
  356.  
  357.         
  358.         StrAllocCat(remote_addr, scheme_specific);
  359.         StrAllocCat(remote_addr, DEFAULT_HELP_PROJECT);
  360.     }
  361.     
  362.     FREE(URL_s->address);
  363.     URL_s->address = remote_addr;
  364.     
  365.     /* If there is no topic, then we'll still attempt to load the project file and
  366.        its window.  The other code below should detect the non-existence of a topic and
  367.        either revert to a default or do some other elegant solution. */
  368.        
  369.     if (topic) {
  370.         NET_UnEscape(topic);
  371.         URL_s->fe_data = XP_STRDUP(topic);
  372.     } else {
  373.         URL_s->fe_data = NULL;
  374.     }
  375.     
  376.     FREEIF(topic);
  377.     
  378.     return MK_DATA_LOADED;
  379. }
  380.  
  381.  
  382. /* EA: NETHELP End */
  383.  
  384.  
  385. PRIVATE HTMLHelpParseObj *
  386. net_ParseHTMLHelpInit(char *url_to_map_file, char *id)
  387. {
  388.     HTMLHelpParseObj *rv = XP_NEW(HTMLHelpParseObj);
  389.  
  390.     if(!rv)
  391.         return(NULL);
  392.  
  393.     XP_ASSERT(url_to_map_file && id);
  394.  
  395.     if(!url_to_map_file || !id)
  396.         return(NULL);
  397.  
  398.     XP_MEMSET(rv, 0, sizeof(HTMLHelpParseObj));
  399.  
  400.     rv->url_to_map_file = XP_STRDUP(url_to_map_file);
  401.     rv->id              = XP_STRDUP(id);
  402.     rv->helpVersion     = 1;
  403.  
  404.     rv->window_height = DEFAULT_HELP_WINDOW_HEIGHT;
  405.     rv->window_width  = DEFAULT_HELP_WINDOW_WIDTH;
  406.  
  407.     rv->frame_group_stack = XP_ListNew();
  408.  
  409.     return(rv);
  410. }
  411.  
  412. PRIVATE void
  413. net_ParseHTMLHelpFree(HTMLHelpParseObj * obj)
  414. {
  415.     XP_ASSERT(obj);
  416.  
  417.     if(!obj)
  418.         return;
  419.  
  420.     FREEIF(obj->window_name);
  421.     FREEIF(obj->id_value);
  422.     FREEIF(obj->default_id_value);
  423.     FREEIF(obj->url_to_map_file);
  424.     FREEIF(obj->line_buffer);
  425.     FREEIF(obj->id);
  426.  
  427.     if(obj->frame_group_stack)
  428.       {
  429.         frame_set_struct * frame_group_ptr;
  430.  
  431.         while((frame_group_ptr = XP_ListRemoveTopObject(obj->frame_group_stack)) != NULL)
  432.             net_help_free_frame_group_struct(frame_group_ptr);
  433.  
  434.         FREE(obj->frame_group_stack);
  435.       }
  436.  
  437.     FREE(obj);
  438. }
  439.  
  440. /* parse a line that looks like 
  441.  * [whitespace]=[whitespace]"token" other stuff...
  442.  *
  443.  * return token or NULL.
  444.  */
  445. PRIVATE char *
  446. net_get_html_help_token(char *line_data, char**next_word)
  447. {
  448.     char * line = line_data;
  449.     char * cp;
  450.  
  451.     if(next_word)
  452.         *next_word = NULL;
  453.     
  454.     while(XP_IS_SPACE(*line)) line++;
  455.     
  456.     if(*line != '=')
  457.         return(NULL);
  458.  
  459.     line++; /* go past '=' */
  460.  
  461.     while(XP_IS_SPACE(*line)) line++;
  462.  
  463.     if(*line != '"')
  464.         return(NULL);
  465.  
  466.     line++; /* go past '"' */
  467.  
  468.     for(cp=line; *cp; cp++)
  469.           if(*cp == '"' && *(cp-1) != '\\')
  470.           {
  471.             *cp = '\0';
  472.             if(next_word)
  473.               {
  474.                 *next_word = cp+1;
  475.                 while(XP_IS_SPACE(*(*next_word))) (*next_word)++;
  476.               }
  477.             break;
  478.           }
  479.  
  480.     return(line);
  481. }
  482.  
  483. /* parse lines in an HTML help mapping file.
  484.  * get window_size and name, etc...
  485.  *
  486.  * when the id is found function returns HTML_HELP_ID_FOUND
  487.  * on error function returns negative error code.
  488.  */
  489. PRIVATE int
  490. net_ParseHTMLHelpLine(HTMLHelpParseObj *obj, char *line_data)
  491. {
  492.     char *line = XP_StripLine(line_data);
  493.     char *token;
  494.     char *next_word;
  495.  
  496.     if(*line == '<')
  497.       {
  498.         /* find and terminate the end '>' */
  499.         XP_STRTOK(line, ">");
  500.  
  501.         token = XP_StripLine(line+1);
  502.  
  503.         if(!strncasecomp(token, 
  504.                          ID_MAP_TOKEN, 
  505.                          sizeof(ID_MAP_TOKEN)-1))
  506.           {
  507.             obj->in_id_mapping = TRUE;
  508.           }
  509.         else if(!strncasecomp(token, 
  510.                          END_ID_MAP_TOKEN, 
  511.                          sizeof(END_ID_MAP_TOKEN)-1))
  512.           {
  513.             obj->in_id_mapping = FALSE;
  514.           }
  515.         else if(!strncasecomp(token, 
  516.                          FRAME_GROUP_TOKEN, 
  517.                          sizeof(FRAME_GROUP_TOKEN)-1))
  518.           {
  519.             char *cp = token + sizeof(FRAME_GROUP_TOKEN)-1;
  520.             frame_set_struct * fgs = XP_NEW(frame_set_struct);
  521.  
  522.             while(isspace(*cp)) cp++;
  523.  
  524.             if(fgs)
  525.               {
  526.                 XP_MEMSET(fgs, 0, sizeof(frame_set_struct));
  527.  
  528.                 next_word=NULL; /* init */
  529.  
  530.                 do {
  531.                     if(!strncasecomp(cp, SRC_TOKEN, sizeof(SRC_TOKEN)-1))
  532.                         {
  533.                         char *address = net_get_html_help_token(
  534.                                                         cp+sizeof(SRC_TOKEN)-1,
  535.                                                         &next_word);
  536.                         cp = next_word;
  537.                         fgs->address = XP_STRDUP(address);
  538.                         }
  539.                     else if(!strncasecomp(cp, 
  540.                                       WINDOW_TOKEN, 
  541.                                       sizeof(WINDOW_TOKEN)-1))
  542.                       {
  543.                         char *window = net_get_html_help_token(
  544.                                                     cp+sizeof(WINDOW_TOKEN)-1, 
  545.                                                     &next_word);
  546.                         cp = next_word;
  547.                         fgs->target = XP_STRDUP(window);
  548.                       }
  549.                     else
  550.                       {
  551.                         /* unknown attribute.  Skip to next whitespace
  552.                          */ 
  553.                         while(*cp && !isspace(*cp)) 
  554.                             cp++;
  555.  
  556.  
  557.                         if(*cp)
  558.                           {
  559.                             while(isspace(*cp)) cp++;
  560.                             next_word = cp;
  561.                           }
  562.                         else
  563.                           {
  564.                             next_word = NULL;
  565.                           }
  566.                       }
  567.  
  568.                   } while(next_word);
  569.             
  570.                 XP_ListAddObject(obj->frame_group_stack, fgs);
  571.               }
  572.           }
  573.         else if(!strncasecomp(token, 
  574.                          END_FRAME_GROUP_TOKEN, 
  575.                          sizeof(END_FRAME_GROUP_TOKEN)-1))
  576.           {
  577.             frame_set_struct *fgs;
  578.  
  579.             fgs = XP_ListRemoveTopObject(obj->frame_group_stack);
  580.  
  581.             if(fgs)
  582.                 net_help_free_frame_group_struct(fgs);
  583.           }
  584.       }
  585.     else if(!obj->in_id_mapping)
  586.       {
  587.         if(!strncasecomp(line, 
  588.                          WINDOW_SIZE_TOKEN, 
  589.                          sizeof(WINDOW_SIZE_TOKEN)-1))
  590.           {
  591.             /* get window size */
  592.             char *comma=0;
  593.             char *window_size = net_get_html_help_token(line+
  594.                                                 sizeof(WINDOW_SIZE_TOKEN)-1, 
  595.                                                 NULL);
  596.  
  597.             if(window_size)
  598.                 comma = XP_STRCHR(window_size, ',');
  599.  
  600.             if(comma)
  601.               {
  602.                 *comma =  '\0';
  603.                 obj->window_width = XP_ATOI(window_size);
  604.                 obj->window_height = XP_ATOI(comma+1);
  605.               }
  606.           }
  607.         else if(!strncasecomp(line, 
  608.                              WINDOW_NAME_TOKEN, 
  609.                              sizeof(WINDOW_NAME_TOKEN)-1))
  610.           {
  611.             char *window_name = net_get_html_help_token(line+
  612.                                                 sizeof(WINDOW_NAME_TOKEN)-1,
  613.                                                 NULL);
  614.  
  615.             if(window_name)
  616.               {
  617.                 FREEIF(obj->window_name);
  618.                 obj->window_name = XP_STRDUP(window_name);
  619.               }
  620.           }
  621.         else if(!strncasecomp(line, 
  622.                          HELP_VERSION_TOKEN, 
  623.                          sizeof(HELP_VERSION_TOKEN)-1))
  624.           {
  625.             /* get window size */
  626.             char *help_version = net_get_html_help_token(line+
  627.                                                 sizeof(HELP_VERSION_TOKEN)-1, 
  628.                                                 NULL);
  629.  
  630.             if(help_version)
  631.               {
  632.                 obj->helpVersion = XP_ATOI(help_version);
  633.               }
  634.           }
  635.       }
  636.     else
  637.       {
  638.         /* id mapping pair */
  639.         if(!strncasecomp(line, obj->id, XP_STRLEN(obj->id)))
  640.           {
  641.             char *id_value = net_get_html_help_token(line+XP_STRLEN(obj->id),
  642.                                                      &next_word);
  643.  
  644.             if(id_value)
  645.               {
  646.                   obj->id_value = XP_STRDUP(id_value);
  647.  
  648.                 while(next_word)
  649.                   {
  650.                     char *cp = next_word;
  651.  
  652.                     if(!strncasecomp(cp,
  653.                                      TARGET_TOKEN,
  654.                                       sizeof(TARGET_TOKEN)-1))
  655.                       {
  656.                         char *target = net_get_html_help_token(
  657.                                                     cp+sizeof(TARGET_TOKEN)-1,
  658.                                                     &next_word);
  659.                         cp = next_word;
  660.                         obj->content_target = XP_STRDUP(target);
  661.                       }
  662.                     else
  663.                       {
  664.                         /* unknown attribute.  Skip to next whitespace
  665.                          */
  666.                         while(*cp && !isspace(*cp))
  667.                             cp++;
  668.  
  669.                         if(*cp)
  670.                           {
  671.                             while(isspace(*cp)) cp++;
  672.                             next_word = cp;
  673.                           }
  674.                         else
  675.                           {
  676.                             next_word = NULL;
  677.                           }
  678.                       }
  679.                   }
  680.               }
  681.         
  682.             return(HTML_HELP_ID_FOUND);
  683.           }
  684.         if(!strncasecomp(line, DEFAULT_HELP_ID, sizeof(DEFAULT_HELP_ID)-1))
  685.           {
  686.             char *default_id_value = net_get_html_help_token(
  687.                                                 line+sizeof(DEFAULT_HELP_ID)-1,
  688.                                                 NULL);
  689.  
  690.             if(default_id_value)
  691.                 obj->default_id_value = XP_STRDUP(default_id_value);
  692.           }
  693.         
  694.       }
  695.  
  696.     return(0);
  697. }
  698.  
  699. PRIVATE
  700. int
  701. NET_ParseHTMLHelpPut(HTMLHelpParseObj *obj, char *str, int32 len)
  702. {
  703.     int32 string_len;
  704.     char *new_line;
  705.     int32 status;
  706.     
  707.     if(!obj)
  708.         return(MK_OUT_OF_MEMORY);
  709.  
  710.     /* buffer until we have a line */
  711.     BlockAllocCat(obj->line_buffer, obj->line_buffer_size, str, len);
  712.     obj->line_buffer_size += len;
  713.  
  714.     /* see if we have a line */
  715.     while((new_line = strchr_in_buf(obj->line_buffer,
  716.                                     obj->line_buffer_size,
  717.                                     LF)) != NULL
  718.           || ((new_line = strchr_in_buf(obj->line_buffer,
  719.                                     obj->line_buffer_size,
  720.                                     CR)) != NULL) )
  721.       {
  722.         /* terminate the line */
  723.         *new_line = '\0';
  724.  
  725.         status = net_ParseHTMLHelpLine(obj, obj->line_buffer);
  726.  
  727.         /* remove the parsed line from obj->line_buffer */
  728.         string_len = (new_line - obj->line_buffer) + 1;
  729.         XP_MEMCPY(obj->line_buffer,
  730.                   new_line+1,
  731.                   obj->line_buffer_size-string_len);
  732.         obj->line_buffer_size -= string_len;
  733.  
  734.         if(status == HTML_HELP_ID_FOUND)
  735.             return(HTML_HELP_ID_FOUND);
  736.       }
  737.  
  738.     return(0);
  739. }
  740.  
  741. PRIVATE void
  742. net_HelpPreExitRoutine(URL_Struct *URL_s, int status, MWContext *context)
  743. {
  744.  
  745.     /* @@@@.  I wanted to use the fe_data to pass the URL struct
  746.      * of the frame content URL.  But the fe_data gets cleared
  747.      * by the front ends.  Therefore I'm using a private global
  748.      * store the information.  This will work fine as long
  749.      * as two help requests don't come in simulatainiously.
  750.      */
  751.  
  752.     /* compatibility for previous versions of NetHelp */
  753.     if(frame_content_for_pre_exit_routine) {
  754.  
  755.         NET_GetURL(frame_content_for_pre_exit_routine,
  756.                    FO_CACHE_AND_PRESENT,
  757.                    context,
  758.                    simple_exit);
  759.         frame_content_for_pre_exit_routine=NULL;
  760.     } else {
  761.         LM_SendOnHelp(context);
  762.     }
  763.  
  764.  
  765. }
  766.  
  767. PRIVATE void 
  768. net_help_init_chrome(Chrome *window_chrome, int32 w, int32 h)
  769. {
  770.     window_chrome->type           = MWContextHTMLHelp;
  771.   #if defined(XP_WIN) || defined(XP_UNIX)
  772.     window_chrome->topmost        = FALSE;
  773.   #else
  774.     window_chrome->topmost        = TRUE;  
  775.   #endif
  776.     window_chrome->w_hint         = w;
  777.     window_chrome->h_hint         = h;
  778.     window_chrome->allow_resize   = TRUE;
  779.     window_chrome->show_scrollbar = TRUE;
  780.     window_chrome->allow_close    = TRUE;
  781.     window_chrome->disable_commands = TRUE;
  782.     window_chrome->restricted_target = TRUE;
  783. }
  784.  
  785. PRIVATE void
  786. net_ParseHTMLHelpLoadHelpDoc(HTMLHelpParseObj *obj, MWContext *context)
  787. {
  788.     URL_Struct *URL_s;
  789.     char *frame_address = NULL;
  790.     char *content_address = NULL;
  791.     MWContext *new_context;
  792.     frame_set_struct *fgs;
  793.  
  794.     if(obj->id_value || obj->default_id_value)
  795.         content_address = NET_MakeAbsoluteURL(obj->url_to_map_file, 
  796.                                               obj->id_value ? 
  797.                                                 obj->id_value : 
  798.                                                 obj->default_id_value);
  799.  
  800.     if(!content_address)
  801.       {
  802.         FE_Alert(context, XP_GetString(MK_CANT_LOAD_HELP_TOPIC));
  803.         return;
  804.       }
  805.  
  806.     fgs = XP_ListPeekTopObject(obj->frame_group_stack);
  807.  
  808.     if(fgs)
  809.       {
  810.         if(fgs->address)
  811.           {
  812.             frame_address = NET_MakeAbsoluteURL(obj->url_to_map_file, 
  813.                                                 fgs->address);
  814.           }
  815.       }
  816.  
  817.     if(frame_address)
  818.         URL_s = NET_CreateURLStruct(frame_address, NET_DONT_RELOAD);
  819.     else
  820.         URL_s = NET_CreateURLStruct(content_address, NET_DONT_RELOAD);
  821.  
  822.     if(!URL_s)
  823.         goto cleanup;
  824.  
  825.     URL_s->window_chrome = XP_NEW(Chrome);    
  826.  
  827.     if(!URL_s->window_chrome)
  828.         goto cleanup;
  829.  
  830.     XP_MEMSET(URL_s->window_chrome, 0, sizeof(Chrome));
  831.  
  832.     if(obj->window_name)
  833.         URL_s->window_target = XP_STRDUP(obj->window_name);
  834.     else
  835.         URL_s->window_target = XP_STRDUP(DEFAULT_HELP_WINDOW_NAME);
  836.  
  837.     net_help_init_chrome(URL_s->window_chrome, 
  838.                          obj->window_width, 
  839.                          obj->window_height);
  840.  
  841.     /* We want to revert the character set of the help frame from the standard
  842.        character set, not whatever happened to be the last viewed source */
  843.  
  844.     StrAllocCopy(URL_s->charset, INTL_ResourceCharSet());
  845.     
  846.     new_context = XP_FindNamedContextInList(NULL, URL_s->window_target);
  847.  
  848.     if(frame_address)
  849.       {
  850.         URL_Struct *content_URL_s;
  851.  
  852.         /* if there is a frame_address then we load the
  853.          * frame first and then load the contents
  854.          * in the frame exit function.
  855.          */
  856.         content_URL_s = NET_CreateURLStruct(content_address, NET_DONT_RELOAD);
  857.  
  858.         if(obj->content_target)
  859.             content_URL_s->window_target = XP_STRDUP(obj->content_target);
  860.         else if(fgs->target)
  861.             content_URL_s->window_target = XP_STRDUP(fgs->target);
  862.  
  863.         /* doesn't work: URL_s->fe_data = (void *) content_URL_s; */
  864.  
  865.         /* hack for older versions, see pre_exit_routine_above */
  866.         if (obj->helpVersion < 2) {
  867.             frame_content_for_pre_exit_routine = content_URL_s;
  868.         } else {
  869.             frame_content_for_pre_exit_routine = NULL;
  870.             NET_FreeURLStruct(content_URL_s);
  871.         }
  872.  
  873.         URL_s->pre_exit_fn = net_HelpPreExitRoutine;
  874.       }
  875.  
  876.     if(!new_context)
  877.       {
  878.       
  879.         /* this will cause the load too */
  880.         new_context = FE_MakeNewWindow(context, 
  881.                          URL_s, 
  882.                          (obj->window_name) ? obj->window_name :  DEFAULT_HELP_WINDOW_NAME, 
  883.                          URL_s->window_chrome);
  884.  
  885.         if (HELP_INFO_PTR(*new_context) == NULL) {
  886.             new_context->pHelpInfo = XP_NEW_ZAP(HelpInfoStruct);
  887.         }
  888.         
  889.         if (HELP_INFO_PTR(*new_context)->topicURL != NULL) {
  890.             XP_FREE(HELP_INFO_PTR(*new_context)->topicURL);
  891.             HELP_INFO_PTR(*new_context)->topicURL = NULL;
  892.         }
  893.         
  894.         StrAllocCopy(HELP_INFO_PTR(*new_context)->topicURL, content_address);
  895.  
  896.       }
  897.     else
  898.       {
  899.     
  900.         if (HELP_INFO_PTR(*new_context) == NULL) {
  901.             new_context->pHelpInfo = XP_NEW_ZAP(HelpInfoStruct);
  902.         }
  903.         
  904.         if (HELP_INFO_PTR(*new_context)->topicURL != NULL) {
  905.             XP_FREE(HELP_INFO_PTR(*new_context)->topicURL);
  906.             HELP_INFO_PTR(*new_context)->topicURL = NULL;
  907.         }
  908.         
  909.         StrAllocCopy(HELP_INFO_PTR(*new_context)->topicURL, content_address);
  910.  
  911.         FE_RaiseWindow(new_context);
  912.  
  913.         /* Compatibility with earlier versions of NetHelp */
  914.         if (obj->helpVersion < 2) {
  915.             FE_GetURL(new_context, URL_s);
  916.         } else {
  917.             LM_SendOnHelp(new_context);
  918.         }
  919.       }
  920.  
  921. cleanup:
  922.     FREEIF(frame_address);
  923.     FREE(content_address);
  924.  
  925.     return;
  926. }
  927.  
  928. typedef struct {
  929.     HTMLHelpParseObj *parse_obj;
  930.     MWContext        *context;
  931.     XP_Bool           file_is_local;
  932. } html_help_map_stream;
  933.  
  934. PRIVATE int
  935. net_HMFConvPut(NET_StreamClass *stream, char *s, int32 l)
  936. {
  937.     html_help_map_stream *obj=stream->data_object;
  938.     int status = NET_ParseHTMLHelpPut(obj->parse_obj, s, l);        
  939.  
  940.     if(obj->file_is_local && status == HTML_HELP_ID_FOUND)
  941.       {
  942.         /* abort since we don't need any more of the file */
  943.         return(MK_UNABLE_TO_CONVERT);
  944.       }
  945.  
  946.     return(status);
  947. }
  948.  
  949. PRIVATE int
  950. net_HMFConvWriteReady(NET_StreamClass *stream)
  951. {    
  952.     return(MAX_WRITE_READY);
  953. }
  954.  
  955. PRIVATE void
  956. net_HMFConvComplete(NET_StreamClass *stream)
  957. {
  958.     html_help_map_stream *obj=stream->data_object;    
  959.     net_ParseHTMLHelpLoadHelpDoc(obj->parse_obj, obj->context);
  960.     net_ParseHTMLHelpFree(obj->parse_obj);
  961. }
  962.  
  963. PRIVATE void
  964. net_HMFConvAbort(NET_StreamClass *stream, int status)
  965. {
  966.     html_help_map_stream*obj=stream->data_object;    
  967.     if(status == MK_UNABLE_TO_CONVERT)
  968.         net_ParseHTMLHelpLoadHelpDoc(obj->parse_obj, obj->context);
  969.  
  970.     net_ParseHTMLHelpFree(obj->parse_obj);
  971. }
  972.  
  973. PUBLIC NET_StreamClass *
  974. NET_HTMLHelpMapToURL(int         format_out,
  975.                      void       *data_object,
  976.                      URL_Struct *URL_s,
  977.                      MWContext  *window_id)
  978. {
  979.     html_help_map_stream* obj;
  980.     NET_StreamClass* stream;
  981.  
  982.     TRACEMSG(("Setting up display stream. Have URL: %s\n", URL_s->address));
  983.  
  984.     stream = XP_NEW(NET_StreamClass);
  985.     if(stream == NULL)
  986.         return(NULL);
  987.  
  988.     obj = XP_NEW(html_help_map_stream);
  989.     if (obj == NULL)
  990.       {
  991.         FREE(stream);
  992.         return(NULL);
  993.       }
  994.  
  995.     XP_MEMSET(obj, 0, sizeof(html_help_map_stream));
  996.  
  997.     if(URL_s->cache_file || URL_s->memory_copy)
  998.         obj->file_is_local = TRUE;
  999.     else
  1000.         obj->file_is_local = NET_IsLocalFileURL(URL_s->address);
  1001.     
  1002.     obj->parse_obj = net_ParseHTMLHelpInit(URL_s->address, URL_s->fe_data);
  1003.  
  1004.     if(!obj->parse_obj)
  1005.       {
  1006.         FREE(stream);
  1007.         FREE(obj);
  1008.       }
  1009.  
  1010.     obj->context = window_id;
  1011.     stream->name           = "HTML Help Map File converter";
  1012.     stream->complete       = (MKStreamCompleteFunc) net_HMFConvComplete;
  1013.     stream->abort          = (MKStreamAbortFunc) net_HMFConvAbort;
  1014.     stream->put_block      = (MKStreamWriteFunc) net_HMFConvPut;
  1015.     stream->is_write_ready = (MKStreamWriteReadyFunc) net_HMFConvWriteReady;
  1016.     stream->data_object    = obj;  /* document info object */
  1017.     stream->window_id      = window_id;
  1018.  
  1019.     return(stream);
  1020. }
  1021.  
  1022.  
  1023.