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 librararies 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 *filename = NULL;
309 char *pathName = NULL;
310 VolumeHandle volume = NULL;
312 pathName = FindFile (volume_name);
313 if (pathName != NULL && _DtHelpCeOpenVolume(canvas,pathName,&volume) == 0)
315 if (_DtHelpCeGetVolumeTitle (canvas, volume, &title) == 0)
317 else if (_DtHelpCeGetTopicTitle(canvas,volume,(char*)TopLocId,&title)
323 if (_DtHelpCeGetAsciiVolumeAbstract(canvas,volume,&abstract) == -1)
326 charSet = _DtHelpCeGetVolumeLocale(volume);
328 charSet = (char *) DefCharSet;
330 _DtHelpCeCloseVolume (canvas, volume);
335 fprintf (outTopic, (GetMessage(3, 4, "<CHARACTERSET %s>\n")), charSet);
336 fprintf (outTopic,"<LINK 0 \"%s %s\">\n", volume_name, (char*)TopLocId);
337 fprintf (outTopic, (GetMessage(3, 5, (char*)defaultTitle12)), title);
338 fprintf (outTopic, "</LINK>\n");
341 * put the abstract information about this
342 * family in the header file
344 fprintf (outTopic, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
346 if (abstract != NULL)
348 fprintf (outTopic, (GetMessage (3, 4, "<CHARACTERSET %s>\n")),
350 fprintf (outTopic, "%s\n", abstract);
351 fprintf (outTopic, "</CHARACTERSET>\n");
354 fprintf (outTopic, "</P>\n</CHARACTERSET>\n");
357 if (charSet != DefCharSet)
361 free ((void *) title);
363 free ((void *) filename);
368 /*****************************************************************************
369 * Function: CreateFamily
371 *****************************************************************************/
383 char *charSet = NULL;
385 char *abstract = NULL;
390 char familyName [20]; /* FAMILY%d */
391 char bitmapName [MAXPATHLEN + 2];
397 db = XrmGetFileDatabase (family_name);
403 if (XrmGetResource (db, "Family.Title", "family.title",
404 &resType, &resValue))
406 title = (char *) resValue.addr;
411 if (XrmGetResource (db, "Family.Abstract", "family.abstract",
412 &resType, &resValue))
414 abstract = (char *) resValue.addr;
417 * get the volumes list
419 if (XrmGetResource (db, "Family.Volumes", "family.volumes",
420 &resType, &resValue))
422 list = (char *) resValue.addr;
425 * get the character set
427 if (XrmGetResource (db, "Family.CharSet", "family.charSet",
428 &resType, &resValue))
430 charSet = (char *) resValue.addr;
433 * get the bitmap (optional)
435 if (XrmGetResource (db,
436 "Family.Bitmap", "family.bitmap",
437 &resType, &resValue))
438 bitmap = (char *) resValue.addr;
444 "%s: character set resource missing\n")),
453 "%s: volumes resource missing\n")),
461 (GetMessage (1, 12, "%s: abstract resource missing\n")),
469 (GetMessage (1, 11, "%s: title resource missing\n")),
474 if (title && abstract && list && charSet)
477 * find out the position of the file pointer
479 filepos = ftell (out_topic);
482 * write out the <TOPIC>
484 fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
488 * write out the <TITLE>
490 fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
492 fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
493 fprintf (out_topic, "%s\n", abstract);
494 fprintf (out_topic, "</P>\n");
499 list = _DtHelpCeGetNxtToken(list, &token);
500 if (token && *token != '\0' && *token != '\n' &&
501 CreateVolumeLink (canvas,out_topic, token) == 0)
504 if (token && *token != '\0' && *token != '\n')
505 free ((void *) token);
507 } while (list && *list != '\0');
512 sprintf (familyName, "FAMILY%d", FamilyNum);
513 fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
516 * Put the link information in the header file
519 (GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
520 fprintf (out_header, "<LINK 0 %s>\n", familyName);
521 fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
523 fprintf (out_header, "</LINK>\n");
526 * put the abstract information about this
527 * family in the header file
529 if (NULL != bitmap && *bitmap != '/')
531 strcpy (bitmapName, family_name);
532 ptr = strrchr (bitmapName, '/');
537 strcat (bitmapName, bitmap);
548 "<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
552 fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
553 fprintf (out_header, "%s\n", abstract);
554 fprintf (out_header, "</P></CHARACTERSET>\n");
557 * put the information in the volume file.
559 fprintf (out_volume, "*.%s.filepos: %ld\n",
560 familyName, filepos);
561 fprintf (out_volume, "*.%s.filename: %s\n",
562 familyName, TopicName);
563 TopicList = (char **) _DtHelpCeAddPtrToArray (
565 strdup (familyName));
570 * rewind back to the original starting position
572 fseek (out_topic, filepos, 0);
575 * didn't find any volumes for this family.
580 XrmDestroyDatabase (db);
587 /*****************************************************************************
588 * Function: CheckFamilyList (name)
590 * See if this family has been seen
592 *****************************************************************************/
594 CheckFamilyList (char *name )
596 char **listPtr = FamilyList;
598 while (listPtr != NULL && *listPtr != NULL)
600 if (strcmp (*listPtr, name) == 0)
608 /*****************************************************************************
609 * Function: AddFamilyToList (name)
611 * add the name to the family list
613 *****************************************************************************/
615 AddFamilyToList (char *name )
618 FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
623 /*****************************************************************************
624 * Function: ScanDirectory
626 * scan a directory looking for family files.
628 *****************************************************************************/
637 char fullName [MAXPATHLEN + 2];
641 struct dirent *pDirent;
644 if (stat(directory, &buf) == -1)
647 *ret_time = buf.st_mtime;
649 pDir = opendir (directory);
653 strcpy (fullName, directory);
654 strcat (fullName, 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 tmpVolume2 [MAXPATHLEN + 2];
951 char tmpTopic [MAXPATHLEN + 2];
952 char tmpHeader [MAXPATHLEN + 2];
953 char headerName [MAXPATHLEN + 2];
954 char baseName [MAXPATHLEN + 2];
955 char tempName [MAXPATHLEN + 2];
967 pid_t childPid = (pid_t) -1;
968 CanvasHandle canvasHandle;
970 myName = strrchr (argv[0], '/');
977 * have to do a setlocale here, so that the usage message is in the
980 Lang = getenv ("LANG");
983 * use the default if no lang is specified.
985 if (Lang == NULL || *Lang == '\0')
986 Lang = (char*)C_String;
988 setlocale(LC_ALL, "");
989 _DtEnvControl(DT_ENV_SET);
992 * now process the arguments
994 for (i = 1; i < argc; i++)
996 if (argv[i][0] == '-')
998 if (argv[i][1] == 'd' && i + 1 < argc)
999 App_args.dir = argv[++i];
1000 else if (argv[i][1] == 'f' && i + 1 < argc)
1001 App_args.file = argv[++i];
1002 else if (argv[i][1] == 'g')
1004 else if (argv[i][1] == 'l' && i + 1 < argc)
1005 App_args.lang = argv[++i];
1008 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1014 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1020 * get the language we are working with.
1022 if (App_args.lang != NULL)
1025 * Set the locale! Since the user has specified a (likely)
1026 * different language to do the processing in, we need to
1027 * do a setlocale to work with the new language.
1029 Lang = App_args.lang;
1030 if (setlocale(LC_ALL, Lang) == NULL)
1032 fprintf (stderr, (GetMessage(1, 20,
1033 "%s: Invalid system language specified - %s\n")),
1037 _DtEnvControl(DT_ENV_SET);
1039 Lang = strdup(Lang);
1042 * get the directory to work in
1044 if (NULL == App_args.dir)
1046 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1050 if (App_args.dir[0] != '/')
1052 if (getcwd (baseName, MAXPATHLEN) == NULL)
1054 fprintf (stderr, (GetMessage (1, 18,
1055 "%s: Unable to access current working directory - error status number %d\n")),
1059 strcat (baseName, "/");
1060 strcat (baseName, App_args.dir);
1063 strcpy (baseName, App_args.dir);
1066 * make sure the directory exists
1068 ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
1069 (_DtSubstitutionRec *) NULL, 0);
1070 if (ptr == NULL || *ptr == '\0')
1073 (GetMessage (1, 15, "%s: Destination directory missing\n")),
1078 (void) strcpy (tmpVolume, ptr);
1079 if (tmpVolume[strlen (tmpVolume) - 1] != '/')
1080 strcat(tmpVolume, SlashString);
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 strcpy (tmpVolume2, endDir);
1106 * trace the path and copy the new string into the old buffer.
1108 ptr = _DtHelpCeTracePathName(tmpVolume);
1111 strcpy (tmpVolume, 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 (void) strcat (tmpVolume, App_args.file);
1190 (void) strcpy (tmpHeader, tmpVolume);
1191 (void) strcpy (tmpTopic, tmpVolume);
1193 (void) strcat (tmpVolume, Ext_Hv);
1194 (void) strcat (tmpHeader, "00.ht");
1195 (void) strcat (tmpTopic , "01.ht");
1197 result = access (tmpVolume, F_OK);
1200 * If it exists, make sure the invoker can write to it.
1204 if (access (tmpVolume, W_OK) == -1)
1207 ptr = GetMessage (1, 7,
1208 "%s: File system containing %s is read only\n");
1209 else if (errno == EACCES)
1210 ptr = GetMessage (1, 8,
1211 "%s: Requires root permission to write to %s\n");
1213 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1215 fprintf (stderr, ptr, myName, tmpVolume, errno);
1219 else if (result == -1 && errno != ENOENT)
1221 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1222 fprintf (stderr, ptr, myName, tmpVolume, errno);
1225 else /* file does not exist */
1230 * Find out if we have any paths to check.
1232 ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
1233 ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
1234 ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
1235 DtDEFAULT_SYSTEM_PATH, &FSysList);
1236 ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
1237 DtDEFAULT_SYSTEM_PATH, &VSysList);
1238 if (((FUserList == NULL || *FUserList == NULL) &&
1239 (FSysList == NULL || *FSysList == NULL)) ||
1240 ((VUserList == NULL || *VUserList == NULL) &&
1241 (VSysList == NULL || *VSysList == NULL)))
1243 ptr = GetMessage (1, 10, "%s: Search Path empty\n");
1244 fprintf (stderr, ptr, myName);
1249 * If we already haven't determined that the volume needs (re)generating
1250 * check the info squirreled away in the old volume.
1253 doGen = CheckInfo(tmpVolume);
1256 * the volume doesn't need (re)generating.
1263 * create a canvas for the functions.
1265 canvasHandle = _DtHelpCeCreateDefCanvas();
1266 if (canvasHandle == NULL)
1268 fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
1274 * open the individual files that will hold the browser information.
1277 outVolume = fopen (tmpVolume, "w");
1278 if (outVolume == NULL)
1280 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1281 fprintf (stderr, ptr, myName, tmpVolume, errno);
1282 _DtHelpCeDestroyCanvas(canvasHandle);
1289 outTopic = fopen (tmpTopic, "w");
1290 if (outTopic == NULL)
1292 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1293 fprintf (stderr, ptr, myName, tmpTopic, errno);
1294 (void) unlink (tmpVolume);
1295 _DtHelpCeDestroyCanvas(canvasHandle);
1302 outHeader = fopen (tmpHeader, "w");
1303 if (outHeader == NULL)
1305 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1306 fprintf (stderr, ptr, myName, tmpHeader, errno);
1307 (void) unlink (tmpVolume);
1308 (void) unlink (tmpTopic);
1309 _DtHelpCeDestroyCanvas(canvasHandle);
1314 * fork off the dtksh script that will put up a dialog
1315 * telling the user that we're building help browser
1324 * if this is the child, exec the dthelpgen.ds script.
1328 execlp("dthelpgen.ds", "dthelpgen.ds",
1329 ((char *) 0), ((char *) 0), ((char *) 0));
1334 * initialize the main topic
1336 strcpy (TopicName, App_args.file);
1337 strcat (TopicName, "01.ht");
1339 strcpy (headerName, App_args.file);
1340 strcat (headerName, "00.ht");
1343 * The original dthelpgen extracts the CDE Standard name from
1344 * its message catalogue( set 2/msg 1 ).
1345 * But on IBM ODE, this is a problem. For example,
1346 * fr_FR's dthelpgen.cat has
1347 * fr_FR.ISO-8859-1 in set 2/msg 1.
1348 * Correct Fr_FR's message catalogue must have,
1350 * there. But current IBM ode's Makefile cannot do this. Instead put
1351 * fr_FR.ISO-8859-1. ( That is "do nothing" ).
1352 * To fix this, dthelpgen converts the current IBM LANG to CDE
1353 * standard name with _DtLcx*() function provided by libDtHelp.a as
1358 _DtXlateDb db = NULL;
1360 char plat[_DtPLATFORM_MAX_LEN];
1363 char *ret_stdLocale;
1364 char *ret_stdLangTerr;
1365 char *ret_stdCodeset;
1366 char *ret_stdModifier;
1368 ret = _DtLcxOpenAllDbs( &db );
1370 ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
1372 ret = _DtLcxXlateOpToStd( db, plat, execver,
1373 DtLCX_OPER_SETLOCALE,
1374 setlocale( LC_MESSAGES, NULL ),
1375 &ret_stdLocale, &ret_stdLangTerr,
1376 &ret_stdCodeset, &ret_stdModifier );
1378 charSet = strdup( ret_stdLocale );
1380 charSet = "C.ISO-8859-1";
1383 charSet = "C.ISO-8859-1";
1385 ret = _DtLcxCloseDb( &db );
1387 charSet = "C.ISO-8859-1";
1392 charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
1394 topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
1396 fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
1397 charSet, topicTitle);
1399 fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
1402 preamble = ftell (outHeader);
1403 fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
1406 * loop through the directories looking for all the unique families
1407 * and -all- the volumes.
1409 fprintf (outVolume, "!# Last modification time stamp per directory\n");
1411 while (next != NULL && *next != NULL)
1413 ScanDirectory(*next, &modTime);
1414 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1418 while (next != NULL && *next != NULL)
1420 ScanDirectory(*next, &modTime);
1421 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1426 while (next != NULL && *next != NULL)
1428 ScanDirectory(*next, &modTime);
1429 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1433 while (next != NULL && *next != NULL)
1435 ScanDirectory(*next, &modTime);
1436 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1440 fprintf (outVolume, "*.charSet: %s\n", charSet);
1442 fprintf (outVolume, "\n!# Topic filenames and offsets\n");
1445 * Now create families.
1449 for (next = FullFamilyName; next != NULL && *next != NULL; next++)
1451 result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
1458 else if (result == -2)
1462 if (foundFamily == 0)
1464 GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
1465 else if (foundVolumes == 0)
1467 GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
1472 if (FamilyList != NULL)
1473 _DtHelpCeFreeStringArray(FamilyList);
1474 if (FullFamilyName != NULL)
1475 _DtHelpCeFreeStringArray(FullFamilyName);
1476 if (VolumeList != NULL)
1477 _DtHelpCeFreeStringArray(VolumeList);
1478 if (FullVolName != NULL)
1479 _DtHelpCeFreeStringArray(FullVolName);
1482 * If no family or volume files were found,
1483 * write out the alternative preamble
1485 if (foundFamily == 0 || foundVolumes == 0)
1487 fseek (outHeader, preamble, 0);
1488 fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
1492 * write the ending message and finish the topic.
1494 fprintf (outHeader, "</TOPIC>\n");
1497 * write out the volume resouces
1499 fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
1500 fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
1501 fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
1503 fprintf (outVolume, "\n\n!# Volume Title\n");
1504 fprintf (outVolume, "*.title: %s\n",
1505 GetMessage (2, 4, "Help - Top Level"));
1510 fprintf (outVolume, "\n\n!# Topic Home Location\n");
1511 fprintf (outVolume, "*.topTopic: %s\n", ParentName);
1516 fprintf (outVolume, "\n\n!# Topic Heirarchy\n");
1517 fprintf (outVolume, "*.%s.parent: \n", ParentName);
1518 for (next = TopicList; next && *next; next++)
1519 fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
1524 fprintf (outVolume, "\n\n!# Topic List\n");
1525 fprintf (outVolume, "*.topicList: %s", ParentName);
1527 while (next && *next)
1529 fprintf (outVolume, " \\\n %s", *next);
1532 fprintf (outVolume, "\n");
1535 * The paths used to create this information.
1537 fprintf (outVolume, "\n\n!# Paths Searched\n");
1538 fprintf (outVolume, "*.dirList: ");
1541 while (next != NULL && *next != NULL)
1543 fprintf (outVolume, " \\\n %s", *next);
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);
1564 fprintf (outVolume, "\n");
1567 * close the volumes.
1573 if (TopicList != NULL)
1574 _DtHelpCeFreeStringArray(TopicList);
1576 if (FUserList != NULL)
1577 _DtHelpCeFreeStringArray(FUserList);
1578 if (FSysList != NULL)
1579 _DtHelpCeFreeStringArray(FSysList);
1580 if (VUserList != NULL)
1581 _DtHelpCeFreeStringArray(VUserList);
1582 if (VSysList != NULL)
1583 _DtHelpCeFreeStringArray(VSysList);
1585 _DtHelpCeDestroyCanvas(canvasHandle);
1587 MyExit (0, childPid);