2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: helpgen.c /main/8 1998/04/20 12:52:36 mgreess $ */
33 #include <sys/param.h>
35 #include <sys/types.h>
38 #include <X11/Xresource.h>
39 #include <X11/Intrinsic.h>
42 #include <Dt/EnvControlP.h>
44 #include "HelpP.h" /* in DtHelp library */
45 #include "GenUtilsP.h" /* in DtHelp library */
46 #include "ObsoleteP.h" /* in DtHelp library */
47 #include "bufioI.h" /* for AccessI.h */
48 #include "Access.h" /* in DtHelp library */
49 #include "AccessP.h" /* in DtHelp library */
50 #include "AccessI.h" /* in DtHelp library */
51 #include "AccessCCDFI.h" /* in DtHelp library */
52 #include "StringFuncsI.h" /* in DtHelp library */
55 #include <LocaleXlate.h>
59 static const int NL_CAT_LOCALE = 0;
62 #ifndef CDE_INSTALLATION_TOP
63 #define CDE_INSTALLATION_TOP "/usr/dt"
66 #ifndef CDE_CONFIGURATION_TOP
67 #define CDE_CONFIGURATION_TOP "/etc/dt"
70 #ifndef DtSYS_FILE_SEARCH_ENV
71 #define DtSYS_FILE_SEARCH_ENV "DTHELPSEARCHPATH"
74 #ifndef DtUSER_FILE_SEARCH_ENV
75 #define DtUSER_FILE_SEARCH_ENV "DTHELPUSERSEARCHPATH"
78 /*****************************************************************************
80 *****************************************************************************/
82 #define VOLUME_EXT ".hv"
83 #define FAMILY_EXT ".hf"
85 /*****************************************************************************
87 *****************************************************************************/
88 static const char *ShellCmd = "sh";
89 static const char *UsageStr =
90 "%s -dir <directory> [-generate] [-file <name>] [-lang <language>]\n";
91 static const char *TopLocId = "_hometopic";
92 static const char *SlashString = "/";
93 static const char *C_String = "C";
94 static const char *DefCharSet = "C.ISO-8859-1";
95 static const char *Family_ext = FAMILY_EXT;
96 static const char *Ext_Hv = ".hv";
97 static const char *Ext_Sdl = ".sdl";
99 static const char *SuperMsg =
100 "%s: Access denied for directory %s\nTry running as super user?\n";
101 static const char *GeneralAccess =
102 "%s: Unable to access %s - error status number %d\n";
103 static const char *NotDirectory = "%s: Element of %s is not a directory\n";
104 static const char *WriteInvalid = "%s: Write to %s invalid\n";
105 static const char *defaultTopic = "<TOPIC charset %s>\n";
106 static const char *defaultTitle12 =
107 "<TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic>\n%s\n</ANGLE></SIZE></WEIGHT></TYPE>\n";
108 static const char *defaultTitle14 =
109 "<TITLE><TYPE serif><WEIGHT bold><SIZE 14>\n%s\n</SIZE></WEIGHT></TYPE></TITLE>\n";
111 static const char *defaultTextBody =
112 "<ABBREV>Welcome to the Help Manager</ABBREV> \n\
113 <PARAGRAPH>Each of the titles listed below represents a <ANGLE italic> \n\
114 product family</> that has installed and registered its online help. Each \n\
115 title (and icon) is a hyperlink that lists the help within the family.</> \n\
116 <PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">To \n\
117 display a list of the help available for a product family, choose its \n\
118 title (underlined text) or icon.</PARAGRAPH> \n\
119 <PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">\n\
121 family, find the help you want to view, then choose its title.</PARAGRAPH> \n\
122 <PARAGRAPH first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\"> \n\
123 If you need help while using help windows, press F1.</PARAGRAPH>";
125 static const char *defaultAlternate =
126 "<ABBREV>Welcome to the Help Manager</ABBREV> \n\
127 <LINK 0 \"Help4Help How-To-Register-Help\"> \n\
128 <TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic> \n\
129 Note:\\ \\ \\ No Help Registered</SIZE></WEIGHT></TYPE></></LINK> \n\
130 <PARAGRAPH leftindent 3 firstindent 3> \n\
131 <WEIGHT bold>No product families have registered their online help \n\
132 files for browsing.</> Help may be available for some applications by \n\
133 choosing Help commands directly within the applications.</>";
135 /*****************************************************************************
137 *****************************************************************************/
140 char *ParentName = "_HOMETOPIC";
142 char **TopicList = NULL;
144 /* The family search list */
145 char **FUserList = NULL;
146 char **FSysList = NULL;
148 /* The volume search list */
149 char **VUserList = NULL;
150 char **VSysList = NULL;
152 char **FamilyList = NULL; /* the names of the unique families */
153 char **FullFamilyName = NULL; /* the fully qualified family names */
154 char **VolumeList = NULL; /* the names (only) of volume */
155 char **FullVolName = NULL; /* the fully qualified volume names */
157 char TopicName [MAXPATHLEN + 2];
161 /* Global Message Catalog file names */
162 /*****************************************************************************
163 * Private Function Declarations
164 *****************************************************************************/
165 extern char *FindFile (char *filename);
167 /*****************************************************************************
168 * options and resources
169 *****************************************************************************/
175 } ApplicationArgs, *ApplicationArgsPtr;
177 static ApplicationArgs App_args =
184 /*****************************************************************************
185 * void MyExit(exit_val, pid)
186 *****************************************************************************/
192 if (pid != ((pid_t) -1))
193 (void) kill(pid, SIGKILL);
198 /*****************************************************************************
199 * char *GetMessage(set, n, s)
200 *****************************************************************************/
209 char *catFileName=NULL;
210 static nl_catd nlmsg_fd;
211 static int first = 1;
216 /* Setup our default message catalog names if none have been set! */
217 /* Setup the short and long versions */
218 catFileName = "dthelpgen";
221 if (strcmp (Lang, "C") == 0)
223 * If LANG is not set or if LANG=C, then there
224 * is no need to open the message catalog - just
225 * return the built-in string "s".
227 nlmsg_fd = (nl_catd) -1;
229 nlmsg_fd = catopen(catFileName, NL_CAT_LOCALE);
231 msg=catgets(nlmsg_fd,set,n,s);
236 /*****************************************************************************
237 * Boolean *GetPath(filename)
238 *****************************************************************************/
240 GetPath (char *filename, short strip, char ***list )
247 ptr = strrchr (filename, '/');
254 while (next != NULL && *next != NULL && strcmp (*next, filename))
257 if (next == NULL || *next == NULL)
258 *list = (char **) _DtHelpCeAddPtrToArray ((void **) (*list),
264 /*****************************************************************************
265 * char *GetExtension(filename)
266 * char *filename - name of file to get the extension from.
267 * return a pointer to the extension of the file name
268 *****************************************************************************/
270 GetExtension(char *filename )
276 * need multi-byte functionality here
278 ext = strrchr(filename, '.');
280 return(ext); /* safe because ext not in middle of character */
282 return(""); /* never returns NULL */
285 /*****************************************************************************
286 * Function: CreateVolumeLink
288 * outTopic the output stream.
289 * volume_name Searches for a volume by this name.
291 * Reads a volume database and creates a label paragraph entry.
293 *****************************************************************************/
302 char *charSet = (char *) DefCharSet;
303 char *abstract = NULL;
304 char *pathName = NULL;
305 VolumeHandle volume = NULL;
307 pathName = FindFile (volume_name);
308 if (pathName != NULL && _DtHelpCeOpenVolume(canvas,pathName,&volume) == 0)
310 if (_DtHelpCeGetVolumeTitle (canvas, volume, &title) == 0)
312 else if (_DtHelpCeGetTopicTitle(canvas,volume,(char*)TopLocId,&title)
318 if (_DtHelpCeGetAsciiVolumeAbstract(canvas,volume,&abstract) == -1)
321 charSet = _DtHelpCeGetVolumeLocale(volume);
323 charSet = (char *) DefCharSet;
325 _DtHelpCeCloseVolume (canvas, volume);
330 fprintf (outTopic, (GetMessage(3, 4, "<CHARACTERSET %s>\n")), charSet);
331 fprintf (outTopic,"<LINK 0 \"%s %s\">\n", volume_name, (char*)TopLocId);
332 fprintf (outTopic, (GetMessage(3, 5, (char*)defaultTitle12)), title);
333 fprintf (outTopic, "</LINK>\n");
336 * put the abstract information about this
337 * family in the header file
339 fprintf (outTopic, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
341 if (abstract != NULL)
343 fprintf (outTopic, (GetMessage (3, 4, "<CHARACTERSET %s>\n")),
345 fprintf (outTopic, "%s\n", abstract);
346 fprintf (outTopic, "</CHARACTERSET>\n");
349 fprintf (outTopic, "</P>\n</CHARACTERSET>\n");
352 if (charSet != DefCharSet)
356 free ((void *) title);
361 /*****************************************************************************
362 * Function: CreateFamily
364 *****************************************************************************/
376 char *charSet = NULL;
378 char *abstract = NULL;
383 char familyName [20]; /* FAMILY%d */
384 char bitmapName [MAXPATHLEN + 2];
385 char bitmapNameTemp [sizeof(bitmapName)];
391 db = XrmGetFileDatabase (family_name);
397 if (XrmGetResource (db, "Family.Title", "family.title",
398 &resType, &resValue))
400 title = (char *) resValue.addr;
405 if (XrmGetResource (db, "Family.Abstract", "family.abstract",
406 &resType, &resValue))
408 abstract = (char *) resValue.addr;
411 * get the volumes list
413 if (XrmGetResource (db, "Family.Volumes", "family.volumes",
414 &resType, &resValue))
416 list = (char *) resValue.addr;
419 * get the character set
421 if (XrmGetResource (db, "Family.CharSet", "family.charSet",
422 &resType, &resValue))
424 charSet = (char *) resValue.addr;
427 * get the bitmap (optional)
429 if (XrmGetResource (db,
430 "Family.Bitmap", "family.bitmap",
431 &resType, &resValue))
432 bitmap = (char *) resValue.addr;
438 "%s: character set resource missing\n")),
447 "%s: volumes resource missing\n")),
455 (GetMessage (1, 12, "%s: abstract resource missing\n")),
463 (GetMessage (1, 11, "%s: title resource missing\n")),
468 if (title && abstract && list && charSet)
471 * find out the position of the file pointer
473 filepos = ftell (out_topic);
476 * write out the <TOPIC>
478 fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
482 * write out the <TITLE>
484 fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
486 fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
487 fprintf (out_topic, "%s\n", abstract);
488 fprintf (out_topic, "</P>\n");
493 list = _DtHelpCeGetNxtToken(list, &token);
494 if (token && *token != '\0' && *token != '\n' &&
495 CreateVolumeLink (canvas,out_topic, token) == 0)
500 free ((void *) token);
504 } while (list && *list != '\0');
509 sprintf (familyName, "FAMILY%d", FamilyNum);
510 fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
513 * Put the link information in the header file
516 (GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
517 fprintf (out_header, "<LINK 0 %s>\n", familyName);
518 fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
520 fprintf (out_header, "</LINK>\n");
523 * put the abstract information about this
524 * family in the header file
526 if (NULL != bitmap && *bitmap != '/')
528 snprintf(bitmapName, sizeof(bitmapName), "%s", family_name);
529 ptr = strrchr (bitmapName, '/');
534 snprintf(bitmapNameTemp, sizeof(bitmapNameTemp), "%s%s", bitmapName, bitmap);
535 strcpy(bitmapName, bitmapNameTemp);
546 "<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
550 fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
551 fprintf (out_header, "%s\n", abstract);
552 fprintf (out_header, "</P></CHARACTERSET>\n");
555 * put the information in the volume file.
557 fprintf (out_volume, "*.%s.filepos: %ld\n",
558 familyName, filepos);
559 fprintf (out_volume, "*.%s.filename: %s\n",
560 familyName, TopicName);
561 TopicList = (char **) _DtHelpCeAddPtrToArray (
563 strdup (familyName));
568 * rewind back to the original starting position
570 fseek (out_topic, filepos, 0);
573 * didn't find any volumes for this family.
578 XrmDestroyDatabase (db);
584 /*****************************************************************************
585 * Function: CheckFamilyList (name)
587 * See if this family has been seen
589 *****************************************************************************/
591 CheckFamilyList (char *name )
593 char **listPtr = FamilyList;
595 while (listPtr != NULL && *listPtr != NULL)
597 if (strcmp (*listPtr, name) == 0)
605 /*****************************************************************************
606 * Function: AddFamilyToList (name)
608 * add the name to the family list
610 *****************************************************************************/
612 AddFamilyToList (char *name )
615 FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
620 /*****************************************************************************
621 * Function: ScanDirectory
623 * scan a directory looking for family files.
625 *****************************************************************************/
634 char fullName [MAXPATHLEN + 2];
638 struct dirent *pDirent;
641 if (stat(directory, &buf) == -1)
644 *ret_time = buf.st_mtime;
646 pDir = opendir (directory);
650 snprintf(fullName, sizeof(fullName), "%s%s", directory, SlashString);
651 ptr = fullName + strlen (fullName);
654 * skip over the "." and ".." entries.
656 (void) readdir (pDir);
657 (void) readdir (pDir);
658 pDirent = readdir (pDir);
661 ext = GetExtension (pDirent->d_name);
662 if (strcmp (ext, Family_ext) == 0)
664 if (CheckFamilyList (pDirent->d_name) == False)
666 AddFamilyToList (pDirent->d_name);
668 strcpy (ptr, pDirent->d_name);
669 FullFamilyName = (char **) _DtHelpCeAddPtrToArray(
670 (void **)FullFamilyName,
674 else if (strcmp(ext, Ext_Hv) == 0 || strcmp(ext, Ext_Sdl) == 0)
676 strcpy (ptr, pDirent->d_name);
677 VolumeList = (char **) _DtHelpCeAddPtrToArray((void **)VolumeList,
678 strdup(pDirent->d_name));
679 FullVolName = (char **) _DtHelpCeAddPtrToArray((void **)FullVolName,
683 pDirent = readdir (pDir);
690 /*****************************************************************************
693 * Resolves the environment variable for all possible paths.
695 *****************************************************************************/
707 fileExt = GetExtension(filename);
708 if (*fileExt == '\0')
712 while (VolumeList != NULL && VolumeList[i] != NULL)
716 ext = GetExtension(VolumeList[i]);
720 different = strcmp(filename, VolumeList[i]);
724 if (!different && access(FullVolName[i], R_OK) == 0
725 && stat(FullVolName[i], &status) == 0
726 && S_ISDIR(status.st_mode) == 0)
727 return (FullVolName[i]);
735 /*****************************************************************************
736 * Function: ExpandPaths
738 * Resolves the environment variable for all possible paths.
740 *****************************************************************************/
756 searchPath = getenv (env_var);
757 if (searchPath == NULL || *searchPath == '\0')
759 if (default_str == NULL)
762 searchPath = default_str;
765 searchPath = strdup (searchPath);
771 ptr = strchr (src, ':');
776 * check to see if %H is declared. If so, we're going
777 * to have to trim it before saving as the directory path.
780 hPtr = strrchr (src, '%');
789 * check to see if the path needs expanding
791 if (NULL != strchr (src, '%'))
792 pathName = _DtHelpCeExpandPathname (src, NULL, type, NULL, lang,
793 (_DtSubstitutionRec *) NULL, 0);
795 pathName = strdup(src);
799 GetPath (pathName, strip, list);
809 } while (src && *src);
814 /*****************************************************************************
815 * Function: CheckTimeStamps
817 * Check the time stamps on the volume dir to determine if
818 * it needs regenerating.
820 *****************************************************************************/
830 while (*dir_list != NULL)
832 if (stat(*dir_list, &buf) == -1)
835 value = _DtHelpCeGetResourceString(db, *dir_list,
836 "TimeStamp", "timeStamp");
837 timeVal = atol(value);
838 if (timeVal != buf.st_mtime)
847 /*****************************************************************************
848 * Function: CheckInfo
850 * Check the information in the volume to determine if it needs regenerating.
852 *****************************************************************************/
858 char **list1, **list2;
862 db = XrmGetFileDatabase (file);
865 volDirList = _DtHelpCeGetResourceStringArray(db, NULL,
866 "DirList", "dirList");
867 if (volDirList != NULL)
872 while (result == 0 && *list1 != NULL
873 && list2 != NULL && *list2 != NULL)
875 result = strcmp(*list1, *list2);
880 if (list2 != NULL && *list2 != NULL)
884 while (result == 0 && *list1 != NULL
885 && list2 != NULL && *list2 != NULL)
887 result = strcmp(*list1, *list2);
892 if (list2 != NULL && *list2 != NULL)
896 while (result == 0 && *list1 != NULL
897 && list2 != NULL && *list2 != NULL)
899 result = strcmp(*list1, *list2);
904 if (list2 != NULL && *list2 != NULL)
908 while (result == 0 && *list1 != NULL
909 && list2 != NULL && *list2 != NULL)
911 result = strcmp(*list1, *list2);
916 if (*list1 != NULL || (list2 != NULL && *list2 != NULL))
920 result = CheckTimeStamps(db, volDirList);
922 _DtHelpCeFreeStringArray(volDirList);
924 XrmDestroyDatabase(db);
930 /*****************************************************************************
932 *****************************************************************************/
945 char tmpVolume [MAXPATHLEN + 2];
946 char tmpVolumeTemp[sizeof(tmpVolume)];
947 char tmpVolume2 [MAXPATHLEN + 2];
948 char tmpTopic [MAXPATHLEN + 2];
949 char tmpHeader [MAXPATHLEN + 2];
950 char headerName [MAXPATHLEN + 2];
951 char baseName [MAXPATHLEN + 2];
952 char baseNameTemp[sizeof(baseName)];
953 char tempName [MAXPATHLEN + 2];
965 pid_t childPid = (pid_t) -1;
966 CanvasHandle canvasHandle;
968 myName = strrchr (argv[0], '/');
975 * have to do a setlocale here, so that the usage message is in the
978 Lang = getenv ("LANG");
981 * use the default if no lang is specified.
983 if (Lang == NULL || *Lang == '\0')
984 Lang = (char*)C_String;
986 setlocale(LC_ALL, "");
987 _DtEnvControl(DT_ENV_SET);
990 * now process the arguments
992 for (i = 1; i < argc; i++)
994 if (argv[i][0] == '-')
996 if (argv[i][1] == 'd' && i + 1 < argc)
997 App_args.dir = argv[++i];
998 else if (argv[i][1] == 'f' && i + 1 < argc)
999 App_args.file = argv[++i];
1000 else if (argv[i][1] == 'g')
1002 else if (argv[i][1] == 'l' && i + 1 < argc)
1003 App_args.lang = argv[++i];
1006 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1012 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1018 * get the language we are working with.
1020 if (App_args.lang != NULL)
1023 * Set the locale! Since the user has specified a (likely)
1024 * different language to do the processing in, we need to
1025 * do a setlocale to work with the new language.
1027 Lang = App_args.lang;
1028 if (setlocale(LC_ALL, Lang) == NULL)
1030 fprintf (stderr, (GetMessage(1, 20,
1031 "%s: Invalid system language specified - %s\n")),
1035 _DtEnvControl(DT_ENV_SET);
1037 Lang = strdup(Lang);
1040 * get the directory to work in
1042 if (NULL == App_args.dir)
1044 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1048 if (App_args.dir[0] != '/')
1050 if (getcwd (baseName, MAXPATHLEN) == NULL)
1052 fprintf (stderr, (GetMessage (1, 18,
1053 "%s: Unable to access current working directory - error status number %d\n")),
1057 snprintf(baseNameTemp, sizeof(baseNameTemp), "%s/%s", baseName, App_args.dir);
1058 strcpy(baseName, baseNameTemp);
1061 snprintf(baseName, sizeof(baseName), "%s", App_args.dir);
1064 * make sure the directory exists
1066 ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
1067 (_DtSubstitutionRec *) NULL, 0);
1068 if (ptr == NULL || *ptr == '\0')
1071 (GetMessage (1, 15, "%s: Destination directory missing\n")),
1076 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1077 if (tmpVolume[strlen (tmpVolume) - 1] != '/') {
1078 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, SlashString);
1079 strcpy(tmpVolume, tmpVolumeTemp);
1085 * march down the path, checking that
1087 * 2) the caller has access permission.
1088 * 3) resolve all symbolic links
1090 endDir = strchr (tmpVolume, '/');
1094 endDir = strchr (endDir, '/');
1096 while (endDir && *endDir != '\0')
1099 * remember the rest of the string (including the slash)
1100 * and strip the trailing slash from the directory path.
1102 snprintf(tmpVolume2, sizeof(tmpVolume2), "%s", endDir);
1106 * trace the path and copy the new string into the old buffer.
1108 ptr = _DtHelpCeTracePathName(tmpVolume);
1111 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1115 if (access (tmpVolume, F_OK) == -1)
1120 ptr = GetMessage (1, 2, (char*)NotDirectory);
1121 fprintf (stderr, ptr, myName, tmpVolume);
1125 ptr = GetMessage (1, 3, (char*)SuperMsg);
1126 fprintf (stderr, ptr, myName, tmpVolume);
1130 if (mkdir(tmpVolume,
1131 (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) == -1
1132 && errno != EEXIST && errno != EROFS)
1137 ptr = GetMessage(1,2,
1138 (char*)NotDirectory);
1142 ptr = GetMessage(1, 3,
1147 ptr = GetMessage(1, 4,
1148 "%s: Element of %s does not exist\n");
1152 ptr = GetMessage (1, 5,
1153 "%s: File system containing %s is full\n");
1157 ptr = GetMessage(1,6,
1158 (char*)GeneralAccess);
1161 fprintf (stderr, ptr, myName, tmpVolume, errno);
1166 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1167 fprintf (stderr, ptr, myName, tmpVolume, errno);
1173 * point to the end of the string (past where the slash will go)
1175 endDir = tmpVolume + strlen(tmpVolume) + 2;
1178 * append the rest of the directory spec that hasn't been checked.
1180 strcat (tmpVolume, tmpVolume2);
1181 endDir = strchr (endDir, '/');
1186 * get temporary files for the volume and topic file.
1188 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, App_args.file);
1189 strcpy(tmpVolume, tmpVolumeTemp);
1191 (void) strcpy (tmpHeader, tmpVolume);
1192 (void) strcpy (tmpTopic, tmpVolume);
1194 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, Ext_Hv);
1195 strcpy(tmpVolume, tmpVolumeTemp);
1196 (void) strcat (tmpHeader, "00.ht");
1197 (void) strcat (tmpTopic , "01.ht");
1199 result = access (tmpVolume, F_OK);
1202 * If it exists, make sure the invoker can write to it.
1206 if (access (tmpVolume, W_OK) == -1)
1209 ptr = GetMessage (1, 7,
1210 "%s: File system containing %s is read only\n");
1211 else if (errno == EACCES)
1212 ptr = GetMessage (1, 8,
1213 "%s: Requires root permission to write to %s\n");
1215 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1217 fprintf (stderr, ptr, myName, tmpVolume, errno);
1221 else if (result == -1 && errno != ENOENT)
1223 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1224 fprintf (stderr, ptr, myName, tmpVolume, errno);
1227 else /* file does not exist */
1232 * Find out if we have any paths to check.
1234 ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
1235 ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
1236 ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
1237 DtDEFAULT_SYSTEM_PATH, &FSysList);
1238 ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
1239 DtDEFAULT_SYSTEM_PATH, &VSysList);
1240 if (((FUserList == NULL || *FUserList == NULL) &&
1241 (FSysList == NULL || *FSysList == NULL)) ||
1242 ((VUserList == NULL || *VUserList == NULL) &&
1243 (VSysList == NULL || *VSysList == NULL)))
1245 ptr = GetMessage (1, 10, "%s: Search Path empty\n");
1246 fprintf (stderr, ptr, myName);
1251 * If we already haven't determined that the volume needs (re)generating
1252 * check the info squirreled away in the old volume.
1255 doGen = CheckInfo(tmpVolume);
1258 * the volume doesn't need (re)generating.
1265 * create a canvas for the functions.
1267 canvasHandle = _DtHelpCeCreateDefCanvas();
1268 if (canvasHandle == NULL)
1270 fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
1276 * open the individual files that will hold the browser information.
1279 outVolume = fopen (tmpVolume, "w");
1280 if (outVolume == NULL)
1282 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1283 fprintf (stderr, ptr, myName, tmpVolume, errno);
1284 _DtHelpCeDestroyCanvas(canvasHandle);
1291 outTopic = fopen (tmpTopic, "w");
1292 if (outTopic == NULL)
1294 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1295 fprintf (stderr, ptr, myName, tmpTopic, errno);
1296 (void) unlink (tmpVolume);
1297 _DtHelpCeDestroyCanvas(canvasHandle);
1304 outHeader = fopen (tmpHeader, "w");
1305 if (outHeader == NULL)
1307 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1308 fprintf (stderr, ptr, myName, tmpHeader, errno);
1309 (void) unlink (tmpVolume);
1310 (void) unlink (tmpTopic);
1311 _DtHelpCeDestroyCanvas(canvasHandle);
1316 * fork off the dtksh script that will put up a dialog
1317 * telling the user that we're building help browser
1326 * if this is the child, exec the dthelpgen.ds script.
1330 execlp("dthelpgen.ds", "dthelpgen.ds",
1331 ((char *) 0), ((char *) 0), ((char *) 0));
1336 * initialize the main topic
1338 strcpy (TopicName, App_args.file);
1339 strcat (TopicName, "01.ht");
1341 strcpy (headerName, App_args.file);
1342 strcat (headerName, "00.ht");
1345 * The original dthelpgen extracts the CDE Standard name from
1346 * its message catalogue( set 2/msg 1 ).
1347 * But on IBM ODE, this is a problem. For example,
1348 * fr_FR's dthelpgen.cat has
1349 * fr_FR.ISO-8859-1 in set 2/msg 1.
1350 * Correct Fr_FR's message catalogue must have,
1352 * there. But current IBM ode's Makefile cannot do this. Instead put
1353 * fr_FR.ISO-8859-1. ( That is "do nothing" ).
1354 * To fix this, dthelpgen converts the current IBM LANG to CDE
1355 * standard name with _DtLcx*() function provided by libDtHelp.a as
1360 _DtXlateDb db = NULL;
1362 char plat[_DtPLATFORM_MAX_LEN];
1365 char *ret_stdLocale;
1366 char *ret_stdLangTerr;
1367 char *ret_stdCodeset;
1368 char *ret_stdModifier;
1370 ret = _DtLcxOpenAllDbs( &db );
1372 ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
1374 ret = _DtLcxXlateOpToStd( db, plat, execver,
1375 DtLCX_OPER_SETLOCALE,
1376 setlocale( LC_MESSAGES, NULL ),
1377 &ret_stdLocale, &ret_stdLangTerr,
1378 &ret_stdCodeset, &ret_stdModifier );
1380 charSet = strdup( ret_stdLocale );
1382 charSet = "C.ISO-8859-1";
1385 charSet = "C.ISO-8859-1";
1387 ret = _DtLcxCloseDb( &db );
1389 charSet = "C.ISO-8859-1";
1394 charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
1396 topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
1398 fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
1399 charSet, topicTitle);
1401 fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
1404 preamble = ftell (outHeader);
1405 fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
1408 * loop through the directories looking for all the unique families
1409 * and -all- the volumes.
1411 fprintf (outVolume, "!# Last modification time stamp per directory\n");
1413 while (next != NULL && *next != NULL)
1415 ScanDirectory(*next, &modTime);
1416 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1420 while (next != NULL && *next != NULL)
1422 ScanDirectory(*next, &modTime);
1423 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1428 while (next != NULL && *next != NULL)
1430 ScanDirectory(*next, &modTime);
1431 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1435 while (next != NULL && *next != NULL)
1437 ScanDirectory(*next, &modTime);
1438 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1442 fprintf (outVolume, "*.charSet: %s\n", charSet);
1444 fprintf (outVolume, "\n!# Topic filenames and offsets\n");
1447 * Now create families.
1451 for (next = FullFamilyName; next != NULL && *next != NULL; next++)
1453 result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
1460 else if (result == -2)
1464 if (foundFamily == 0)
1466 GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
1467 else if (foundVolumes == 0)
1469 GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
1474 if (FamilyList != NULL)
1475 _DtHelpCeFreeStringArray(FamilyList);
1476 if (FullFamilyName != NULL)
1477 _DtHelpCeFreeStringArray(FullFamilyName);
1478 if (VolumeList != NULL)
1479 _DtHelpCeFreeStringArray(VolumeList);
1480 if (FullVolName != NULL)
1481 _DtHelpCeFreeStringArray(FullVolName);
1484 * If no family or volume files were found,
1485 * write out the alternative preamble
1487 if (foundFamily == 0 || foundVolumes == 0)
1489 fseek (outHeader, preamble, 0);
1490 fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
1494 * write the ending message and finish the topic.
1496 fprintf (outHeader, "</TOPIC>\n");
1499 * write out the volume resouces
1501 fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
1502 fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
1503 fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
1505 fprintf (outVolume, "\n\n!# Volume Title\n");
1506 fprintf (outVolume, "*.title: %s\n",
1507 GetMessage (2, 4, "Help - Top Level"));
1512 fprintf (outVolume, "\n\n!# Topic Home Location\n");
1513 fprintf (outVolume, "*.topTopic: %s\n", ParentName);
1518 fprintf (outVolume, "\n\n!# Topic Hierarchy\n");
1519 fprintf (outVolume, "*.%s.parent: \n", ParentName);
1520 for (next = TopicList; next && *next; next++)
1521 fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
1526 fprintf (outVolume, "\n\n!# Topic List\n");
1527 fprintf (outVolume, "*.topicList: %s", ParentName);
1529 while (next && *next)
1531 fprintf (outVolume, " \\\n %s", *next);
1534 fprintf (outVolume, "\n");
1537 * The paths used to create this information.
1539 fprintf (outVolume, "\n\n!# Paths Searched\n");
1540 fprintf (outVolume, "*.dirList: ");
1543 while (next != NULL && *next != NULL)
1545 fprintf (outVolume, " \\\n %s", *next);
1549 while (next != NULL && *next != NULL)
1551 fprintf (outVolume, " \\\n %s", *next);
1555 while (next != NULL && *next != NULL)
1557 fprintf (outVolume, " \\\n %s", *next);
1561 while (next != NULL && *next != NULL)
1563 fprintf (outVolume, " \\\n %s", *next);
1566 fprintf (outVolume, "\n");
1569 * close the volumes.
1575 if (TopicList != NULL)
1576 _DtHelpCeFreeStringArray(TopicList);
1578 if (FUserList != NULL)
1579 _DtHelpCeFreeStringArray(FUserList);
1580 if (FSysList != NULL)
1581 _DtHelpCeFreeStringArray(FSysList);
1582 if (VUserList != NULL)
1583 _DtHelpCeFreeStringArray(VUserList);
1584 if (VSysList != NULL)
1585 _DtHelpCeFreeStringArray(VSysList);
1587 _DtHelpCeDestroyCanvas(canvasHandle);
1589 MyExit (0, childPid);