/* @(#)thcreate.c 17.1.1.1 (ES0-DMD) 01/25/02 17:48:01 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++ .TYPE Program .IDENTIFICATION thcreate.c .AUTHOR Francois Ochsenbein [ESO-IPG] .LANGUAGE C .KEYWORDS Hierarchical Help using TermWindows .ENVIRONMENT TermWindows .VERSION 1.0 07-Nov-1988: Creation .VERSION 1.1 05-Dec-1988: Added `header'; remove insertion of comments. .VERSION 1.2 13-Jan-1989: Remov bug in the sorting process: new internal `compare' routine to ensure that the } (closing brace) comes before any other character .VERSION 1.3 22-Jun-1989: Make sure anything is aligned... .VERSION 1.4 16-Feb-1990: Be sure the program doesn't crash... .COMMENTS The module creates an index to a help file. The generated file is made of the following parts: \begin{TeX} \begin{enumerate} \item The various definitions taken from the included files, preceded by the {\tt \b fromHelpFiles} macro \item The {\tt \b HelpIndex } definitions \item The remaining part of the text. \end{enumerate} The \b HelpIndex has 7 parameters: \begin{enumerate} \item The level, a number starting from 0 up to 9 \item The topic, or filename for HelpLoad \item A short explanation, for survey purposes. \item The context specification, as a set of words separated by commas. \item The name of the file where the help is included \item The starting position just following the \b Help \item The number of bytes to load. \end{enumerate} The default extension for the input file is {\tt .tex}; the default extension for the index file is {\tt .ind}. \end{TeX} ----------------------------*/ #define DEBUG 0 /* For debugging only */ #define PM_LEVEL 2 #define PASCAL_DEF 0 #include #include #include #include #include #include #include #include /* Time operations */ #define GetProgramName() osfparse(GetProgramFile(),_FILE_) #define NREC 20 static TeX htex; TeX *tx_tex(); typedef struct { long pos; /* Current position */ int fid; /* File number */ int level; /* File level */ int phase; /* 0: ignore; 1: copy */ char filename[1]; /* File name */ } PIECE; /* Piece of text to use with DisplayArray */ typedef struct { int previous, next; /* Continuation */ char text[12]; } INDEX; static BUFFER *bpiece = NULL_PTR(BUFFER); static BUFFER *bindex = NULL_PTR(BUFFER); static BUFFER *bstart = NULL_PTR(BUFFER); static INDEX start_index = {-1, -1, {'\\', 'H', 'e', 'l', 'p', 'I','n','d','e','x','{'}}; static PIECE *pp = NULL_PTR(PIECE); static PIECE piece = {0,0,0,0,""}; static long pos_in_file[NREC]; static char buf[NREC*133]; static int fout = 0; /* Name of Output File */ static char error_flag = 0; static char osort = 0; static char olist = 0; #define FINISH goto FIN #define FROM_MACRO "\\fromHelpFiles" #define HELP_MACRO "\\Help" #define HELP_INDEX "\\HelpIndex" #define time_pic "DD-MMM-YYYY" static char time_buf[sizeof(time_pic)]; /*==========================================================================*/ static int synopsis() /*+++ .PURPOSE Just write the message if no argument. .RETURNS 0 .REMARKS ---*/ { static char text[] = "[-v] [-s] [-help] input_file [output_file]"; printf("Usage: %s %s\n", GetProgramName(), text); return(0); } static void help() /*+++ .PURPOSE Write a detailed Help .RETURNS 0 .REMARKS ---*/ { int i; static char *text[] = { "\nCreate an index for a set of TW Help Files", " input_file has an extension .tex by default", " output_file is, by default, the input_file with an extension .ind", " -s sort the topics alphabetically in each topic level", " -v verbose mode" }; synopsis(); for (i = 0; i < ITEMS(text); i++) puts(text[i]); } /*==========================================================================*/ static INDEX *Previous(pc, level) /*+++ .PURPOSE Find previous index for a specified level .RETURNS Found index .REMARKS ---*/ INDEX *pc; /* IN: Starting point */ char level; /* IN: Level to check */ { register INDEX *pi; for (pi = pc; pi->text[11] > level; ) pi = (INDEX *)(bindex->buf + pi->previous); return(pi); } /*==========================================================================*/ static INDEX *Last(pc, level) /*+++ .PURPOSE Find Last index for a specified level .RETURNS Found index .REMARKS ---*/ INDEX *pc; /* IN: Starting point */ char level; /* IN: Level to check */ { register INDEX *pi, *p; for (pi = pc; pi->next != (-1); pi = p) { p = (INDEX *)(bindex->buf + pi->next); if (p->text[11] <= level) break; } return(pi); } /*==========================================================================*/ static INDEX *Next(pc, level) /*+++ .PURPOSE Find Next index for a specified level .RETURNS Found index / NULL if none .REMARKS ---*/ INDEX *pc; /* IN: Starting point */ char level; /* IN: Level to check */ { register INDEX *pi, *p; pi = Last(pc, level); p = NULL_PTR(INDEX); if (pi->next != (-1)) { pi = (INDEX *)(bindex->buf + pi->next); if (pi->text[11] == level) p = pi; } return(p); } /*========================================================================== * help_load *==========================================================================*/ int help_load(filename, level) /*+++ .PURPOSE Execute \HelpLoad .RETURNS OK .REMARKS ---*/ char *filename; /* IN: New file to load */ int level; /* IN: Current level */ { PIECE *p; int l, size; ENTER("help_load"); TRACE(filename); l = strlen(filename); size = (l + sizeof(piece) + 4)&~3; /* Adjust for Alignments */ p = (PIECE *) mm_bst(bpiece, (char *)(&piece), size); oscopy(p->filename, filename, l+1); p->level = level; if (pp) p->level += pp->level; p->fid = fi_open(p->filename, READ|RECORD_MODE); if (p->fid <= 0) { error_flag = 1; BUF_Unstack(bpiece); FINISH; } p->phase = 1; /* Copy until next \Help */ pp = p; ReadNext(); pp->phase = 0; FIN: EXIT(p->fid); } /*========================================================================== * act0 *==========================================================================*/ static int act0(str, len) /*+++ .PURPOSE Action Routine to execute definitions in a help file .RETURNS len (does nothing) .REMARKS ---*/ char *str; /* IN: Action string, should start with H */ int len; /* IN: Length of action string */ { return(len); } /*========================================================================== * acti *==========================================================================*/ static int acti(str, len) /*+++ .PURPOSE Action Routine to deal with Help .RETURNS 0 (must stop) .REMARKS ---*/ char *str; /* IN: Action string, should start with H */ int len; /* IN: Length of action string */ { int o, l, level; char alevel, *p; long fpos; static char zeroes[4] = ""; if (*str != 'H') return(len); switch(str[1]) { case '+': /* \fromHelpFiles: Ignore */ pp->phase = 0; help_tell(); break; case ':': /* \HelpIndex: Ignore */ pp->phase = 0; /* No copy */ help_tell(); break; case '.': /* \Help: Create \HelpIndex */ o = bindex->used; BUF_AppendItem(bindex, INDEX, &start_index); bindex->used -= 1; /* !?!?!? Suppress the ending EOS */ tex_getparm(1); /* Level */ level = atoi(htex.ap); alevel = level + pp->level + '0'; BUF_AppendItem(bindex, char, &alevel); BUF_AppendString(bindex, "}{"); tex_getparm(2); /* Topic */ BUF_AppendString(bindex, htex.ap), BUF_AppendString(bindex, "}{"); l = tex_getvparm(3); /* Explanation */ BUF_AppendItems(bindex, char, htex.ap, l); BUF_AppendString(bindex, "}{"); l = tex_getvparm(4); /* Context */ BUF_AppendItems(bindex, char, htex.ap, l); BUF_AppendString(bindex, "}{"); BUF_AppendString(bindex, pp->filename); BUF_AppendString(bindex, "}{"); help_tell(); fpos = pp->pos; p = ltoa(fpos); BUF_AppendString(bindex, p); BUF_AppendString(bindex, "}{"); ReadNext(); p = ltoa(pp->pos - fpos); BUF_AppendString(bindex, p); BUF_AppendItems(bindex, char, "}", 1); BUF_AppendItems(bindex, char, zeroes, 4-(bindex->used&3)); LinkIndex(o); break; case '@': /* \HelpLoad */ tex_getparm(1); /* Level */ level = atoi(htex.ap); tex_getparm(2); /* FileName */ help_tell(); help_load(htex.ap, level); break; } return(0); } static int compare(str1, str2, len) /*++++++++++++++++++++++++++++++ .PURPOSE Compare two strings of equal length, case insensitive. Note that the {} are equated ti zero. .RETURNS Sign of (str1-str2), i.e. 0 for identical strings, negative number if str1str2. .REMARKS The `}' is smaller than any other character. ----------------------------------------------*/ unsigned char *str1; /* IN: string to compare */ unsigned char *str2; /* IN: second string */ int len; /* IN: length of strings */ { register unsigned char *p, *pe; register int index; index = 0; for (p = str1, pe = str1+len; p < pe; p++, str2++) if (index = (toupper(*p) - toupper(*str2))) break; if (index) { if (*p == '}') /* Ending brace */ index = -1; if (*str2 == '}') index = 1; } return(index); } PGM(THCreate) /*========================================================================== * Main Program *==========================================================================*/ /*+++ .PURPOSE Modify the File to add an Index .RETURNS to OS. .REMARKS Parameter is FileName. Option -s to sort, -v for Verbose -l to list files. ---*/ { MID_STATIC char definitions[] = "\\def\\Help#4{\\action{H.}}\\def\\HelpLoad#4{\\action{H@}}\ \\def\\HelpIndex#7{\\action{H:}}\\def\\fromHelpFiles#1{\\action{H+}}"; char *filename, *p; int l; INDEX *pi; MID_STATIC char *header[] = {"\ %+++++++++++++++\n%.IDENTIFICATION ", "\n\ %.AUTHOR\t ESO - IPG (for problems: Span ESOMC1::FRANCOIS)\n\ %.LANGUAGE \t TeX-like\n\ %.KEYWORDS\t Hierarchical Help using TermWindows\n\ %.ENVIRONMENT\t TermWindows\n\ %.VERSION 3.1\t ", ": Generated by THCREATE\n\ %.COMMENTS\t This index improves the access to the topics.\n\ %---------------\n%\n%\t Definitions from included files\n%\n","\ %\n%\t Complete Index\n%\n"}; SaveParms(); if (GetParmString("-help")) { help(); return; } htex.output = act0, htex.action = acti; TeX_Execute(&htex, definitions, sizeof(definitions)-1); /* Buffers */ bpiece = BUF_Open(PIECE, 10, 10); bindex = BUF_Open(char, 1024, 1024); bstart = BUF_Open(char, 1024, 1024); /* Get File Name */ if_not(filename = GetNextParm()) { synopsis (); return; } osort = GetOption('s'); olist = GetOption('v') | GetOption('l'); /* Load Help file */ if_not (help_load(NameFile(filename, ".tex"), 0)) FINISH; BUF_AppendItems(bstart, char, FROM_MACRO, sizeof(FROM_MACRO)-1); BUF_AppendString(bstart, "{ }\n"); while(pp) { if (ReadNext() == EOF) { fi_close(pp->fid); if (olist) LOG_ED_STRING("File processed: ", pp->filename); pp = BUF_UnstackItem(bpiece, PIECE); continue; } l = ReadBuffer(pp->fid); TeX_Execute(&htex, buf, l); } if(error_flag) { ERROR("Index not created"); return; } /* Check if something was found! */ if (bindex->used == 0) /* Nothing ! */ { ERROR("Input file has no \\Help or \\HelpLoad..."); ERROR("Index Not Created"); return; } /* Copy now the 3 buffers */ p = GetNextParm(); /* Output file name */ if_not(p) p = ParseFile(filename, _PATH_|_FILE_); fout = fi_open(NameFile(p, ".ind"), WRITE); /* Add the Header */ fi_put (fout, header[0]); fi_put (fout, p); /* File Name */ fi_put (fout, header[1]); ed_t (time_buf, time_pic, oshtime()); fi_put (fout, time_buf); /* File Name */ fi_put (fout, header[2]); fi_write(fout, bstart->buf, bstart->used); fi_put (fout, header[3]); pi = (INDEX *)(bindex->buf); while(1) { fi_puts(fout, pi->text); if (pi->next == (-1)) break; pi = (INDEX *)(bindex->buf + pi->next); } fi_close(fout); FIN: return; } /*========================================================================== * ReadBuffer *==========================================================================*/ int ReadBuffer(fid) /*+++ .PURPOSE Read NREC lines from current input file. .RETURNS Length of buffer .REMARKS ---*/ int fid; /* IN: File identifier */ { char *p; int i, k; ENTER("+ReadBuffer"); pos_in_file[0] = fi_tell(fid); for (i=0, p=buf; ipos = fi_tell(pp->fid); st = fi_gets(pp->fid, buf, sizeof(buf)); if (st == NOK) { ERR_ED_STRING("Bad record in ", pp->filename); error_flag = 1; st = EOF; } if (st == EOF ) break; if (buf[0] == '%') continue; /* Comment */ l = strlen(buf); if (l == 0) continue; if (oscindex(buf, l, HELP_MACRO, sizeof(HELP_MACRO)-1) < l) break; /* \Help found */ if (oscindex(buf, l, FROM_MACRO, sizeof(FROM_MACRO)-1) < l) break; /* \Help found */ buf[l++] = '\n'; if (pp->phase) BUF_AppendItems(bstart, char, buf, l); } if (st == OK) fi_seek(pp->fid, pp->pos, FILE_START); EXIT(st); } /*========================================================================== * help_tell *==========================================================================*/ int help_tell() /*+++ .PURPOSE Tell were we're in the current input file .RETURNS OK / NOK .REMARKS ---*/ { int l, nn, i; ENTER("help_tell"); l = tex_tell(); for (i=0, nn=0; ipos = pos_in_file[nn]; fi_seek(pp->fid, pp->pos, FILE_START); EXIT(OK); } /*========================================================================== * LinkIndex *==========================================================================*/ int LinkIndex(o) /*+++ .PURPOSE Add new index .RETURNS OK .REMARKS Sorted only if osort is on. ---*/ int o; /* IN: Position in bindex buffer */ { INDEX *pi, *pip, *p; int l, st, brace; char level; ENTER("LinkIndex"); pi = (INDEX *)(bindex->buf + o); pi->previous = bindex->offset; pi->next = -1; /* End of chain */ bindex->offset = o; if (o == 0) FINISH; /* First element */ pip = (INDEX *)(bindex->buf + pi->previous); /* Last */ if_not(osort) /* Don't sort */ { pip->next = o; FINISH; } /* Modify links to have result sorted */ brace = oscloc(pi->text+14, 80, '}'); /* To get a correct sort */ pi->text[14+brace] = '\0'; level = pi->text[11]; /* Find first previous record with same level */ pip = Previous(pip, level); /* If new topic comes after previous one, move forwards */ while ((pip->text[11] == level) && (compare(pi->text, pip->text, 94) > 0)) { p = Next(pip, level); if (p) pip = p; else break; } /* If new topic comes before previous one, move backwards */ while ((pip->text[11] == level) && (compare(pi->text, pip->text, 94) < 0)) { pip = (INDEX *)(bindex->buf + pip->previous); pip = Previous(pip, level); } pip = Last(pip, level); /* Insert new topic just after this one */ pi->text[14+brace] = '}'; pi->previous = ((char *)pip) - bindex->buf; pi->next = pip->next; pip->next = o; if (pi->next != (-1)) { p = (INDEX *)(bindex->buf + pi->next); p->previous = o; } FIN: EXIT(OK); }