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 */
219 catFileName = "dthelpgen.cat";
221 catFileName = "dthelpgen";
225 if (strcmp (Lang, "C") == 0)
227 * If LANG is not set or if LANG=C, then there
228 * is no need to open the message catalog - just
229 * return the built-in string "s".
231 nlmsg_fd = (nl_catd) -1;
233 nlmsg_fd = catopen(catFileName, NL_CAT_LOCALE);
235 msg=catgets(nlmsg_fd,set,n,s);
240 /*****************************************************************************
241 * Boolean *GetPath(filename)
242 *****************************************************************************/
244 GetPath (char *filename, short strip, char ***list )
251 ptr = strrchr (filename, '/');
258 while (next != NULL && *next != NULL && strcmp (*next, filename))
261 if (next == NULL || *next == NULL)
262 *list = (char **) _DtHelpCeAddPtrToArray ((void **) (*list),
268 /*****************************************************************************
269 * char *GetExtension(filename)
270 * char *filename - name of file to get the extension from.
271 * return a pointer to the extension of the file name
272 *****************************************************************************/
274 GetExtension(char *filename )
280 * need multi-byte functionality here
282 ext = strrchr(filename, '.');
284 return(ext); /* safe because ext not in middle of character */
286 return(""); /* never returns NULL */
289 /*****************************************************************************
290 * Function: CreateVolumeLink
292 * outTopic the output stream.
293 * volume_name Searches for a volume by this name.
295 * Reads a volume database and creates a label paragraph entry.
297 *****************************************************************************/
306 char *charSet = (char *) DefCharSet;
307 char *abstract = NULL;
308 char *pathName = NULL;
309 VolumeHandle volume = NULL;
311 pathName = FindFile (volume_name);
312 if (pathName != NULL && _DtHelpCeOpenVolume(canvas,pathName,&volume) == 0)
314 if (_DtHelpCeGetVolumeTitle (canvas, volume, &title) == 0)
316 else if (_DtHelpCeGetTopicTitle(canvas,volume,(char*)TopLocId,&title)
322 if (_DtHelpCeGetAsciiVolumeAbstract(canvas,volume,&abstract) == -1)
325 charSet = _DtHelpCeGetVolumeLocale(volume);
327 charSet = (char *) DefCharSet;
329 _DtHelpCeCloseVolume (canvas, volume);
334 fprintf (outTopic, (GetMessage(3, 4, "<CHARACTERSET %s>\n")), charSet);
335 fprintf (outTopic,"<LINK 0 \"%s %s\">\n", volume_name, (char*)TopLocId);
336 fprintf (outTopic, (GetMessage(3, 5, (char*)defaultTitle12)), title);
337 fprintf (outTopic, "</LINK>\n");
340 * put the abstract information about this
341 * family in the header file
343 fprintf (outTopic, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
345 if (abstract != NULL)
347 fprintf (outTopic, (GetMessage (3, 4, "<CHARACTERSET %s>\n")),
349 fprintf (outTopic, "%s\n", abstract);
350 fprintf (outTopic, "</CHARACTERSET>\n");
353 fprintf (outTopic, "</P>\n</CHARACTERSET>\n");
356 if (charSet != DefCharSet)
360 free ((void *) title);
365 /*****************************************************************************
366 * Function: CreateFamily
368 *****************************************************************************/
380 char *charSet = NULL;
382 char *abstract = NULL;
387 char familyName [20]; /* FAMILY%d */
388 char bitmapName [MAXPATHLEN + 2];
389 char bitmapNameTemp [sizeof(bitmapName)];
395 db = XrmGetFileDatabase (family_name);
401 if (XrmGetResource (db, "Family.Title", "family.title",
402 &resType, &resValue))
404 title = (char *) resValue.addr;
409 if (XrmGetResource (db, "Family.Abstract", "family.abstract",
410 &resType, &resValue))
412 abstract = (char *) resValue.addr;
415 * get the volumes list
417 if (XrmGetResource (db, "Family.Volumes", "family.volumes",
418 &resType, &resValue))
420 list = (char *) resValue.addr;
423 * get the character set
425 if (XrmGetResource (db, "Family.CharSet", "family.charSet",
426 &resType, &resValue))
428 charSet = (char *) resValue.addr;
431 * get the bitmap (optional)
433 if (XrmGetResource (db,
434 "Family.Bitmap", "family.bitmap",
435 &resType, &resValue))
436 bitmap = (char *) resValue.addr;
442 "%s: character set resource missing\n")),
451 "%s: volumes resource missing\n")),
459 (GetMessage (1, 12, "%s: abstract resource missing\n")),
467 (GetMessage (1, 11, "%s: title resource missing\n")),
472 if (title && abstract && list && charSet)
475 * find out the position of the file pointer
477 filepos = ftell (out_topic);
480 * write out the <TOPIC>
482 fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
486 * write out the <TITLE>
488 fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
490 fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
491 fprintf (out_topic, "%s\n", abstract);
492 fprintf (out_topic, "</P>\n");
497 list = _DtHelpCeGetNxtToken(list, &token);
498 if (token && *token != '\0' && *token != '\n' &&
499 CreateVolumeLink (canvas,out_topic, token) == 0)
504 free ((void *) token);
508 } while (list && *list != '\0');
513 sprintf (familyName, "FAMILY%d", FamilyNum);
514 fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
517 * Put the link information in the header file
520 (GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
521 fprintf (out_header, "<LINK 0 %s>\n", familyName);
522 fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
524 fprintf (out_header, "</LINK>\n");
527 * put the abstract information about this
528 * family in the header file
530 if (NULL != bitmap && *bitmap != '/')
532 snprintf(bitmapName, sizeof(bitmapName), "%s", family_name);
533 ptr = strrchr (bitmapName, '/');
538 snprintf(bitmapNameTemp, sizeof(bitmapNameTemp), "%s%s", bitmapName, bitmap);
539 strcpy(bitmapName, bitmapNameTemp);
550 "<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
554 fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
555 fprintf (out_header, "%s\n", abstract);
556 fprintf (out_header, "</P></CHARACTERSET>\n");
559 * put the information in the volume file.
561 fprintf (out_volume, "*.%s.filepos: %ld\n",
562 familyName, filepos);
563 fprintf (out_volume, "*.%s.filename: %s\n",
564 familyName, TopicName);
565 TopicList = (char **) _DtHelpCeAddPtrToArray (
567 strdup (familyName));
572 * rewind back to the original starting position
574 fseek (out_topic, filepos, 0);
577 * didn't find any volumes for this family.
582 XrmDestroyDatabase (db);
588 /*****************************************************************************
589 * Function: CheckFamilyList (name)
591 * See if this family has been seen
593 *****************************************************************************/
595 CheckFamilyList (char *name )
597 char **listPtr = FamilyList;
599 while (listPtr != NULL && *listPtr != NULL)
601 if (strcmp (*listPtr, name) == 0)
609 /*****************************************************************************
610 * Function: AddFamilyToList (name)
612 * add the name to the family list
614 *****************************************************************************/
616 AddFamilyToList (char *name )
619 FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
624 /*****************************************************************************
625 * Function: ScanDirectory
627 * scan a directory looking for family files.
629 *****************************************************************************/
638 char fullName [MAXPATHLEN + 2];
642 struct dirent *pDirent;
645 if (stat(directory, &buf) == -1)
648 *ret_time = buf.st_mtime;
650 pDir = opendir (directory);
654 snprintf(fullName, sizeof(fullName), "%s%s", directory, SlashString);
655 ptr = fullName + strlen (fullName);
658 * skip over the "." and ".." entries.
660 (void) readdir (pDir);
661 (void) readdir (pDir);
662 pDirent = readdir (pDir);
665 ext = GetExtension (pDirent->d_name);
666 if (strcmp (ext, Family_ext) == 0)
668 if (CheckFamilyList (pDirent->d_name) == False)
670 AddFamilyToList (pDirent->d_name);
672 strcpy (ptr, pDirent->d_name);
673 FullFamilyName = (char **) _DtHelpCeAddPtrToArray(
674 (void **)FullFamilyName,
678 else if (strcmp(ext, Ext_Hv) == 0 || strcmp(ext, Ext_Sdl) == 0)
680 strcpy (ptr, pDirent->d_name);
681 VolumeList = (char **) _DtHelpCeAddPtrToArray((void **)VolumeList,
682 strdup(pDirent->d_name));
683 FullVolName = (char **) _DtHelpCeAddPtrToArray((void **)FullVolName,
687 pDirent = readdir (pDir);
694 /*****************************************************************************
697 * Resolves the environment variable for all possible paths.
699 *****************************************************************************/
711 fileExt = GetExtension(filename);
712 if (*fileExt == '\0')
716 while (VolumeList != NULL && VolumeList[i] != NULL)
720 ext = GetExtension(VolumeList[i]);
724 different = strcmp(filename, VolumeList[i]);
728 if (!different && access(FullVolName[i], R_OK) == 0
729 && stat(FullVolName[i], &status) == 0
730 && S_ISDIR(status.st_mode) == 0)
731 return (FullVolName[i]);
739 /*****************************************************************************
740 * Function: ExpandPaths
742 * Resolves the environment variable for all possible paths.
744 *****************************************************************************/
760 searchPath = getenv (env_var);
761 if (searchPath == NULL || *searchPath == '\0')
763 if (default_str == NULL)
766 searchPath = default_str;
769 searchPath = strdup (searchPath);
775 ptr = strchr (src, ':');
780 * check to see if %H is declared. If so, we're going
781 * to have to trim it before saving as the directory path.
784 hPtr = strrchr (src, '%');
793 * check to see if the path needs expanding
795 if (NULL != strchr (src, '%'))
796 pathName = _DtHelpCeExpandPathname (src, NULL, type, NULL, lang,
797 (_DtSubstitutionRec *) NULL, 0);
799 pathName = strdup(src);
803 GetPath (pathName, strip, list);
813 } while (src && *src);
818 /*****************************************************************************
819 * Function: CheckTimeStamps
821 * Check the time stamps on the volume dir to determine if
822 * it needs regenerating.
824 *****************************************************************************/
834 while (*dir_list != NULL)
836 if (stat(*dir_list, &buf) == -1)
839 value = _DtHelpCeGetResourceString(db, *dir_list,
840 "TimeStamp", "timeStamp");
841 timeVal = atol(value);
842 if (timeVal != buf.st_mtime)
851 /*****************************************************************************
852 * Function: CheckInfo
854 * Check the information in the volume to determine if it needs regenerating.
856 *****************************************************************************/
862 char **list1, **list2;
866 db = XrmGetFileDatabase (file);
869 volDirList = _DtHelpCeGetResourceStringArray(db, NULL,
870 "DirList", "dirList");
871 if (volDirList != NULL)
876 while (result == 0 && *list1 != NULL
877 && list2 != NULL && *list2 != NULL)
879 result = strcmp(*list1, *list2);
884 if (list2 != NULL && *list2 != NULL)
888 while (result == 0 && *list1 != NULL
889 && list2 != NULL && *list2 != NULL)
891 result = strcmp(*list1, *list2);
896 if (list2 != NULL && *list2 != NULL)
900 while (result == 0 && *list1 != NULL
901 && list2 != NULL && *list2 != NULL)
903 result = strcmp(*list1, *list2);
908 if (list2 != NULL && *list2 != NULL)
912 while (result == 0 && *list1 != NULL
913 && list2 != NULL && *list2 != NULL)
915 result = strcmp(*list1, *list2);
920 if (*list1 != NULL || (list2 != NULL && *list2 != NULL))
924 result = CheckTimeStamps(db, volDirList);
926 _DtHelpCeFreeStringArray(volDirList);
928 XrmDestroyDatabase(db);
934 /*****************************************************************************
936 *****************************************************************************/
949 char tmpVolume [MAXPATHLEN + 2];
950 char tmpVolumeTemp[sizeof(tmpVolume)];
951 char tmpVolume2 [MAXPATHLEN + 2];
952 char tmpTopic [MAXPATHLEN + 2];
953 char tmpHeader [MAXPATHLEN + 2];
954 char headerName [MAXPATHLEN + 2];
955 char baseName [MAXPATHLEN + 2];
956 char baseNameTemp[sizeof(baseName)];
957 char tempName [MAXPATHLEN + 2];
969 pid_t childPid = (pid_t) -1;
970 CanvasHandle canvasHandle;
972 myName = strrchr (argv[0], '/');
979 * have to do a setlocale here, so that the usage message is in the
982 Lang = getenv ("LANG");
985 * use the default if no lang is specified.
987 if (Lang == NULL || *Lang == '\0')
988 Lang = (char*)C_String;
990 setlocale(LC_ALL, "");
991 _DtEnvControl(DT_ENV_SET);
994 * now process the arguments
996 for (i = 1; i < argc; i++)
998 if (argv[i][0] == '-')
1000 if (argv[i][1] == 'd' && i + 1 < argc)
1001 App_args.dir = argv[++i];
1002 else if (argv[i][1] == 'f' && i + 1 < argc)
1003 App_args.file = argv[++i];
1004 else if (argv[i][1] == 'g')
1006 else if (argv[i][1] == 'l' && i + 1 < argc)
1007 App_args.lang = argv[++i];
1010 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1016 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1022 * get the language we are working with.
1024 if (App_args.lang != NULL)
1027 * Set the locale! Since the user has specified a (likely)
1028 * different language to do the processing in, we need to
1029 * do a setlocale to work with the new language.
1031 Lang = App_args.lang;
1032 if (setlocale(LC_ALL, Lang) == NULL)
1034 fprintf (stderr, (GetMessage(1, 20,
1035 "%s: Invalid system language specified - %s\n")),
1039 _DtEnvControl(DT_ENV_SET);
1041 Lang = strdup(Lang);
1044 * get the directory to work in
1046 if (NULL == App_args.dir)
1048 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1052 if (App_args.dir[0] != '/')
1054 if (getcwd (baseName, MAXPATHLEN) == NULL)
1056 fprintf (stderr, (GetMessage (1, 18,
1057 "%s: Unable to access current working directory - error status number %d\n")),
1061 snprintf(baseNameTemp, sizeof(baseNameTemp), "%s/%s", baseName, App_args.dir);
1062 strcpy(baseName, baseNameTemp);
1065 snprintf(baseName, sizeof(baseName), "%s", App_args.dir);
1068 * make sure the directory exists
1070 ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
1071 (_DtSubstitutionRec *) NULL, 0);
1072 if (ptr == NULL || *ptr == '\0')
1075 (GetMessage (1, 15, "%s: Destination directory missing\n")),
1080 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1081 if (tmpVolume[strlen (tmpVolume) - 1] != '/') {
1082 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, SlashString);
1083 strcpy(tmpVolume, tmpVolumeTemp);
1089 * march down the path, checking that
1091 * 2) the caller has access permission.
1092 * 3) resolve all symbolic links
1094 endDir = strchr (tmpVolume, '/');
1098 endDir = strchr (endDir, '/');
1100 while (endDir && *endDir != '\0')
1103 * remember the rest of the string (including the slash)
1104 * and strip the trailing slash from the directory path.
1106 snprintf(tmpVolume2, sizeof(tmpVolume2), "%s", endDir);
1110 * trace the path and copy the new string into the old buffer.
1112 ptr = _DtHelpCeTracePathName(tmpVolume);
1115 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1119 if (access (tmpVolume, F_OK) == -1)
1124 ptr = GetMessage (1, 2, (char*)NotDirectory);
1125 fprintf (stderr, ptr, myName, tmpVolume);
1129 ptr = GetMessage (1, 3, (char*)SuperMsg);
1130 fprintf (stderr, ptr, myName, tmpVolume);
1134 if (mkdir(tmpVolume,
1135 (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) == -1
1136 && errno != EEXIST && errno != EROFS)
1141 ptr = GetMessage(1,2,
1142 (char*)NotDirectory);
1146 ptr = GetMessage(1, 3,
1151 ptr = GetMessage(1, 4,
1152 "%s: Element of %s does not exist\n");
1156 ptr = GetMessage (1, 5,
1157 "%s: File system containing %s is full\n");
1161 ptr = GetMessage(1,6,
1162 (char*)GeneralAccess);
1165 fprintf (stderr, ptr, myName, tmpVolume, errno);
1170 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1171 fprintf (stderr, ptr, myName, tmpVolume, errno);
1177 * point to the end of the string (past where the slash will go)
1179 endDir = tmpVolume + strlen(tmpVolume) + 2;
1182 * append the rest of the directory spec that hasn't been checked.
1184 strcat (tmpVolume, tmpVolume2);
1185 endDir = strchr (endDir, '/');
1190 * get temporary files for the volume and topic file.
1192 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, App_args.file);
1193 strcpy(tmpVolume, tmpVolumeTemp);
1195 (void) strcpy (tmpHeader, tmpVolume);
1196 (void) strcpy (tmpTopic, tmpVolume);
1198 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, Ext_Hv);
1199 strcpy(tmpVolume, tmpVolumeTemp);
1200 (void) strcat (tmpHeader, "00.ht");
1201 (void) strcat (tmpTopic , "01.ht");
1203 result = access (tmpVolume, F_OK);
1206 * If it exists, make sure the invoker can write to it.
1210 if (access (tmpVolume, W_OK) == -1)
1213 ptr = GetMessage (1, 7,
1214 "%s: File system containing %s is read only\n");
1215 else if (errno == EACCES)
1216 ptr = GetMessage (1, 8,
1217 "%s: Requires root permission to write to %s\n");
1219 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1221 fprintf (stderr, ptr, myName, tmpVolume, errno);
1225 else if (result == -1 && errno != ENOENT)
1227 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1228 fprintf (stderr, ptr, myName, tmpVolume, errno);
1231 else /* file does not exist */
1236 * Find out if we have any paths to check.
1238 ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
1239 ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
1240 ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
1241 DtDEFAULT_SYSTEM_PATH, &FSysList);
1242 ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
1243 DtDEFAULT_SYSTEM_PATH, &VSysList);
1244 if (((FUserList == NULL || *FUserList == NULL) &&
1245 (FSysList == NULL || *FSysList == NULL)) ||
1246 ((VUserList == NULL || *VUserList == NULL) &&
1247 (VSysList == NULL || *VSysList == NULL)))
1249 ptr = GetMessage (1, 10, "%s: Search Path empty\n");
1250 fprintf (stderr, ptr, myName);
1255 * If we already haven't determined that the volume needs (re)generating
1256 * check the info squirreled away in the old volume.
1259 doGen = CheckInfo(tmpVolume);
1262 * the volume doesn't need (re)generating.
1269 * create a canvas for the functions.
1271 canvasHandle = _DtHelpCeCreateDefCanvas();
1272 if (canvasHandle == NULL)
1274 fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
1280 * open the individual files that will hold the browser information.
1283 outVolume = fopen (tmpVolume, "w");
1284 if (outVolume == NULL)
1286 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1287 fprintf (stderr, ptr, myName, tmpVolume, errno);
1288 _DtHelpCeDestroyCanvas(canvasHandle);
1295 outTopic = fopen (tmpTopic, "w");
1296 if (outTopic == NULL)
1298 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1299 fprintf (stderr, ptr, myName, tmpTopic, errno);
1300 (void) unlink (tmpVolume);
1301 _DtHelpCeDestroyCanvas(canvasHandle);
1308 outHeader = fopen (tmpHeader, "w");
1309 if (outHeader == NULL)
1311 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1312 fprintf (stderr, ptr, myName, tmpHeader, errno);
1313 (void) unlink (tmpVolume);
1314 (void) unlink (tmpTopic);
1315 _DtHelpCeDestroyCanvas(canvasHandle);
1320 * fork off the dtksh script that will put up a dialog
1321 * telling the user that we're building help browser
1330 * if this is the child, exec the dthelpgen.ds script.
1334 execlp("dthelpgen.ds", "dthelpgen.ds",
1335 ((char *) 0), ((char *) 0), ((char *) 0));
1340 * initialize the main topic
1342 strcpy (TopicName, App_args.file);
1343 strcat (TopicName, "01.ht");
1345 strcpy (headerName, App_args.file);
1346 strcat (headerName, "00.ht");
1349 * The original dthelpgen extracts the CDE Standard name from
1350 * its message catalogue( set 2/msg 1 ).
1351 * But on IBM ODE, this is a problem. For example,
1352 * fr_FR's dthelpgen.cat has
1353 * fr_FR.ISO-8859-1 in set 2/msg 1.
1354 * Correct Fr_FR's message catalogue must have,
1356 * there. But current IBM ode's Makefile cannot do this. Instead put
1357 * fr_FR.ISO-8859-1. ( That is "do nothing" ).
1358 * To fix this, dthelpgen converts the current IBM LANG to CDE
1359 * standard name with _DtLcx*() function provided by libDtHelp.a as
1364 _DtXlateDb db = NULL;
1366 char plat[_DtPLATFORM_MAX_LEN];
1369 char *ret_stdLocale;
1370 char *ret_stdLangTerr;
1371 char *ret_stdCodeset;
1372 char *ret_stdModifier;
1374 ret = _DtLcxOpenAllDbs( &db );
1376 ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
1378 ret = _DtLcxXlateOpToStd( db, plat, execver,
1379 DtLCX_OPER_SETLOCALE,
1380 setlocale( LC_MESSAGES, NULL ),
1381 &ret_stdLocale, &ret_stdLangTerr,
1382 &ret_stdCodeset, &ret_stdModifier );
1384 charSet = strdup( ret_stdLocale );
1386 charSet = "C.ISO-8859-1";
1389 charSet = "C.ISO-8859-1";
1391 ret = _DtLcxCloseDb( &db );
1393 charSet = "C.ISO-8859-1";
1398 charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
1400 topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
1402 fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
1403 charSet, topicTitle);
1405 fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
1408 preamble = ftell (outHeader);
1409 fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
1412 * loop through the directories looking for all the unique families
1413 * and -all- the volumes.
1415 fprintf (outVolume, "!# Last modification time stamp per directory\n");
1417 while (next != NULL && *next != NULL)
1419 ScanDirectory(*next, &modTime);
1420 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1424 while (next != NULL && *next != NULL)
1426 ScanDirectory(*next, &modTime);
1427 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1432 while (next != NULL && *next != NULL)
1434 ScanDirectory(*next, &modTime);
1435 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1439 while (next != NULL && *next != NULL)
1441 ScanDirectory(*next, &modTime);
1442 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1446 fprintf (outVolume, "*.charSet: %s\n", charSet);
1448 fprintf (outVolume, "\n!# Topic filenames and offsets\n");
1451 * Now create families.
1455 for (next = FullFamilyName; next != NULL && *next != NULL; next++)
1457 result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
1464 else if (result == -2)
1468 if (foundFamily == 0)
1470 GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
1471 else if (foundVolumes == 0)
1473 GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
1478 if (FamilyList != NULL)
1479 _DtHelpCeFreeStringArray(FamilyList);
1480 if (FullFamilyName != NULL)
1481 _DtHelpCeFreeStringArray(FullFamilyName);
1482 if (VolumeList != NULL)
1483 _DtHelpCeFreeStringArray(VolumeList);
1484 if (FullVolName != NULL)
1485 _DtHelpCeFreeStringArray(FullVolName);
1488 * If no family or volume files were found,
1489 * write out the alternative preamble
1491 if (foundFamily == 0 || foundVolumes == 0)
1493 fseek (outHeader, preamble, 0);
1494 fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
1498 * write the ending message and finish the topic.
1500 fprintf (outHeader, "</TOPIC>\n");
1503 * write out the volume resouces
1505 fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
1506 fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
1507 fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
1509 fprintf (outVolume, "\n\n!# Volume Title\n");
1510 fprintf (outVolume, "*.title: %s\n",
1511 GetMessage (2, 4, "Help - Top Level"));
1516 fprintf (outVolume, "\n\n!# Topic Home Location\n");
1517 fprintf (outVolume, "*.topTopic: %s\n", ParentName);
1522 fprintf (outVolume, "\n\n!# Topic Heirarchy\n");
1523 fprintf (outVolume, "*.%s.parent: \n", ParentName);
1524 for (next = TopicList; next && *next; next++)
1525 fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
1530 fprintf (outVolume, "\n\n!# Topic List\n");
1531 fprintf (outVolume, "*.topicList: %s", ParentName);
1533 while (next && *next)
1535 fprintf (outVolume, " \\\n %s", *next);
1538 fprintf (outVolume, "\n");
1541 * The paths used to create this information.
1543 fprintf (outVolume, "\n\n!# Paths Searched\n");
1544 fprintf (outVolume, "*.dirList: ");
1547 while (next != NULL && *next != NULL)
1549 fprintf (outVolume, " \\\n %s", *next);
1553 while (next != NULL && *next != NULL)
1555 fprintf (outVolume, " \\\n %s", *next);
1559 while (next != NULL && *next != NULL)
1561 fprintf (outVolume, " \\\n %s", *next);
1565 while (next != NULL && *next != NULL)
1567 fprintf (outVolume, " \\\n %s", *next);
1570 fprintf (outVolume, "\n");
1573 * close the volumes.
1579 if (TopicList != NULL)
1580 _DtHelpCeFreeStringArray(TopicList);
1582 if (FUserList != NULL)
1583 _DtHelpCeFreeStringArray(FUserList);
1584 if (FSysList != NULL)
1585 _DtHelpCeFreeStringArray(FSysList);
1586 if (VUserList != NULL)
1587 _DtHelpCeFreeStringArray(VUserList);
1588 if (VSysList != NULL)
1589 _DtHelpCeFreeStringArray(VSysList);
1591 _DtHelpCeDestroyCanvas(canvasHandle);
1593 MyExit (0, childPid);