1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/programs/dthelp/dthelpgen/helpgen.c
Jon Trulson 137bbf383e dthelp: get parts of it building.
This was a patch from Peter G, though modified a bit regarding the
LDADDs the way we do them now.
2020-03-23 13:51:01 -06:00

1590 lines
40 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: helpgen.c /main/8 1998/04/20 12:52:36 mgreess $ */
#include <dirent.h>
#include <errno.h>
#include <locale.h>
#include <nl_types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <X11/Intrinsic.h>
#include <Dt/Help.h>
#include <Dt/EnvControlP.h>
#include "Dt/HelpP.h" /* in DtHelp library */
#include "GenUtilsP.h" /* in DtHelp library */
#include "ObsoleteP.h" /* in DtHelp library */
#include "DtI/bufioI.h" /* for AccessI.h */
#include "DtI/Access.h" /* in DtHelp library */
#include "DtI/AccessP.h" /* in DtHelp library */
#include "DtI/AccessI.h" /* in DtHelp library */
#include "AccessCCDFI.h" /* in DtHelp library */
#include "StringFuncsI.h" /* in DtHelp library */
#ifdef _AIX
#include <LocaleXlate.h>
#endif
#ifndef NL_CAT_LOCALE
static const int NL_CAT_LOCALE = 0;
#endif
#ifndef CDE_INSTALLATION_TOP
#define CDE_INSTALLATION_TOP "/usr/dt"
#endif
#ifndef CDE_CONFIGURATION_TOP
#define CDE_CONFIGURATION_TOP "/etc/dt"
#endif
#ifndef DtSYS_FILE_SEARCH_ENV
#define DtSYS_FILE_SEARCH_ENV "DTHELPSEARCHPATH"
#endif
#ifndef DtUSER_FILE_SEARCH_ENV
#define DtUSER_FILE_SEARCH_ENV "DTHELPUSERSEARCHPATH"
#endif
/*****************************************************************************
* defines
*****************************************************************************/
#define VOLUME_EXT ".hv"
#define FAMILY_EXT ".hf"
/*****************************************************************************
* static strings.
*****************************************************************************/
static const char *ShellCmd = "sh";
static const char *UsageStr =
"%s -dir <directory> [-generate] [-file <name>] [-lang <language>]\n";
static const char *TopLocId = "_hometopic";
static const char *SlashString = "/";
static const char *C_String = "C";
static const char *DefCharSet = "C.ISO-8859-1";
static const char *Family_ext = FAMILY_EXT;
static const char *Ext_Hv = ".hv";
static const char *Ext_Sdl = ".sdl";
static const char *SuperMsg =
"%s: Access denied for directory %s\nTry running as super user?\n";
static const char *GeneralAccess =
"%s: Unable to access %s - error status number %d\n";
static const char *NotDirectory = "%s: Element of %s is not a directory\n";
static const char *WriteInvalid = "%s: Write to %s invalid\n";
static const char *defaultTopic = "<TOPIC charset %s>\n";
static const char *defaultTitle12 =
"<TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic>\n%s\n</ANGLE></SIZE></WEIGHT></TYPE>\n";
static const char *defaultTitle14 =
"<TITLE><TYPE serif><WEIGHT bold><SIZE 14>\n%s\n</SIZE></WEIGHT></TYPE></TITLE>\n";
static const char *defaultTextBody =
"<ABBREV>Welcome to the Help Manager</ABBREV> \n\
<PARAGRAPH>Each of the titles listed below represents a <ANGLE italic> \n\
product family</> that has installed and registered its online help. Each \n\
title (and icon) is a hyperlink that lists the help within the family.</> \n\
<PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">To \n\
display a list of the help available for a product family, choose its \n\
title (underlined text) or icon.</PARAGRAPH> \n\
<PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">\n\
Within a product \n\
family, find the help you want to view, then choose its title.</PARAGRAPH> \n\
<PARAGRAPH first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\"> \n\
If you need help while using help windows, press F1.</PARAGRAPH>";
static const char *defaultAlternate =
"<ABBREV>Welcome to the Help Manager</ABBREV> \n\
<LINK 0 \"Help4Help How-To-Register-Help\"> \n\
<TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic> \n\
Note:\\ \\ \\ No Help Registered</SIZE></WEIGHT></TYPE></></LINK> \n\
<PARAGRAPH leftindent 3 firstindent 3> \n\
<WEIGHT bold>No product families have registered their online help \n\
files for browsing.</> Help may be available for some applications by \n\
choosing Help commands directly within the applications.</>";
/*****************************************************************************
* global variables.
*****************************************************************************/
char *myName;
char *Lang = NULL;
char *ParentName = "_HOMETOPIC";
char **TopicList = NULL;
/* The family search list */
char **FUserList = NULL;
char **FSysList = NULL;
/* The volume search list */
char **VUserList = NULL;
char **VSysList = NULL;
char **FamilyList = NULL; /* the names of the unique families */
char **FullFamilyName = NULL; /* the fully qualified family names */
char **VolumeList = NULL; /* the names (only) of volume */
char **FullVolName = NULL; /* the fully qualified volume names */
char TopicName [MAXPATHLEN + 2];
int FamilyNum = 0;
/* Global Message Catalog file names */
/*****************************************************************************
* Private Function Declarations
*****************************************************************************/
extern char *FindFile (char *filename);
/*****************************************************************************
* options and resources
*****************************************************************************/
typedef struct
{
char *dir;
char *file;
char *lang;
} ApplicationArgs, *ApplicationArgsPtr;
static ApplicationArgs App_args =
{
NULL,
"browser",
NULL,
};
/*****************************************************************************
* void MyExit(exit_val, pid)
*****************************************************************************/
void
MyExit (
int exit_val,
pid_t pid)
{
if (pid != ((pid_t) -1))
(void) kill(pid, SIGKILL);
exit (exit_val);
}
/*****************************************************************************
* char *GetMessage(set, n, s)
*****************************************************************************/
char *
GetMessage (
int set,
int n,
char *s)
{
char *msg;
char *lang;
char *catFileName=NULL;
static nl_catd nlmsg_fd;
static int first = 1;
if ( first )
{
/* Setup our default message catalog names if none have been set! */
/* Setup the short and long versions */
catFileName = "dthelpgen";
first = 0;
if (strcmp (Lang, "C") == 0)
/*
* If LANG is not set or if LANG=C, then there
* is no need to open the message catalog - just
* return the built-in string "s".
*/
nlmsg_fd = (nl_catd) -1;
else
nlmsg_fd = catopen(catFileName, NL_CAT_LOCALE);
}
msg=catgets(nlmsg_fd,set,n,s);
return (msg);
}
/*****************************************************************************
* Boolean *GetPath(filename)
*****************************************************************************/
Boolean
GetPath (char *filename, short strip, char ***list )
{
char *ptr;
char **next = *list;
if (strip)
{
ptr = strrchr (filename, '/');
if (ptr)
*ptr = '\0';
else
filename = "./";
}
while (next != NULL && *next != NULL && strcmp (*next, filename))
next++;
if (next == NULL || *next == NULL)
*list = (char **) _DtHelpCeAddPtrToArray ((void **) (*list),
strdup(filename));
return False;
}
/*****************************************************************************
* char *GetExtension(filename)
* char *filename - name of file to get the extension from.
* return a pointer to the extension of the file name
*****************************************************************************/
char *
GetExtension(char *filename )
{
char *ext;
/*
* WARNING...
* need multi-byte functionality here
*/
ext = strrchr(filename, '.');
if (ext)
return(ext); /* safe because ext not in middle of character */
return(""); /* never returns NULL */
}
/*****************************************************************************
* Function: CreateVolumeLink
*
* outTopic the output stream.
* volume_name Searches for a volume by this name.
*
* Reads a volume database and creates a label paragraph entry.
*
*****************************************************************************/
int
CreateVolumeLink (
CanvasHandle canvas,
FILE *outTopic,
char *volume_name )
{
int result = -1;
char *title = NULL;
char *charSet = (char *) DefCharSet;
char *abstract = NULL;
char *pathName = NULL;
VolumeHandle volume = NULL;
pathName = FindFile (volume_name);
if (pathName != NULL && _DtHelpCeOpenVolume(canvas,pathName,&volume) == 0)
{
if (_DtHelpCeGetVolumeTitle (canvas, volume, &title) == 0)
result = 0;
else if (_DtHelpCeGetTopicTitle(canvas,volume,(char*)TopLocId,&title)
== True)
result = 0;
if (result == 0)
{
if (_DtHelpCeGetAsciiVolumeAbstract(canvas,volume,&abstract) == -1)
abstract = NULL;
charSet = _DtHelpCeGetVolumeLocale(volume);
if (charSet == NULL)
charSet = (char *) DefCharSet;
}
_DtHelpCeCloseVolume (canvas, volume);
}
if (result == 0)
{
fprintf (outTopic, (GetMessage(3, 4, "<CHARACTERSET %s>\n")), charSet);
fprintf (outTopic,"<LINK 0 \"%s %s\">\n", volume_name, (char*)TopLocId);
fprintf (outTopic, (GetMessage(3, 5, (char*)defaultTitle12)), title);
fprintf (outTopic, "</LINK>\n");
/*
* put the abstract information about this
* family in the header file
*/
fprintf (outTopic, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
if (abstract != NULL)
{
fprintf (outTopic, (GetMessage (3, 4, "<CHARACTERSET %s>\n")),
charSet);
fprintf (outTopic, "%s\n", abstract);
fprintf (outTopic, "</CHARACTERSET>\n");
free (abstract);
}
fprintf (outTopic, "</P>\n</CHARACTERSET>\n");
}
if (charSet != DefCharSet)
free(charSet);
if (title)
free ((void *) title);
return result;
}
/*****************************************************************************
* Function: CreateFamily
*
*****************************************************************************/
int
CreateFamily (
CanvasHandle canvas,
char *family_name,
FILE *out_volume,
FILE *out_header,
FILE *out_topic )
{
int result = -1;
int count = 0;
long filepos;
char *charSet = NULL;
char *title = NULL;
char *abstract = NULL;
char *list = NULL;
char *token = NULL;
char *ptr;
char *bitmap = NULL;
char familyName [20]; /* FAMILY%d */
char bitmapName [MAXPATHLEN + 2];
char bitmapNameTemp [sizeof(bitmapName)];
XrmDatabase db;
char *resType;
XrmValue resValue;
db = XrmGetFileDatabase (family_name);
if (db)
{
/*
* get the title
*/
if (XrmGetResource (db, "Family.Title", "family.title",
&resType, &resValue))
{
title = (char *) resValue.addr;
/*
* get the abstract
*/
if (XrmGetResource (db, "Family.Abstract", "family.abstract",
&resType, &resValue))
{
abstract = (char *) resValue.addr;
/*
* get the volumes list
*/
if (XrmGetResource (db, "Family.Volumes", "family.volumes",
&resType, &resValue))
{
list = (char *) resValue.addr;
/*
* get the character set
*/
if (XrmGetResource (db, "Family.CharSet", "family.charSet",
&resType, &resValue))
{
charSet = (char *) resValue.addr;
/*
* get the bitmap (optional)
*/
if (XrmGetResource (db,
"Family.Bitmap", "family.bitmap",
&resType, &resValue))
bitmap = (char *) resValue.addr;
}
else
{
fprintf (stderr,
(GetMessage (1, 14,
"%s: character set resource missing\n")),
family_name);
return -1;
}
}
else
{
fprintf (stderr,
(GetMessage (1, 13,
"%s: volumes resource missing\n")),
family_name);
return -1;
}
}
else
{
fprintf (stderr,
(GetMessage (1, 12, "%s: abstract resource missing\n")),
family_name);
return -1;
}
}
else
{
fprintf (stderr,
(GetMessage (1, 11, "%s: title resource missing\n")),
family_name);
return -1;
}
if (title && abstract && list && charSet)
{
/*
* find out the position of the file pointer
*/
filepos = ftell (out_topic);
/*
* write out the <TOPIC>
*/
fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
charSet, title);
/*
* write out the <TITLE>
*/
fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
title);
fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
fprintf (out_topic, "%s\n", abstract);
fprintf (out_topic, "</P>\n");
do
{
token = NULL;
list = _DtHelpCeGetNxtToken(list, &token);
if (token && *token != '\0' && *token != '\n' &&
CreateVolumeLink (canvas,out_topic, token) == 0)
count++;
if (token)
{
free ((void *) token);
token = NULL;
}
} while (list && *list != '\0');
if (count)
{
result = 0;
sprintf (familyName, "FAMILY%d", FamilyNum);
fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
/*
* Put the link information in the header file
*/
fprintf (out_header,
(GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
fprintf (out_header, "<LINK 0 %s>\n", familyName);
fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
title);
fprintf (out_header, "</LINK>\n");
/*
* put the abstract information about this
* family in the header file
*/
if (NULL != bitmap && *bitmap != '/')
{
snprintf(bitmapName, sizeof(bitmapName), "%s", family_name);
ptr = strrchr (bitmapName, '/');
if (ptr)
{
ptr++;
*ptr = '\0';
snprintf(bitmapNameTemp, sizeof(bitmapNameTemp), "%s%s", bitmapName, bitmap);
strcpy(bitmapName, bitmapNameTemp);
bitmap = bitmapName;
}
else
bitmap = NULL;
}
if (NULL != bitmap)
{
fprintf (out_header,
(GetMessage (3, 6,
"<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
bitmap, familyName);
}
else
fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
fprintf (out_header, "%s\n", abstract);
fprintf (out_header, "</P></CHARACTERSET>\n");
/*
* put the information in the volume file.
*/
fprintf (out_volume, "*.%s.filepos: %ld\n",
familyName, filepos);
fprintf (out_volume, "*.%s.filename: %s\n",
familyName, TopicName);
TopicList = (char **) _DtHelpCeAddPtrToArray (
(void **) TopicList,
strdup (familyName));
}
else
{
/*
* rewind back to the original starting position
*/
fseek (out_topic, filepos, 0);
/*
* didn't find any volumes for this family.
*/
result = -2;
}
}
XrmDestroyDatabase (db);
}
return result;
}
/*****************************************************************************
* Function: CheckFamilyList (name)
*
* See if this family has been seen
*
*****************************************************************************/
int
CheckFamilyList (char *name )
{
char **listPtr = FamilyList;
while (listPtr != NULL && *listPtr != NULL)
{
if (strcmp (*listPtr, name) == 0)
return True;
listPtr++;
}
return False;
}
/*****************************************************************************
* Function: AddFamilyToList (name)
*
* add the name to the family list
*
*****************************************************************************/
char **
AddFamilyToList (char *name )
{
FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
strdup(name));
return FamilyList;
}
/*****************************************************************************
* Function: ScanDirectory
*
* scan a directory looking for family files.
*
*****************************************************************************/
void
ScanDirectory (
char *directory,
long *ret_time)
{
DIR *pDir;
struct stat buf;
char fullName [MAXPATHLEN + 2];
char *ptr;
char *ext;
struct dirent *pDirent;
*ret_time = 0;
if (stat(directory, &buf) == -1)
return;
*ret_time = buf.st_mtime;
pDir = opendir (directory);
if (pDir == NULL)
return;
snprintf(fullName, sizeof(fullName), "%s%s", directory, SlashString);
ptr = fullName + strlen (fullName);
/*
* skip over the "." and ".." entries.
*/
(void) readdir (pDir);
(void) readdir (pDir);
pDirent = readdir (pDir);
while (pDirent)
{
ext = GetExtension (pDirent->d_name);
if (strcmp (ext, Family_ext) == 0)
{
if (CheckFamilyList (pDirent->d_name) == False)
{
AddFamilyToList (pDirent->d_name);
strcpy (ptr, pDirent->d_name);
FullFamilyName = (char **) _DtHelpCeAddPtrToArray(
(void **)FullFamilyName,
strdup(fullName));
}
}
else if (strcmp(ext, Ext_Hv) == 0 || strcmp(ext, Ext_Sdl) == 0)
{
strcpy (ptr, pDirent->d_name);
VolumeList = (char **) _DtHelpCeAddPtrToArray((void **)VolumeList,
strdup(pDirent->d_name));
FullVolName = (char **) _DtHelpCeAddPtrToArray((void **)FullVolName,
strdup(fullName));
}
pDirent = readdir (pDir);
}
closedir(pDir);
return;
}
/*****************************************************************************
* Function: FindFile
*
* Resolves the environment variable for all possible paths.
*
*****************************************************************************/
char *
FindFile (
char *filename)
{
int i;
int trimExt = 0;
int different;
char *fileExt;
char *ext;
struct stat status;
fileExt = GetExtension(filename);
if (*fileExt == '\0')
trimExt = 1;
i = 0;
while (VolumeList != NULL && VolumeList[i] != NULL)
{
if (trimExt)
{
ext = GetExtension(VolumeList[i]);
*ext = '\0';
}
different = strcmp(filename, VolumeList[i]);
if (trimExt)
*ext = '.';
if (!different && access(FullVolName[i], R_OK) == 0
&& stat(FullVolName[i], &status) == 0
&& S_ISDIR(status.st_mode) == 0)
return (FullVolName[i]);
i++;
}
return NULL;
}
/*****************************************************************************
* Function: ExpandPaths
*
* Resolves the environment variable for all possible paths.
*
*****************************************************************************/
void
ExpandPaths (
char *lang,
char *type,
char *env_var,
char *default_str,
char ***list)
{
short strip;
char *ptr;
char *hPtr;
char *src;
char *pathName;
char *searchPath;
searchPath = getenv (env_var);
if (searchPath == NULL || *searchPath == '\0')
{
if (default_str == NULL)
return;
searchPath = default_str;
}
searchPath = strdup (searchPath);
*list = NULL;
src = searchPath;
do
{
ptr = strchr (src, ':');
if (ptr)
*ptr = '\0';
/*
* check to see if %H is declared. If so, we're going
* to have to trim it before saving as the directory path.
*/
strip = False;
hPtr = strrchr (src, '%');
if (hPtr != NULL)
{
hPtr++;
if (*hPtr == 'H')
strip = True;
}
/*
* check to see if the path needs expanding
*/
if (NULL != strchr (src, '%'))
pathName = _DtHelpCeExpandPathname (src, NULL, type, NULL, lang,
(_DtSubstitutionRec *) NULL, 0);
else
pathName = strdup(src);
if (pathName)
{
GetPath (pathName, strip, list);
free (pathName);
}
if (ptr)
{
*ptr = ':';
ptr++;
}
src = ptr;
} while (src && *src);
free(searchPath);
}
/*****************************************************************************
* Function: CheckTimeStamps
*
* Check the time stamps on the volume dir to determine if
* it needs regenerating.
*
*****************************************************************************/
int
CheckTimeStamps (
XrmDatabase db,
char **dir_list)
{
long timeVal;
char *value;
struct stat buf;
while (*dir_list != NULL)
{
if (stat(*dir_list, &buf) == -1)
buf.st_mtime = 0;
value = _DtHelpCeGetResourceString(db, *dir_list,
"TimeStamp", "timeStamp");
timeVal = atol(value);
if (timeVal != buf.st_mtime)
return 1;
dir_list++;
}
return 0;
}
/*****************************************************************************
* Function: CheckInfo
*
* Check the information in the volume to determine if it needs regenerating.
*
*****************************************************************************/
int
CheckInfo (
char *file)
{
int result = 1;
char **list1, **list2;
char **volDirList;
XrmDatabase db;
db = XrmGetFileDatabase (file);
if (db != NULL)
{
volDirList = _DtHelpCeGetResourceStringArray(db, NULL,
"DirList", "dirList");
if (volDirList != NULL)
{
result = 0;
list1 = volDirList;
list2 = FUserList;
while (result == 0 && *list1 != NULL
&& list2 != NULL && *list2 != NULL)
{
result = strcmp(*list1, *list2);
list1++;
list2++;
}
if (list2 != NULL && *list2 != NULL)
result = 1;
list2 = FSysList;
while (result == 0 && *list1 != NULL
&& list2 != NULL && *list2 != NULL)
{
result = strcmp(*list1, *list2);
list1++;
list2++;
}
if (list2 != NULL && *list2 != NULL)
result = 1;
list2 = VUserList;
while (result == 0 && *list1 != NULL
&& list2 != NULL && *list2 != NULL)
{
result = strcmp(*list1, *list2);
list1++;
list2++;
}
if (list2 != NULL && *list2 != NULL)
result = 1;
list2 = VSysList;
while (result == 0 && *list1 != NULL
&& list2 != NULL && *list2 != NULL)
{
result = strcmp(*list1, *list2);
list1++;
list2++;
}
if (*list1 != NULL || (list2 != NULL && *list2 != NULL))
result = 1;
if (result == 0)
result = CheckTimeStamps(db, volDirList);
_DtHelpCeFreeStringArray(volDirList);
}
XrmDestroyDatabase(db);
}
return result;
}
/*****************************************************************************
* Main routine
*****************************************************************************/
int
main(
int argc,
char *argv[] )
{
int i;
int result;
int foundFamily;
int foundVolumes;
int usedUser = 0;
int doGen = 0;
char tmpVolume [MAXPATHLEN + 2];
char tmpVolumeTemp[sizeof(tmpVolume)];
char tmpVolume2 [MAXPATHLEN + 2];
char tmpTopic [MAXPATHLEN + 2];
char tmpHeader [MAXPATHLEN + 2];
char headerName [MAXPATHLEN + 2];
char baseName [MAXPATHLEN + 2];
char baseNameTemp[sizeof(baseName)];
char tempName [MAXPATHLEN + 2];
char **next;
char *charSet;
char *topicTitle;
char *ptr;
char *endDir;
long preamble;
long modTime;
FILE *outVolume;
FILE *outTopic;
FILE *outHeader;
pid_t childPid = (pid_t) -1;
CanvasHandle canvasHandle;
myName = strrchr (argv[0], '/');
if (myName)
myName++;
else
myName = argv[0];
/*
* have to do a setlocale here, so that the usage message is in the
* correct language.
*/
Lang = getenv ("LANG");
/*
* use the default if no lang is specified.
*/
if (Lang == NULL || *Lang == '\0')
Lang = (char*)C_String;
setlocale(LC_ALL, "");
_DtEnvControl(DT_ENV_SET);
/*
* now process the arguments
*/
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
if (argv[i][1] == 'd' && i + 1 < argc)
App_args.dir = argv[++i];
else if (argv[i][1] == 'f' && i + 1 < argc)
App_args.file = argv[++i];
else if (argv[i][1] == 'g')
doGen = 1;
else if (argv[i][1] == 'l' && i + 1 < argc)
App_args.lang = argv[++i];
else
{
fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
exit (1);
}
}
else
{
fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
exit (1);
}
}
/*
* get the language we are working with.
*/
if (App_args.lang != NULL)
{
/*
* Set the locale! Since the user has specified a (likely)
* different language to do the processing in, we need to
* do a setlocale to work with the new language.
*/
Lang = App_args.lang;
if (setlocale(LC_ALL, Lang) == NULL)
{
fprintf (stderr, (GetMessage(1, 20,
"%s: Invalid system language specified - %s\n")),
myName, Lang);
exit (1);
}
_DtEnvControl(DT_ENV_SET);
}
Lang = strdup(Lang);
/*
* get the directory to work in
*/
if (NULL == App_args.dir)
{
fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
exit (1);
}
if (App_args.dir[0] != '/')
{
if (getcwd (baseName, MAXPATHLEN) == NULL)
{
fprintf (stderr, (GetMessage (1, 18,
"%s: Unable to access current working directory - error status number %d\n")),
myName, errno);
exit (1);
}
snprintf(baseNameTemp, sizeof(baseNameTemp), "%s/%s", baseName, App_args.dir);
strcpy(baseName, baseNameTemp);
}
else
snprintf(baseName, sizeof(baseName), "%s", App_args.dir);
/*
* make sure the directory exists
*/
ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
(_DtSubstitutionRec *) NULL, 0);
if (ptr == NULL || *ptr == '\0')
{
fprintf (stderr,
(GetMessage (1, 15, "%s: Destination directory missing\n")),
myName);
exit (1);
}
snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
if (tmpVolume[strlen (tmpVolume) - 1] != '/') {
snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, SlashString);
strcpy(tmpVolume, tmpVolumeTemp);
}
free (ptr);
/*
* march down the path, checking that
* 1) it exists
* 2) the caller has access permission.
* 3) resolve all symbolic links
*/
endDir = strchr (tmpVolume, '/');
if (endDir != NULL)
{
endDir++;
endDir = strchr (endDir, '/');
}
while (endDir && *endDir != '\0')
{
/*
* remember the rest of the string (including the slash)
* and strip the trailing slash from the directory path.
*/
snprintf(tmpVolume2, sizeof(tmpVolume2), "%s", endDir);
*endDir = '\0';
/*
* trace the path and copy the new string into the old buffer.
*/
ptr = _DtHelpCeTracePathName(tmpVolume);
if (ptr != NULL)
{
snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
free (ptr);
}
if (access (tmpVolume, F_OK) == -1)
{
switch (errno)
{
case ENOTDIR:
ptr = GetMessage (1, 2, (char*)NotDirectory);
fprintf (stderr, ptr, myName, tmpVolume);
exit (1);
case EACCES:
ptr = GetMessage (1, 3, (char*)SuperMsg);
fprintf (stderr, ptr, myName, tmpVolume);
exit (1);
case ENOENT:
if (mkdir(tmpVolume,
(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) == -1
&& errno != EEXIST && errno != EROFS)
{
switch (errno)
{
case ENOTDIR:
ptr = GetMessage(1,2,
(char*)NotDirectory);
break;
case EACCES:
ptr = GetMessage(1, 3,
(char*)SuperMsg);
break;
case ENOENT:
ptr = GetMessage(1, 4,
"%s: Element of %s does not exist\n");
break;
case ENOSPC:
ptr = GetMessage (1, 5,
"%s: File system containing %s is full\n");
break;
default:
ptr = GetMessage(1,6,
(char*)GeneralAccess);
break;
}
fprintf (stderr, ptr, myName, tmpVolume, errno);
exit (1);
}
break;
default:
ptr = GetMessage (1, 6, (char*)GeneralAccess);
fprintf (stderr, ptr, myName, tmpVolume, errno);
exit (1);
}
}
/*
* point to the end of the string (past where the slash will go)
*/
endDir = tmpVolume + strlen(tmpVolume) + 2;
/*
* append the rest of the directory spec that hasn't been checked.
*/
strcat (tmpVolume, tmpVolume2);
endDir = strchr (endDir, '/');
}
/*
* get temporary files for the volume and topic file.
*/
snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, App_args.file);
strcpy(tmpVolume, tmpVolumeTemp);
(void) strcpy (tmpHeader, tmpVolume);
(void) strcpy (tmpTopic, tmpVolume);
snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, Ext_Hv);
strcpy(tmpVolume, tmpVolumeTemp);
(void) strcat (tmpHeader, "00.ht");
(void) strcat (tmpTopic , "01.ht");
result = access (tmpVolume, F_OK);
/*
* If it exists, make sure the invoker can write to it.
*/
if (result == 0)
{
if (access (tmpVolume, W_OK) == -1)
{
if (errno == EROFS)
ptr = GetMessage (1, 7,
"%s: File system containing %s is read only\n");
else if (errno == EACCES)
ptr = GetMessage (1, 8,
"%s: Requires root permission to write to %s\n");
else
ptr = GetMessage (1, 9, (char*)WriteInvalid);
fprintf (stderr, ptr, myName, tmpVolume, errno);
exit (1);
}
}
else if (result == -1 && errno != ENOENT)
{
ptr = GetMessage (1, 6, (char*)GeneralAccess);
fprintf (stderr, ptr, myName, tmpVolume, errno);
exit (1);
}
else /* file does not exist */
doGen = 1;
/*
* Find out if we have any paths to check.
*/
ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
DtDEFAULT_SYSTEM_PATH, &FSysList);
ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
DtDEFAULT_SYSTEM_PATH, &VSysList);
if (((FUserList == NULL || *FUserList == NULL) &&
(FSysList == NULL || *FSysList == NULL)) ||
((VUserList == NULL || *VUserList == NULL) &&
(VSysList == NULL || *VSysList == NULL)))
{
ptr = GetMessage (1, 10, "%s: Search Path empty\n");
fprintf (stderr, ptr, myName);
exit (1);
}
/*
* If we already haven't determined that the volume needs (re)generating
* check the info squirreled away in the old volume.
*/
if (doGen == 0)
doGen = CheckInfo(tmpVolume);
/*
* the volume doesn't need (re)generating.
* exit now.
*/
if (doGen == 0)
exit(0);
/*
* create a canvas for the functions.
*/
canvasHandle = _DtHelpCeCreateDefCanvas();
if (canvasHandle == NULL)
{
fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
myName);
MyExit (1, -1);
}
/*
* open the individual files that will hold the browser information.
* <file>.hv
*/
outVolume = fopen (tmpVolume, "w");
if (outVolume == NULL)
{
ptr = GetMessage (1, 9, (char*)WriteInvalid);
fprintf (stderr, ptr, myName, tmpVolume, errno);
_DtHelpCeDestroyCanvas(canvasHandle);
MyExit (1, -1);
}
/*
* <file>00.ht
*/
outTopic = fopen (tmpTopic, "w");
if (outTopic == NULL)
{
ptr = GetMessage (1, 9, (char*)WriteInvalid);
fprintf (stderr, ptr, myName, tmpTopic, errno);
(void) unlink (tmpVolume);
_DtHelpCeDestroyCanvas(canvasHandle);
MyExit (1, -1);
}
/*
* <file>01.ht
*/
outHeader = fopen (tmpHeader, "w");
if (outHeader == NULL)
{
ptr = GetMessage (1, 9, (char*)WriteInvalid);
fprintf (stderr, ptr, myName, tmpHeader, errno);
(void) unlink (tmpVolume);
(void) unlink (tmpTopic);
_DtHelpCeDestroyCanvas(canvasHandle);
MyExit (1, -1);
}
/*
* fork off the dtksh script that will put up a dialog
* telling the user that we're building help browser
* information.
*/
#ifdef __hpux
childPid = vfork();
#else
childPid = fork();
#endif
/*
* if this is the child, exec the dthelpgen.ds script.
*/
if (childPid == 0)
{
execlp("dthelpgen.ds", "dthelpgen.ds",
((char *) 0), ((char *) 0), ((char *) 0));
_exit(1);
}
/*
* initialize the main topic
*/
strcpy (TopicName, App_args.file);
strcat (TopicName, "01.ht");
strcpy (headerName, App_args.file);
strcat (headerName, "00.ht");
/*
* The original dthelpgen extracts the CDE Standard name from
* its message catalogue( set 2/msg 1 ).
* But on IBM ODE, this is a problem. For example,
* fr_FR's dthelpgen.cat has
* fr_FR.ISO-8859-1 in set 2/msg 1.
* Correct Fr_FR's message catalogue must have,
* fr_FR.IBM-850
* there. But current IBM ode's Makefile cannot do this. Instead put
* fr_FR.ISO-8859-1. ( That is "do nothing" ).
* To fix this, dthelpgen converts the current IBM LANG to CDE
* standard name with _DtLcx*() function provided by libDtHelp.a as
* internal API.
*/
#ifdef _AIX
{
_DtXlateDb db = NULL;
int ret;
char plat[_DtPLATFORM_MAX_LEN];
int execver;
int compver;
char *ret_stdLocale;
char *ret_stdLangTerr;
char *ret_stdCodeset;
char *ret_stdModifier;
ret = _DtLcxOpenAllDbs( &db );
if ( !ret ) {
ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
if ( !ret ) {
ret = _DtLcxXlateOpToStd( db, plat, execver,
DtLCX_OPER_SETLOCALE,
setlocale( LC_MESSAGES, NULL ),
&ret_stdLocale, &ret_stdLangTerr,
&ret_stdCodeset, &ret_stdModifier );
if ( !ret ) {
charSet = strdup( ret_stdLocale );
} else {
charSet = "C.ISO-8859-1";
}
} else {
charSet = "C.ISO-8859-1";
}
ret = _DtLcxCloseDb( &db );
} else {
charSet = "C.ISO-8859-1";
}
}
#else /* _AIX */
charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
#endif /* _AIX */
topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
charSet, topicTitle);
fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
free(topicTitle);
preamble = ftell (outHeader);
fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
/*
* loop through the directories looking for all the unique families
* and -all- the volumes.
*/
fprintf (outVolume, "!# Last modification time stamp per directory\n");
next = FUserList;
while (next != NULL && *next != NULL)
{
ScanDirectory(*next, &modTime);
fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
next++;
}
next = FSysList;
while (next != NULL && *next != NULL)
{
ScanDirectory(*next, &modTime);
fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
next++;
}
next = VUserList;
while (next != NULL && *next != NULL)
{
ScanDirectory(*next, &modTime);
fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
next++;
}
next = VSysList;
while (next != NULL && *next != NULL)
{
ScanDirectory(*next, &modTime);
fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
next++;
}
fprintf (outVolume, "*.charSet: %s\n", charSet);
free(charSet);
fprintf (outVolume, "\n!# Topic filenames and offsets\n");
/*
* Now create families.
*/
foundVolumes = 0;
foundFamily = 0;
for (next = FullFamilyName; next != NULL && *next != NULL; next++)
{
result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
if (result == 0)
{
FamilyNum++;
foundVolumes = 1;
foundFamily = 1;
}
else if (result == -2)
foundFamily = 1;
}
if (foundFamily == 0)
fprintf(stderr,
GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
else if (foundVolumes == 0)
fprintf (stderr,
GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
/*
* Clean up
*/
if (FamilyList != NULL)
_DtHelpCeFreeStringArray(FamilyList);
if (FullFamilyName != NULL)
_DtHelpCeFreeStringArray(FullFamilyName);
if (VolumeList != NULL)
_DtHelpCeFreeStringArray(VolumeList);
if (FullVolName != NULL)
_DtHelpCeFreeStringArray(FullVolName);
/*
* If no family or volume files were found,
* write out the alternative preamble
*/
if (foundFamily == 0 || foundVolumes == 0)
{
fseek (outHeader, preamble, 0);
fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
}
/*
* write the ending message and finish the topic.
*/
fprintf (outHeader, "</TOPIC>\n");
/*
* write out the volume resouces
*/
fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
fprintf (outVolume, "\n\n!# Volume Title\n");
fprintf (outVolume, "*.title: %s\n",
GetMessage (2, 4, "Help - Top Level"));
/*
* top topic
*/
fprintf (outVolume, "\n\n!# Topic Home Location\n");
fprintf (outVolume, "*.topTopic: %s\n", ParentName);
/*
* topic hierarchy
*/
fprintf (outVolume, "\n\n!# Topic Hierarchy\n");
fprintf (outVolume, "*.%s.parent: \n", ParentName);
for (next = TopicList; next && *next; next++)
fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
/*
* topic list
*/
fprintf (outVolume, "\n\n!# Topic List\n");
fprintf (outVolume, "*.topicList: %s", ParentName);
next = TopicList;
while (next && *next)
{
fprintf (outVolume, " \\\n %s", *next);
next++;
}
fprintf (outVolume, "\n");
/*
* The paths used to create this information.
*/
fprintf (outVolume, "\n\n!# Paths Searched\n");
fprintf (outVolume, "*.dirList: ");
next = FUserList;
while (next != NULL && *next != NULL)
{
fprintf (outVolume, " \\\n %s", *next);
next++;
}
next = FSysList;
while (next != NULL && *next != NULL)
{
fprintf (outVolume, " \\\n %s", *next);
next++;
}
next = VUserList;
while (next != NULL && *next != NULL)
{
fprintf (outVolume, " \\\n %s", *next);
next++;
}
next = VSysList;
while (next != NULL && *next != NULL)
{
fprintf (outVolume, " \\\n %s", *next);
next++;
}
fprintf (outVolume, "\n");
/*
* close the volumes.
*/
fclose (outVolume);
fclose (outHeader);
fclose (outTopic);
if (TopicList != NULL)
_DtHelpCeFreeStringArray(TopicList);
if (FUserList != NULL)
_DtHelpCeFreeStringArray(FUserList);
if (FSysList != NULL)
_DtHelpCeFreeStringArray(FSysList);
if (VUserList != NULL)
_DtHelpCeFreeStringArray(VUserList);
if (VSysList != NULL)
_DtHelpCeFreeStringArray(VSysList);
_DtHelpCeDestroyCanvas(canvasHandle);
MyExit (0, childPid);
}