Files
cdesktop/cde/programs/dthelp/parser.ccdf/volumegen/Volumegen.c

765 lines
21 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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
*/
/* $XConsortium: Volumegen.c /main/4 1995/11/08 11:48:17 rswiston $ */
/************************************<+>*************************************
****************************************************************************
*
* File: Volumegen.c
*
* Project: Cache Creek (Rivers) Project
* Description: Source for the 'volumegen' portion of HelpTAG.
* Author: Brian Cripe
* Modifications by Mike Wilson
* Modifications to support non-topic IDs added by Dex Smith
* Language: C
*
* (C) Copyright 1992, Hewlett-Packard, all rights reserved.
*
****************************************************************************
************************************<+>*************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <locale.h>
/* Local Includes */
#include "PstackI.h"
#define TRUE 1
#define FALSE 0
typedef int Boolean;
/* extern int errno; */
/* extern int sys_nerr; */
static void GenTopicList (
FILE *infile,
FILE *outfile);
static void GenTopicHeir(
FILE *infile,
FILE *outfile);
static void GenTopicLoc(
FILE *infile,
FILE *outfile);
static void GenHomeLocation(
FILE *outfile);
static void GenKeyWordList(
FILE *infile,
FILE *outfile);
static void MergeMetaInfo(
FILE *infile,
FILE *outfile);
static char *GetNextToken(
FILE *file,
Boolean delimIsSpace);
/* Volumegen Input file suffixes */
#define HEIR_FILE_SUFFIX ".tpc" /* The input filename suffix used for topic */
/* hierarchy files. */
#define TLOC_FILE_SUFFIX ".idt" /* The input filename suffix used for topic */
/* location files. */
#define IKEY_FILE_SUFFIX ".idx" /* The input filename suffix used for sorted*/
/* keyword file. */
#define IMETA_FILE_SUFFIX ".hmi" /* The input filename suffix used for meta */
/* information file. */
/* Volumegen Output file suffixes */
#define VOL_FILE_SUFFIX ".hv" /* The filename suffix used for volume */
/* file generated by volumegen. */
#define KEY_FILE_SUFFIX ".hvk" /* The filename suffix used for keyword */
/* file generated by volumegen. */
/*****************************************************************************
* Function: void main();
*
*
* Purpose: Program Main line body
*
*****************************************************************************/
void main (
int argc,
char **argv)
{
char *fName;
FILE *tlocFile, *heirFile, *keyFile, *metaFile;
FILE *volFile, *keyWordFile;
setlocale(LC_ALL, "");
/* Make sure that an argument naming the volume was supplied. */
if (argc < 2) {
fprintf (stderr, "usage: %s <volume-name>\n", *argv);
exit (1);
}
/* Construct the name of the hierarchy file and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (HEIR_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, HEIR_FILE_SUFFIX);
if ((heirFile = fopen (fName, "r")) == NULL) {
fprintf (stderr,
"%s: error opening hierarchy file %s for reading\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Construct the name of the topic location file and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (TLOC_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, TLOC_FILE_SUFFIX);
if ((tlocFile = fopen (fName, "r")) == NULL) {
fprintf (stderr,
"%s: error opening topic location file %s for reading\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Construct the name of the keyword file and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (IKEY_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, IKEY_FILE_SUFFIX);
if ((keyFile = fopen (fName, "r")) == NULL) {
fprintf (stderr,
"%s: error opening keyword file %s for reading\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Construct the name of the meta information file and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (IMETA_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, IMETA_FILE_SUFFIX);
if ((metaFile = fopen(fName, "r")) == NULL) {
fprintf (stderr,
"%s: error opening meta file %s for reading\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Construct the name of the volume file (the one we are creating)
and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (VOL_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, VOL_FILE_SUFFIX);
if ((volFile = fopen (fName, "w")) == NULL) {
fprintf (stderr, "%s: error opening Volume file %s for writing\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Construct the name of the keyword file (the one we are creating)
and open it. */
fName = malloc (strlen (*(argv+1)) + strlen (KEY_FILE_SUFFIX) + 1);
strcpy (fName, *(argv+1));
strcat (fName, KEY_FILE_SUFFIX);
if ((keyWordFile = fopen (fName, "w")) == NULL) {
fprintf (stderr, "%s: error opening Keyword file %s for writing\n",
*argv, fName);
perror (NULL);
exit (1);
}
/* Generate topic list and hierarchy */
GenTopicList (heirFile, volFile);
GenTopicHeir (heirFile, volFile);
/* Generate topic location table. */
GenTopicLoc(tlocFile, volFile);
/* Generate the keyword information */
GenKeyWordList(keyFile, keyWordFile);
/* Merge the Meta information */
MergeMetaInfo(metaFile, volFile);
/* Generate the Home Topic entry */
GenHomeLocation(volFile);
exit(0);
}
/*****************************************************************************
* Function: static void GenTopicList(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Generates the topic list in the <class>.hv file.
*
*****************************************************************************/
static void GenTopicList (
FILE *infile,
FILE *outfile)
{
char *token;
fseek (infile, 0, SEEK_SET);
fprintf (outfile, "# Topic List\n");
/* The output formatting is kind of tricky as we want to end every
line with a "\", except for the last line. Therefore each time
through the loop we print the "\\\n" for the previous line and
the body of the current line. */
fprintf (outfile, "*.topicList: ");
while ((token = GetNextToken (infile, TRUE)) != NULL) {
if ((strcmp (token, "{") != 0) && (strcmp (token, "}") != 0))
fprintf (outfile, "\\\n\t%s ", token);
free (token);
}
fprintf (outfile, "\n\n");
}
/*****************************************************************************
* Function: static void GenTopicHeir(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Generates the topic hierarchy in the <class>.hv file.
*
*****************************************************************************/
static void GenTopicHeir(
FILE *infile,
FILE *outfile)
{
char *token, *prevToken, *tempS;
PStack topicStack;
topicStack = PStackCreate();
fseek (infile, 0, SEEK_SET);
fprintf (outfile, "# Topic Hierarchy\n");
prevToken = NULL;
while ((token = GetNextToken (infile, TRUE)) != NULL) {
if (strcmp (token, "{") == 0)
PStackPush (topicStack, prevToken);
else if (strcmp (token, "}") == 0) {
if (prevToken != NULL)
free (prevToken);
free (PStackPop (topicStack));
}
else {
tempS = (char *) PStackPeek (topicStack);
if (tempS == NULL) {
tempS = "";
}
fprintf (outfile, "*.%s.parent:\t%s\n", token, tempS);
if (prevToken != NULL)
free (prevToken);
}
prevToken = token;
}
PStackDestroy (topicStack);
fprintf (outfile, "\n");
}
/*****************************************************************************
* Function: static void GenTopicLoc(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Generates the topic Location section in the
* <class>.hv file.
*
*****************************************************************************/
static void GenTopicLoc(
FILE *infile,
FILE *outfile)
{
char *topic, *topicFile, *topicPos;
char *trueTopicID = NULL;
char *locationIdNew = NULL;
char *idList = NULL;
fseek (infile, 0, SEEK_SET);
fprintf (outfile,
"# Topic Locations (file names, file positions, and non-topic IDs)\n");
/* Topic location files have a strict syntax where each line contains
either three tokens (the topic ID, the file containing the topic,
and the byte offset to the start of the topic), or two tokens (the
topic ID and a non-topic ID that occurs within the topic). The
first style (three tokens) is identified by the trailing ":" on the
topic ID. Similarly, the second style (two tokens) is identified by
the trailing ">" on the topic ID. If the file deviates from these
two variations of the syntax, the file is considered corrupt. */
while (1) {
if ((topic = GetNextToken (infile, TRUE)) == NULL)
break;
/* If the topic ID ends with ":", then we've found a primary entry. */
if (*(topic + strlen (topic) - 1) == ':')
{
/* Strip the ":" at the end of the topic ID */
*(topic + strlen (topic) - 1) = '\0';
/* if there was a previous trueTopicID, print it out */
if (trueTopicID != (char *)NULL && idList != (char *)NULL)
{
fprintf(outfile, "*.%s.locationIDs:\t%s\n",
trueTopicID, idList);
free (trueTopicID);
free (idList);
idList = (char *)NULL;
}
/* Save the new true topic. */
trueTopicID = malloc(strlen(topic) + 1);
strcpy(trueTopicID, topic);
if ((topicFile = GetNextToken (infile, TRUE)) == NULL)
break;
if ((topicPos = GetNextToken (infile, TRUE)) == NULL)
break;
fprintf (outfile, "*.%s.filename:\t%s\n", topic, topicFile);
fprintf (outfile, "*.%s.filepos:\t%s\n", topic, topicPos);
free (topicFile);
free (topicPos);
}
/* Else, if the id ends with ">", we've found a non-topic entry. */
else if (*(topic + strlen (topic) - 1) == '>')
{
/* Get the next token, its the non-topic ID. */
if ((locationIdNew = GetNextToken (infile, TRUE)) == NULL)
break;
/* If the ID list hasn't been started for this topic, start it. */
if (idList == (char *)NULL)
{
idList = malloc(strlen(locationIdNew) + 1);
strcpy(idList, locationIdNew);
}
/* Else, add the ID we've just found to the list. */
else
{
/* append the non-topic location ID to the list */
idList =
realloc(idList, strlen(idList) + strlen(locationIdNew) +2);
strcat(idList, " ");
strcat(idList, locationIdNew);
}
}
else
{
/* If the token does not end with ":" or ">", we have a problem. */
printf("The <volume>%s file is corrupt!\n", TLOC_FILE_SUFFIX);
}
free (topic);
}
if (trueTopicID != (char *)NULL && idList != (char *)NULL)
{
fprintf(outfile, "*.%s.locationIDs:\t%s\n",
trueTopicID, idList);
free (trueTopicID);
free (idList);
}
fprintf (outfile, "\n\n");
}
/*****************************************************************************
* Function: static void GenKeyWordList(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Generates the keyword list using the <class>.idx file and
* writes the results to <class>.hv file.
*
*****************************************************************************/
static void GenKeyWordList(
FILE *infile,
FILE *outfile)
{
char *sortKey=NULL;
char *keyWordNew=NULL;
char *locationIdNew=NULL;
char *keyWordLast=NULL;
char *locationIdLast=NULL;
char *idList=NULL;
char *newList=NULL;
static char empty[] = "";
fseek (infile, 0, SEEK_SET);
fprintf (outfile, "# Keyword Index\n");
/* idx files (e.g. keyword) have a strict syntax where each line contains
* three tokens (the sort key, the keyword, and the locationID of the
* topic in which the keyword resides). Therefore it is an error if the
* number of tokens in the file is not an integral multiple of 3.
*/
fprintf (outfile, "*Keywords:\t\\\n");
while (1) {
/* We get the sortKey, but we don't use it */
if ((sortKey = GetNextToken (infile, FALSE)) == NULL)
break;
if ((keyWordNew = GetNextToken (infile, FALSE)) == NULL)
break;
if ((locationIdNew = GetNextToken (infile, FALSE)) == NULL)
break;
/* Check to see if we have the same keyword as before? */
if (keyWordLast && (strcmp (keyWordNew, keyWordLast) == 0))
{
/* We have a duplicate so add it to our previous keyword list */
idList =
realloc(idList, strlen(idList) + strlen(locationIdNew) + 2);
/* Add the new locationId to our current list */
strcat(idList, " ");
strcat(idList, locationIdNew);
}
else
if (keyWordLast != NULL)
{
/* Write out the lastList keyword list */
fprintf (outfile, "%s<\\\\>%s\\n\\\n", keyWordLast, idList);
/* Clean up our old values */
free(keyWordLast);
free(idList);
/* We have a new keyword, so create a new keyword list */
idList = malloc(strlen(locationIdNew) + 1);
strcpy(idList, locationIdNew);
keyWordLast = malloc(strlen(keyWordNew) + 1);
strcpy(keyWordLast, keyWordNew);
}
else
{
/* This is the first time in so we special case it */
/* Create our initial keyword list */
idList = malloc(strlen(locationIdNew) + 1);
strcpy(idList, locationIdNew);
keyWordLast = malloc(strlen(keyWordNew) + 1);
strcpy(keyWordLast, keyWordNew);
}
free (sortKey);
free (keyWordNew);
free (locationIdNew);
}
/* Write out the last keyword and idList */
if (!keyWordLast)
keyWordLast = empty;
if (!idList)
idList = empty;
fprintf (outfile, "%s<\\\\>%s\\n\n", keyWordLast, idList);
/* Clean up our old values */
if (keyWordLast != empty)
free(keyWordLast);
if (idList != empty)
free(idList);
fprintf (outfile, "\n\n");
}
/*****************************************************************************
* Function: static char *GetAChar(FILE *file)
*
* Parameters: file from which to read a (possibly multibyte) character
*
*
* Return Value: pointer to (possibly multibyte) character
*
* Purpose: Read a (possibly multibyte) character from the file.
* Put the character byte(s) into local static storage,
* terminating the character with a null byte.
*
*****************************************************************************/
static char *GetAChar(FILE *ifile)
{
int c;
static char mbyte[32]; /* bigger than any possible multibyte char */
int length;
length = 0;
if (((c = getc(ifile)) == EOF) || (c == '\0'))
{
*mbyte = '\0';
return mbyte;
}
while (1)
{
mbyte[length++] = c;
mbyte[length] = '\0';
if (mblen(mbyte,length) != -1) return mbyte; /* hurray! */
if (length == MB_CUR_MAX)
{ /* reached max without a hit */
printf("An invalid multi-byte character was found in the input");
mbyte[0] = ' ';
mbyte[1] = '\0';
return mbyte;
}
if ((c = getc(ifile)) == EOF)
{ /* huh? */
printf("End-of-file found within a multi-byte character");
mbyte[0] = '\0';
return mbyte;
}
}
}
/*****************************************************************************
* Function: static void MergeMetaInfo(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Merges the <class>.hmi meta information into the
* runtime volume file <class>.hv file.
*
*****************************************************************************/
static void MergeMetaInfo(FILE *infile, FILE *outfile)
{
char buff[BUFSIZ];
char *nextC;
char *writeC, *token;
fprintf (outfile, "# Meta Information\n");
fseek (infile, 0, SEEK_SET);
/* Clear out any initial white space that may be present */
while ((*(nextC = GetAChar(infile)) != '\0') &&
(mblen(nextC, MB_CUR_MAX) == 1) &&
isspace(*nextC))
;
/* place that initial nextC value */
fputs(nextC, outfile);
while (*(nextC = GetAChar(infile)))
fputs(nextC, outfile);
fputs("\n\n", outfile);
}
/*****************************************************************************
* Function: static void GenHomeLocation(
* FILE *infile,
* FILE *outfile)
*
* Parameters: infile
* outfile
*
* Return Value: Void.
*
* Purpose: Generates the topic Location section in the
* <class>.hv file.
*
*****************************************************************************/
static void GenHomeLocation(
FILE *outfile)
{
char *topic, *topicFile, *topicPos;
fprintf (outfile, "# Topic Home Locations\n");
fprintf (outfile, "*topTopic: _HOMETOPIC\n");
fprintf (outfile, "\n\n");
}
/*****************************************************************************
* Function: static char *GetNextToken(FILE *file)
*
* Parameters: WidgetClass
*
*
* Return Value: Void.
*
* Purpose: This function will return a token from the input streem.
* A boolean flag is passed in which instructs the function to
* use one of two token delimiters: " " or '\0'.
* (e.g. space or null char).
*****************************************************************************/
static char *GetNextToken(FILE *file, Boolean delimIsSpace)
{
char buff[BUFSIZ];
char *nextC;
char *writeC, *token;
int length;
while ((*(nextC = GetAChar(file)) != '\0') &&
((length = mblen(nextC, MB_CUR_MAX)) == 1) &&
isspace(*nextC))
;
if (*nextC == '\0')
return (NULL);
writeC = buff;
if (delimIsSpace)
{
do {
if (writeC < (buff + BUFSIZ - length - 1))
{
strcpy(writeC, nextC);
writeC += length;
}
nextC = GetAChar(file);
length = mblen(nextC, MB_CUR_MAX);
}
while ((length > 1) || ((*nextC != '\0') && !isspace(*nextC)));
}
else
{
do {
if (writeC < (buff + BUFSIZ - length - 1))
{
strcpy(writeC, nextC);
writeC += length;
}
nextC = GetAChar(file);
length = mblen(nextC, MB_CUR_MAX);
if ((length == 1) && (*nextC == '\036'))
*nextC = '\0';
}
while ((length > 1) || (*nextC != '\0'));
}
token = strdup(buff);
return token;
}