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];
392 char bitmapNameTemp [sizeof(bitmapName)];
398 db = XrmGetFileDatabase (family_name);
404 if (XrmGetResource (db, "Family.Title", "family.title",
405 &resType, &resValue))
407 title = (char *) resValue.addr;
412 if (XrmGetResource (db, "Family.Abstract", "family.abstract",
413 &resType, &resValue))
415 abstract = (char *) resValue.addr;
418 * get the volumes list
420 if (XrmGetResource (db, "Family.Volumes", "family.volumes",
421 &resType, &resValue))
423 list = (char *) resValue.addr;
426 * get the character set
428 if (XrmGetResource (db, "Family.CharSet", "family.charSet",
429 &resType, &resValue))
431 charSet = (char *) resValue.addr;
434 * get the bitmap (optional)
436 if (XrmGetResource (db,
437 "Family.Bitmap", "family.bitmap",
438 &resType, &resValue))
439 bitmap = (char *) resValue.addr;
445 "%s: character set resource missing\n")),
454 "%s: volumes resource missing\n")),
462 (GetMessage (1, 12, "%s: abstract resource missing\n")),
470 (GetMessage (1, 11, "%s: title resource missing\n")),
475 if (title && abstract && list && charSet)
478 * find out the position of the file pointer
480 filepos = ftell (out_topic);
483 * write out the <TOPIC>
485 fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
489 * write out the <TITLE>
491 fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
493 fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
494 fprintf (out_topic, "%s\n", abstract);
495 fprintf (out_topic, "</P>\n");
500 list = _DtHelpCeGetNxtToken(list, &token);
501 if (token && *token != '\0' && *token != '\n' &&
502 CreateVolumeLink (canvas,out_topic, token) == 0)
507 free ((void *) token);
511 } while (list && *list != '\0');
516 sprintf (familyName, "FAMILY%d", FamilyNum);
517 fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
520 * Put the link information in the header file
523 (GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
524 fprintf (out_header, "<LINK 0 %s>\n", familyName);
525 fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
527 fprintf (out_header, "</LINK>\n");
530 * put the abstract information about this
531 * family in the header file
533 if (NULL != bitmap && *bitmap != '/')
535 snprintf(bitmapName, sizeof(bitmapName), "%s", family_name);
536 ptr = strrchr (bitmapName, '/');
541 snprintf(bitmapNameTemp, sizeof(bitmapNameTemp), "%s%s", bitmapName, bitmap);
542 strcpy(bitmapName, bitmapNameTemp);
553 "<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
557 fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
558 fprintf (out_header, "%s\n", abstract);
559 fprintf (out_header, "</P></CHARACTERSET>\n");
562 * put the information in the volume file.
564 fprintf (out_volume, "*.%s.filepos: %ld\n",
565 familyName, filepos);
566 fprintf (out_volume, "*.%s.filename: %s\n",
567 familyName, TopicName);
568 TopicList = (char **) _DtHelpCeAddPtrToArray (
570 strdup (familyName));
575 * rewind back to the original starting position
577 fseek (out_topic, filepos, 0);
580 * didn't find any volumes for this family.
585 XrmDestroyDatabase (db);
591 /*****************************************************************************
592 * Function: CheckFamilyList (name)
594 * See if this family has been seen
596 *****************************************************************************/
598 CheckFamilyList (char *name )
600 char **listPtr = FamilyList;
602 while (listPtr != NULL && *listPtr != NULL)
604 if (strcmp (*listPtr, name) == 0)
612 /*****************************************************************************
613 * Function: AddFamilyToList (name)
615 * add the name to the family list
617 *****************************************************************************/
619 AddFamilyToList (char *name )
622 FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
627 /*****************************************************************************
628 * Function: ScanDirectory
630 * scan a directory looking for family files.
632 *****************************************************************************/
641 char fullName [MAXPATHLEN + 2];
645 struct dirent *pDirent;
648 if (stat(directory, &buf) == -1)
651 *ret_time = buf.st_mtime;
653 pDir = opendir (directory);
657 snprintf(fullName, sizeof(fullName), "%s%s", directory, SlashString);
658 ptr = fullName + strlen (fullName);
661 * skip over the "." and ".." entries.
663 (void) readdir (pDir);
664 (void) readdir (pDir);
665 pDirent = readdir (pDir);
668 ext = GetExtension (pDirent->d_name);
669 if (strcmp (ext, Family_ext) == 0)
671 if (CheckFamilyList (pDirent->d_name) == False)
673 AddFamilyToList (pDirent->d_name);
675 strcpy (ptr, pDirent->d_name);
676 FullFamilyName = (char **) _DtHelpCeAddPtrToArray(
677 (void **)FullFamilyName,
681 else if (strcmp(ext, Ext_Hv) == 0 || strcmp(ext, Ext_Sdl) == 0)
683 strcpy (ptr, pDirent->d_name);
684 VolumeList = (char **) _DtHelpCeAddPtrToArray((void **)VolumeList,
685 strdup(pDirent->d_name));
686 FullVolName = (char **) _DtHelpCeAddPtrToArray((void **)FullVolName,
690 pDirent = readdir (pDir);
697 /*****************************************************************************
700 * Resolves the environment variable for all possible paths.
702 *****************************************************************************/
714 fileExt = GetExtension(filename);
715 if (*fileExt == '\0')
719 while (VolumeList != NULL && VolumeList[i] != NULL)
723 ext = GetExtension(VolumeList[i]);
727 different = strcmp(filename, VolumeList[i]);
731 if (!different && access(FullVolName[i], R_OK) == 0
732 && stat(FullVolName[i], &status) == 0
733 && S_ISDIR(status.st_mode) == 0)
734 return (FullVolName[i]);
742 /*****************************************************************************
743 * Function: ExpandPaths
745 * Resolves the environment variable for all possible paths.
747 *****************************************************************************/
763 searchPath = getenv (env_var);
764 if (searchPath == NULL || *searchPath == '\0')
766 if (default_str == NULL)
769 searchPath = default_str;
772 searchPath = strdup (searchPath);
778 ptr = strchr (src, ':');
783 * check to see if %H is declared. If so, we're going
784 * to have to trim it before saving as the directory path.
787 hPtr = strrchr (src, '%');
796 * check to see if the path needs expanding
798 if (NULL != strchr (src, '%'))
799 pathName = _DtHelpCeExpandPathname (src, NULL, type, NULL, lang,
800 (_DtSubstitutionRec *) NULL, 0);
802 pathName = strdup(src);
806 GetPath (pathName, strip, list);
816 } while (src && *src);
821 /*****************************************************************************
822 * Function: CheckTimeStamps
824 * Check the time stamps on the volume dir to determine if
825 * it needs regenerating.
827 *****************************************************************************/
837 while (*dir_list != NULL)
839 if (stat(*dir_list, &buf) == -1)
842 value = _DtHelpCeGetResourceString(db, *dir_list,
843 "TimeStamp", "timeStamp");
844 timeVal = atol(value);
845 if (timeVal != buf.st_mtime)
854 /*****************************************************************************
855 * Function: CheckInfo
857 * Check the information in the volume to determine if it needs regenerating.
859 *****************************************************************************/
865 char **list1, **list2;
869 db = XrmGetFileDatabase (file);
872 volDirList = _DtHelpCeGetResourceStringArray(db, NULL,
873 "DirList", "dirList");
874 if (volDirList != NULL)
879 while (result == 0 && *list1 != NULL
880 && list2 != NULL && *list2 != NULL)
882 result = strcmp(*list1, *list2);
887 if (list2 != NULL && *list2 != NULL)
891 while (result == 0 && *list1 != NULL
892 && list2 != NULL && *list2 != NULL)
894 result = strcmp(*list1, *list2);
899 if (list2 != NULL && *list2 != NULL)
903 while (result == 0 && *list1 != NULL
904 && list2 != NULL && *list2 != NULL)
906 result = strcmp(*list1, *list2);
911 if (list2 != NULL && *list2 != NULL)
915 while (result == 0 && *list1 != NULL
916 && list2 != NULL && *list2 != NULL)
918 result = strcmp(*list1, *list2);
923 if (*list1 != NULL || (list2 != NULL && *list2 != NULL))
927 result = CheckTimeStamps(db, volDirList);
929 _DtHelpCeFreeStringArray(volDirList);
931 XrmDestroyDatabase(db);
937 /*****************************************************************************
939 *****************************************************************************/
952 char tmpVolume [MAXPATHLEN + 2];
953 char tmpVolumeTemp[sizeof(tmpVolume)];
954 char tmpVolume2 [MAXPATHLEN + 2];
955 char tmpTopic [MAXPATHLEN + 2];
956 char tmpHeader [MAXPATHLEN + 2];
957 char headerName [MAXPATHLEN + 2];
958 char baseName [MAXPATHLEN + 2];
959 char baseNameTemp[sizeof(baseName)];
960 char tempName [MAXPATHLEN + 2];
972 pid_t childPid = (pid_t) -1;
973 CanvasHandle canvasHandle;
975 myName = strrchr (argv[0], '/');
982 * have to do a setlocale here, so that the usage message is in the
985 Lang = getenv ("LANG");
988 * use the default if no lang is specified.
990 if (Lang == NULL || *Lang == '\0')
991 Lang = (char*)C_String;
993 setlocale(LC_ALL, "");
994 _DtEnvControl(DT_ENV_SET);
997 * now process the arguments
999 for (i = 1; i < argc; i++)
1001 if (argv[i][0] == '-')
1003 if (argv[i][1] == 'd' && i + 1 < argc)
1004 App_args.dir = argv[++i];
1005 else if (argv[i][1] == 'f' && i + 1 < argc)
1006 App_args.file = argv[++i];
1007 else if (argv[i][1] == 'g')
1009 else if (argv[i][1] == 'l' && i + 1 < argc)
1010 App_args.lang = argv[++i];
1013 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1019 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1025 * get the language we are working with.
1027 if (App_args.lang != NULL)
1030 * Set the locale! Since the user has specified a (likely)
1031 * different language to do the processing in, we need to
1032 * do a setlocale to work with the new language.
1034 Lang = App_args.lang;
1035 if (setlocale(LC_ALL, Lang) == NULL)
1037 fprintf (stderr, (GetMessage(1, 20,
1038 "%s: Invalid system language specified - %s\n")),
1042 _DtEnvControl(DT_ENV_SET);
1044 Lang = strdup(Lang);
1047 * get the directory to work in
1049 if (NULL == App_args.dir)
1051 fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
1055 if (App_args.dir[0] != '/')
1057 if (getcwd (baseName, MAXPATHLEN) == NULL)
1059 fprintf (stderr, (GetMessage (1, 18,
1060 "%s: Unable to access current working directory - error status number %d\n")),
1064 snprintf(baseNameTemp, sizeof(baseNameTemp), "%s/%s", baseName, App_args.dir);
1065 strcpy(baseName, baseNameTemp);
1068 snprintf(baseName, sizeof(baseName), "%s", App_args.dir);
1071 * make sure the directory exists
1073 ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
1074 (_DtSubstitutionRec *) NULL, 0);
1075 if (ptr == NULL || *ptr == '\0')
1078 (GetMessage (1, 15, "%s: Destination directory missing\n")),
1083 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1084 if (tmpVolume[strlen (tmpVolume) - 1] != '/') {
1085 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, SlashString);
1086 strcpy(tmpVolume, tmpVolumeTemp);
1092 * march down the path, checking that
1094 * 2) the caller has access permission.
1095 * 3) resolve all symbolic links
1097 endDir = strchr (tmpVolume, '/');
1101 endDir = strchr (endDir, '/');
1103 while (endDir && *endDir != '\0')
1106 * remember the rest of the string (including the slash)
1107 * and strip the trailing slash from the directory path.
1109 snprintf(tmpVolume2, sizeof(tmpVolume2), "%s", endDir);
1113 * trace the path and copy the new string into the old buffer.
1115 ptr = _DtHelpCeTracePathName(tmpVolume);
1118 snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
1122 if (access (tmpVolume, F_OK) == -1)
1127 ptr = GetMessage (1, 2, (char*)NotDirectory);
1128 fprintf (stderr, ptr, myName, tmpVolume);
1132 ptr = GetMessage (1, 3, (char*)SuperMsg);
1133 fprintf (stderr, ptr, myName, tmpVolume);
1137 if (mkdir(tmpVolume,
1138 (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) == -1
1139 && errno != EEXIST && errno != EROFS)
1144 ptr = GetMessage(1,2,
1145 (char*)NotDirectory);
1149 ptr = GetMessage(1, 3,
1154 ptr = GetMessage(1, 4,
1155 "%s: Element of %s does not exist\n");
1159 ptr = GetMessage (1, 5,
1160 "%s: File system containing %s is full\n");
1164 ptr = GetMessage(1,6,
1165 (char*)GeneralAccess);
1168 fprintf (stderr, ptr, myName, tmpVolume, errno);
1173 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1174 fprintf (stderr, ptr, myName, tmpVolume, errno);
1180 * point to the end of the string (past where the slash will go)
1182 endDir = tmpVolume + strlen(tmpVolume) + 2;
1185 * append the rest of the directory spec that hasn't been checked.
1187 strcat (tmpVolume, tmpVolume2);
1188 endDir = strchr (endDir, '/');
1193 * get temporary files for the volume and topic file.
1195 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, App_args.file);
1196 strcpy(tmpVolume, tmpVolumeTemp);
1198 (void) strcpy (tmpHeader, tmpVolume);
1199 (void) strcpy (tmpTopic, tmpVolume);
1201 snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, Ext_Hv);
1202 strcpy(tmpVolume, tmpVolumeTemp);
1203 (void) strcat (tmpHeader, "00.ht");
1204 (void) strcat (tmpTopic , "01.ht");
1206 result = access (tmpVolume, F_OK);
1209 * If it exists, make sure the invoker can write to it.
1213 if (access (tmpVolume, W_OK) == -1)
1216 ptr = GetMessage (1, 7,
1217 "%s: File system containing %s is read only\n");
1218 else if (errno == EACCES)
1219 ptr = GetMessage (1, 8,
1220 "%s: Requires root permission to write to %s\n");
1222 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1224 fprintf (stderr, ptr, myName, tmpVolume, errno);
1228 else if (result == -1 && errno != ENOENT)
1230 ptr = GetMessage (1, 6, (char*)GeneralAccess);
1231 fprintf (stderr, ptr, myName, tmpVolume, errno);
1234 else /* file does not exist */
1239 * Find out if we have any paths to check.
1241 ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
1242 ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
1243 ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
1244 DtDEFAULT_SYSTEM_PATH, &FSysList);
1245 ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
1246 DtDEFAULT_SYSTEM_PATH, &VSysList);
1247 if (((FUserList == NULL || *FUserList == NULL) &&
1248 (FSysList == NULL || *FSysList == NULL)) ||
1249 ((VUserList == NULL || *VUserList == NULL) &&
1250 (VSysList == NULL || *VSysList == NULL)))
1252 ptr = GetMessage (1, 10, "%s: Search Path empty\n");
1253 fprintf (stderr, ptr, myName);
1258 * If we already haven't determined that the volume needs (re)generating
1259 * check the info squirreled away in the old volume.
1262 doGen = CheckInfo(tmpVolume);
1265 * the volume doesn't need (re)generating.
1272 * create a canvas for the functions.
1274 canvasHandle = _DtHelpCeCreateDefCanvas();
1275 if (canvasHandle == NULL)
1277 fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
1283 * open the individual files that will hold the browser information.
1286 outVolume = fopen (tmpVolume, "w");
1287 if (outVolume == NULL)
1289 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1290 fprintf (stderr, ptr, myName, tmpVolume, errno);
1291 _DtHelpCeDestroyCanvas(canvasHandle);
1298 outTopic = fopen (tmpTopic, "w");
1299 if (outTopic == NULL)
1301 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1302 fprintf (stderr, ptr, myName, tmpTopic, errno);
1303 (void) unlink (tmpVolume);
1304 _DtHelpCeDestroyCanvas(canvasHandle);
1311 outHeader = fopen (tmpHeader, "w");
1312 if (outHeader == NULL)
1314 ptr = GetMessage (1, 9, (char*)WriteInvalid);
1315 fprintf (stderr, ptr, myName, tmpHeader, errno);
1316 (void) unlink (tmpVolume);
1317 (void) unlink (tmpTopic);
1318 _DtHelpCeDestroyCanvas(canvasHandle);
1323 * fork off the dtksh script that will put up a dialog
1324 * telling the user that we're building help browser
1333 * if this is the child, exec the dthelpgen.ds script.
1337 execlp("dthelpgen.ds", "dthelpgen.ds",
1338 ((char *) 0), ((char *) 0), ((char *) 0));
1343 * initialize the main topic
1345 strcpy (TopicName, App_args.file);
1346 strcat (TopicName, "01.ht");
1348 strcpy (headerName, App_args.file);
1349 strcat (headerName, "00.ht");
1352 * The original dthelpgen extracts the CDE Standard name from
1353 * its message catalogue( set 2/msg 1 ).
1354 * But on IBM ODE, this is a problem. For example,
1355 * fr_FR's dthelpgen.cat has
1356 * fr_FR.ISO-8859-1 in set 2/msg 1.
1357 * Correct Fr_FR's message catalogue must have,
1359 * there. But current IBM ode's Makefile cannot do this. Instead put
1360 * fr_FR.ISO-8859-1. ( That is "do nothing" ).
1361 * To fix this, dthelpgen converts the current IBM LANG to CDE
1362 * standard name with _DtLcx*() function provided by libDtHelp.a as
1367 _DtXlateDb db = NULL;
1369 char plat[_DtPLATFORM_MAX_LEN];
1372 char *ret_stdLocale;
1373 char *ret_stdLangTerr;
1374 char *ret_stdCodeset;
1375 char *ret_stdModifier;
1377 ret = _DtLcxOpenAllDbs( &db );
1379 ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
1381 ret = _DtLcxXlateOpToStd( db, plat, execver,
1382 DtLCX_OPER_SETLOCALE,
1383 setlocale( LC_MESSAGES, NULL ),
1384 &ret_stdLocale, &ret_stdLangTerr,
1385 &ret_stdCodeset, &ret_stdModifier );
1387 charSet = strdup( ret_stdLocale );
1389 charSet = "C.ISO-8859-1";
1392 charSet = "C.ISO-8859-1";
1394 ret = _DtLcxCloseDb( &db );
1396 charSet = "C.ISO-8859-1";
1401 charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
1403 topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
1405 fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
1406 charSet, topicTitle);
1408 fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
1411 preamble = ftell (outHeader);
1412 fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
1415 * loop through the directories looking for all the unique families
1416 * and -all- the volumes.
1418 fprintf (outVolume, "!# Last modification time stamp per directory\n");
1420 while (next != NULL && *next != NULL)
1422 ScanDirectory(*next, &modTime);
1423 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1427 while (next != NULL && *next != NULL)
1429 ScanDirectory(*next, &modTime);
1430 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 while (next != NULL && *next != NULL)
1444 ScanDirectory(*next, &modTime);
1445 fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
1449 fprintf (outVolume, "*.charSet: %s\n", charSet);
1451 fprintf (outVolume, "\n!# Topic filenames and offsets\n");
1454 * Now create families.
1458 for (next = FullFamilyName; next != NULL && *next != NULL; next++)
1460 result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
1467 else if (result == -2)
1471 if (foundFamily == 0)
1473 GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
1474 else if (foundVolumes == 0)
1476 GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
1481 if (FamilyList != NULL)
1482 _DtHelpCeFreeStringArray(FamilyList);
1483 if (FullFamilyName != NULL)
1484 _DtHelpCeFreeStringArray(FullFamilyName);
1485 if (VolumeList != NULL)
1486 _DtHelpCeFreeStringArray(VolumeList);
1487 if (FullVolName != NULL)
1488 _DtHelpCeFreeStringArray(FullVolName);
1491 * If no family or volume files were found,
1492 * write out the alternative preamble
1494 if (foundFamily == 0 || foundVolumes == 0)
1496 fseek (outHeader, preamble, 0);
1497 fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
1501 * write the ending message and finish the topic.
1503 fprintf (outHeader, "</TOPIC>\n");
1506 * write out the volume resouces
1508 fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
1509 fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
1510 fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
1512 fprintf (outVolume, "\n\n!# Volume Title\n");
1513 fprintf (outVolume, "*.title: %s\n",
1514 GetMessage (2, 4, "Help - Top Level"));
1519 fprintf (outVolume, "\n\n!# Topic Home Location\n");
1520 fprintf (outVolume, "*.topTopic: %s\n", ParentName);
1525 fprintf (outVolume, "\n\n!# Topic Heirarchy\n");
1526 fprintf (outVolume, "*.%s.parent: \n", ParentName);
1527 for (next = TopicList; next && *next; next++)
1528 fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
1533 fprintf (outVolume, "\n\n!# Topic List\n");
1534 fprintf (outVolume, "*.topicList: %s", ParentName);
1536 while (next && *next)
1538 fprintf (outVolume, " \\\n %s", *next);
1541 fprintf (outVolume, "\n");
1544 * The paths used to create this information.
1546 fprintf (outVolume, "\n\n!# Paths Searched\n");
1547 fprintf (outVolume, "*.dirList: ");
1550 while (next != NULL && *next != NULL)
1552 fprintf (outVolume, " \\\n %s", *next);
1556 while (next != NULL && *next != NULL)
1558 fprintf (outVolume, " \\\n %s", *next);
1562 while (next != NULL && *next != NULL)
1564 fprintf (outVolume, " \\\n %s", *next);
1568 while (next != NULL && *next != NULL)
1570 fprintf (outVolume, " \\\n %s", *next);
1573 fprintf (outVolume, "\n");
1576 * close the volumes.
1582 if (TopicList != NULL)
1583 _DtHelpCeFreeStringArray(TopicList);
1585 if (FUserList != NULL)
1586 _DtHelpCeFreeStringArray(FUserList);
1587 if (FSysList != NULL)
1588 _DtHelpCeFreeStringArray(FSysList);
1589 if (VUserList != NULL)
1590 _DtHelpCeFreeStringArray(VUserList);
1591 if (VSysList != NULL)
1592 _DtHelpCeFreeStringArray(VSysList);
1594 _DtHelpCeDestroyCanvas(canvasHandle);
1596 MyExit (0, childPid);