1
/*===========================================================================
2
Copyright (C) 1988-2009 European Southern Observatory (ESO)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; either version 2 of
7
the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public
15
License along with this program; if not, write to the Free
16
Software Foundation, Inc., 675 Massachusetss Ave, Cambridge,
19
Corresponding concerning ESO-MIDAS should be addressed as follows:
20
Internet e-mail: midas@eso.org
21
Postal address: European Southern Observatory
22
Data Management Division
23
Karl-Schwarzschild-Strasse 2
24
D 85748 Garching bei Muenchen
26
===========================================================================*/
28
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31
.IDENTIFICATION thelp.c
32
.AUTHOR Francois Ochsenbein [ESO-IPG]
34
.KEYWORDS Hierarchical Help using TermWindows
35
.ENVIRONMENT TermWindows
38
.COMMENTS The module uses actions starting with `H'
39
The \Help and \HelpLoad macros contain four parameters:
42
\item The level, a number starting from 0 up to 9
43
\item The topic, or filename for HelpLoad
44
\item A short explanation, for survey purposes.
45
\item The context specification, as a set of words separated by commas.
48
A located topic starts {\em just after} the {\tt\b Help} found macro.
52
The \HelpIndex has 7 parameters:
55
\item The level, a number starting from 0 up to 9
56
\item The topic, or filename for HelpLoad
57
\item A short explanation, for survey purposes.
58
\item The context specification, as a set of words separated by commas.
59
\item The name of the file where the help is included
60
\item The starting position just following the \b Help
61
\item The number of bytes to load.
66
.VERSION 1.0 13-May-1988: Creation
67
.VERSION 1.1 07-Nov-1988: Possibility of an index with macro \HelpIndex
68
.VERSION 1.2 05-Dec-1988: Check if \Help commented out...
69
.VERSION 1.3 20-Jan-1989: th_set: allows NULL pointer without crash...
70
.VERSION 1.4 03-Mar-1989: Corrected bug signaled by Jeannine:
71
\Help is always triggered, even if it's commented...
72
.VERSION 1.5 29-Mar-1989: Default extension for files = .tex
73
.VERSION 1.6 23-May-1989: Modified documentation
74
.VERSION 1.7 22-Jun-1989: Modified th_set: ONLY ADDRESSES are kept...
75
.VERSION 1.8 05-Apr-1990: Modified PromptKey: The prompt "? for subtopics"
76
appears only if subtopics do exist..
77
.VERSION 1.9 09-Sep-1990: Bug corrected in load_file: fname is saved
78
in a independant location.
79
.VERSION 1.91 21-Nov-1990: Routine th_setsep to define the list
80
of separators between topics.
81
.VERSION 2.0 04-Dec-1990: Allow Several Indexes to be Merged.
83
.VERSION 2.1 07-Jun-1991: Added th_loc routine
86
--------------------------------------------------------------------------*/
88
#define DEBUG 0 /* For debugging only */
93
#define PM_LEVEL LEVEL_TX
94
#define MAX_TOPIC 31 /* Maximal length for topic comparison */
104
#include <proto_os.h>
106
#define reply_size 40
107
#define default_ext ".tex"
108
#define FileDate(f) fi_date(NameFile(f,default_ext))
110
#define _REDISPLAY_ 10
113
#define _BAD_INDEX_ -3
116
extern int mm_free();
118
extern int tv_bell(), tv_dim(), tv_getcc();
120
extern int fi_open(), fi_gets(), fi_close(), fi_load();
122
extern int ty_close(), ty_display(), ty_end(), ty_mdisplay();
123
extern int ty_more();
125
extern int tw_fill(), tw_attr(), tw_uattr(), tw_r(), tw_goto(), tw_rule();
126
extern int tw_st(), tw_uflag(), tw_chars(), tw_copw(), tw_flags();
127
extern int tw_uw(), tw_write(), tw_il(), tw_clear(), tw_dc();
128
extern int tw_nl(), tw_upw(), tw_uc(), tw_mvc(), tw_copy();
129
extern int tw_mrule(), tw_cus(), tw_gc2(), tw_close(), tw_cur();
130
extern int tw_cline(), tw_home(), tw_tra(), tw_wa();
131
extern int tw_awhere(), tw_agoto(), tw_gc1(), tw_get1(), tw_wf();
133
extern int pm_enter(), pm_iexit(), pm_tr2(), pm_ed_i(), pm_ed_trace();
135
extern int eh_ed_i(), eh_ed_as(), eh_put1(), eh_put();
137
extern int tex_exec(), tex_unit(), tex_getparm(), tex_mexec(), tex_tell();
138
extern int tex_input(), tex_load(), tex_list(), tex_getvparm();
140
extern int tx_jr(), tx_jc(), tx_justify();
141
extern int tx_display(), tx_option();
142
extern int tx_fdisplay(), tx_file(), tx_mdisplay();
145
static int TheDoc = 0; /* DOC Folder */
146
static WINDOW *helpw = NULL_WINDOW; /* Small ^G Window */
147
static TeX *htex = NULL_PTR(TeX);
153
} PIECE; /* Piece of text to use with DisplayArray */
155
static PIECE loaded_file; /* Just loaded file */
159
char level; /* Level 0-9 */
160
char flag; /* '@' to load a file */
161
short ltopic; /* Proposed topic length*/
162
char *topic; /* The topic address */
163
char *got_topic; /* The got topic address*/
164
char *hpos; /* Where exactly is \Help */
165
char *pos; /* Where exactly in current piece */
166
int piece; /* Position in PIECE */
167
int ofile; /* Filenames Position */
168
long fpos; /* Position in File */
169
int ltext; /* Text length */
173
int ofile; /* Filenames Position */
174
long fpos; /* Position in File */
175
int ltext; /* Text length */
176
char text[1]; /* Filename + Text */
179
static LOADED *loaded = NULL_PTR(LOADED);
182
topics[10] = { /* Current topic to look for */
183
{'0', 0, 0, (char *)0, (char *)0, (char *)0, 0}, {'1'}, {'2'},
184
{'3'}, {'4'}, {'5'}, {'6'}, {'7'}, {'8'}, {'9'}};
188
static char *located_help = (char *)0; /* Used by th_loc */
189
static char help_flag; /* Used for communication with th_act */
190
static char level_found; /* Used for communication with th_act */
191
static char reply[reply_size];
192
static char blank = ' ';
193
static int subtopics = 0; /* Used for communication with EdTop */
195
static TWHELP help; /* Contains the Help definitions: windows + buffer */
197
static BUFFER *list; /* This buffer collects title + subtopics */
198
static BUFFER *filenames; /* This buffer collects filenames */
199
static char *tit3 = (char *)0;
200
static int ltit3 = 0;
202
static unsigned char sep_table[256];
203
static char *sep_top = (char *)0; /* Default Separators */
205
#define FINISH goto FIN
207
#define HELP_MACRO "\\Help"
208
#define HELP_INDEX "\\HelpIndex"
209
#define default_title " Help"
211
/* MONITOR(TXHELP); */
214
/*==========================================================================
216
*==========================================================================*/
217
static int myOpenDocText(str,len)
219
.PURPOSE Interface to OpenDocText
220
.RETURNS NOK if not completely displayed / OK otherwise
222
char *str; /* IN: TeX string to display */
223
int len; /* IN: Length of Text */
226
TheDoc = OpenDocText(help.w[1], str, len);
227
RaiseWindow(help.w[1]);
228
return(atLastDocPage(TheDoc));
231
static int myOpenDocArray(str,n)
233
.PURPOSE Interface to OpenDocText
234
.RETURNS NOK if not completely displayed / OK otherwise
236
char **str; /* IN: TeX strings to display */
237
int n; /* IN: How many strings */
240
TheDoc = OpenDocArray(help.w[1], str, n);
241
RaiseWindow(help.w[1]);
242
return(atLastDocPage(TheDoc));
245
static int get_tit3()
247
.PURPOSE Get the 3rd parameter of Title
248
.RETURNS Length of Text
254
l3 = tex_getvparm(3); /* The short explanation */
255
p = (l3 > 0 ? htex->ap : "");
257
if (l3 >= ltit3) /* Must expand */
258
ltit3 = 1 + (l3|7), tit3 = MEM_EXP(char, tit3, ltit3);
259
oscopy (tit3, p, l3);
264
/*==========================================================================
266
*==========================================================================*/
267
static int act0(str, len)
269
.PURPOSE Action Routine to execute definitions in a help file
270
.RETURNS len (does nothing)
273
char *str; /* IN: Action string, should start with H */
274
int len; /* IN: Length of action string */
279
/*==========================================================================
281
*==========================================================================*/
282
static int CheckContext()
284
.PURPOSE Checks if the context is OK
286
.REMARKS Context is a string in help; if the 4th parameter of \Help
287
includes something, the same string must be in help.context
295
tex_getparm(4); /* Get 4th parameter */
296
if (*(htex->ap) == EOS) /* No 4th parameter => always valid */
299
/* Check if 4th parameter includes context */
300
p = htex->ap + stritem(htex->ap, help.context, "\t, ");
301
/* Separators may be , blank tab */
302
if (*p == EOS) status = NOK;
308
/*==========================================================================
310
*==========================================================================*/
311
static int th_act(str, len)
313
.PURPOSE Action Routine to interpret the `\Help' Macros
314
.RETURNS 0 (must stop)
315
.REMARKS Context checking and \HelpIndex check.
317
char *str; /* IN: Action string, should start with H */
318
int len; /* IN: Length of action string */
321
if (*str != 'H') FINISH;
325
if_not(CheckContext())
328
tex_getparm(1); /* Indicates Level */
330
if ((help.indexed == 0) && (str[1] == ':')) FINISH;
332
level_found = '0' + atoi(htex->ap);
333
help_flag = str[1]; /* @ for HelpLoad */
335
tex_getparm(2); /* Get argument = Topic or File Name */
341
/*==========================================================================
343
*==========================================================================*/
344
static int th_out(str, len)
346
.PURPOSE Output Routine to interpret the `\Help' Macros
347
.RETURNS 0 (must stop)
350
char *str; /* IN: Action string, should start with H */
351
int len; /* IN: Length of action string */
353
return(0); /* Must stop, should NEVER be called !!! */
356
/*==========================================================================*/
357
static int next_help(str, len)
359
.PURPOSE Locate next \Help
360
.RETURNS Offset found
361
.REMARKS Check if not in comment ...
363
char *str; /* IN: Text in which locate \Help */
364
int len; /* IN: Length of str */
369
b = str, be = b + len;
371
{ b += oscindex(b, be-b, HELP_MACRO, sizeof(HELP_MACRO)-1);
373
/* Check if it's not a comment... */
374
is_a_comment = FALSE;
375
for (bc = b; (bc > str) && (*bc != '\n'); bc--)
377
if ((*bc == '%') && (*(bc-1) != '\\')) /* It's a comment */
378
{ is_a_comment = TRUE; break; }
380
if (is_a_comment) b += sizeof(HELP_MACRO) -1;
386
/*==========================================================================
388
*==========================================================================*/
389
static int which_help(str, len, topic)
391
.PURPOSE interpret the next Help as (level+Text)
392
.RETURNS Offset found
393
.REMARKS The actions th_act are assumed to be in effect.
395
char *str; /* IN: Text in which locate \Help */
396
int len; /* IN: Length of str */
397
char *topic; /* OUT: Level + Topic, assumed size MAX_TOPIC+1 */
401
p = str; pe = p + len;
403
p += next_help(p, pe-p);
405
tex_exec(htex, p, pe-p);
406
*topic = level_found;
407
strncopy(topic+1, MAX_TOPIC, htex->ap);
412
static PIECE *MergeHelp(p1, q2)
414
.PURPOSE Merge two loaded helps into a single index
415
.RETURNS The merged piece
416
.REMARKS Works properly only for Sorted Indexed Helps. p1 and q2 are freed.
418
PIECE *p1; /* IN: First Help tree */
419
PIECE *q2; /* IN: Second Help tree */
421
char *b1, *b2, *c1, *c2;
422
char top1[MAX_TOPIC+1], top2[MAX_TOPIC+1];
424
int (*old_act)(), (*old_out)();
427
/* Allocate first the new Piece */
429
old_act = htex->action, old_out = htex->output;
430
htex->action = th_act, htex->output = th_out;
431
i = (p1->end - p1->start) + (q2->end - q2->start);
432
p.start = MEM_GET(char, i); p.end = p.start;
434
b1 = c1 = p1->start; b2 = c2 = q2->start;
435
c2 += which_help(c2, q2->end - c2, top2); if (top2[0] != '0') FINISH;
437
c2 += which_help(c2, q2->end - c2, top2); if (top2[0] != '1') FINISH;
438
b2 = c2; /* Ignore 2nd help tree until first topic */
439
c1 += which_help(c1, p1->end - c1, top1); if (top1[0] != '0') FINISH;
441
c1 += which_help(c1, p1->end - c1, top1); if (top1[0] != '1') FINISH;
442
p.end += oscopy(p.end, b1, c1-b1);
444
while ( (c1 < p1->end) && (c2 < q2->end)) {
445
i = top2[0] - top1[0];
446
if (i == 0) i = studiff(top1, top2);
447
if (i <= 0) { /* top1 comes first */
449
c1 += which_help(c1, p1->end - c1, top1);
450
p.end += oscopy(p.end, b1, c1-b1);
453
if (i >= 0) { /* top2 comes first */
455
c2 += which_help(c2, q2->end - c2, top2);
456
if (i) p.end += oscopy(p.end, b2, c2-b2);
462
p.end += oscopy(p.end, b1, p1->end - b1); /* Append rest */
463
p.end += oscopy(p.end, b2, q2->end - b2); /* Append rest */
464
MEM_FREE(p1->start); MEM_FREE(q2->start);
465
htex->action = old_act, htex->output = old_out;
470
/*==========================================================================
471
* Reset anything at specified level
472
*==========================================================================*/
473
static int Reset(lev)
475
.PURPOSE Reset the list of subtopics to specified level:
476
title and starting point of subtopics.
480
int lev; /* IN: The current level */
485
/* First, reset the Title in the List buffer */
487
for (b = list->buf, i = 0; i <= lev; i++)
488
b += oscloc(b, list->offset, ' ') + 1;
489
list->offset = b - list->buf;
490
list->used = list->offset;
492
/* Second, reset starting point of subtopic */
496
{ topics[i].piece = topics[lev].piece;
497
topics[i].pos = topics[lev].pos;
504
/*==========================================================================
506
*==========================================================================*/
507
static int LocHelp(t)
509
.PURPOSE Locate the next `\Help' macro
510
.RETURNS Level (t->level) as a number / -1 if end found
511
.REMARKS On return, t->pos AND t->hpos point to the text starting with \Help
512
The context is checked.
513
If the index is not loaded, \HelpIndex is ignored.
515
TOPIC *t; /* MOD: Starting search point */
519
int (*old_act)(), (*old_out)();
522
t->got_topic = NULL_PTR(char);
523
old_act = htex->action, old_out = htex->output;
524
htex->action = th_act, htex->output = th_out;
527
flag = 0; /* Indicates starting of a new piece */
529
while(1) /* Loop over pieces */
530
{ if (t->piece >= help.buf->used) FINISH;
531
p = (PIECE *)(help.buf->buf + t->piece);
532
if (flag) t->pos = p->start;
534
if (t->pos >= p->end)
535
{ t->piece += sizeof(PIECE);
539
t->pos += next_help(t->pos, p->end - t->pos);
540
if (t->pos >= p->end) continue; /* Not found */
542
/* Something starting with \Help found
543
* Interpret with the TeX parser --
544
* but be sure it's not a comment! */
547
for (st = t->pos; st > p->start; st--)
548
if ( (*st == '\n') || (*st == '%')) break;
550
if (*st == '%') /* It's a comment */
551
{ t->pos += 1; continue; }
554
tex_exec(htex, t->pos, p->end - t->pos);
555
if (level_found) break;
559
/* Here if a \Help macro found: level is stored as level_found,
560
* and the found topic / filename as htex->ap.
563
t->level = level_found;
566
t->got_topic = htex->ap;
567
got = level_found - '0';
570
htex->action = old_act, htex->output = old_out;
574
/*==========================================================================
575
* Sorry (no help available...)
576
*==========================================================================*/
577
static int Sorry(asked, exit_option)
579
.PURPOSE Display the "Sorry" message ...
583
char *asked; /* IN: What was asked for and not found */
584
int exit_option; /* IN: 1 to log error, 0 to output on window */
586
static char *sp[] = {"Sorry, no such", NULL_PTR(char)};
590
ERR_ED_STRING("Topic not found: ", asked);
592
{ sp[1] = help.title;
593
ClearWindow(help.w[0]);
594
SetAttr(help.w[0], _BOLD_|_BLINK_|_REVERSE_);
595
for (i = 0; i < ITEMS(sp); i++)
596
Put(help.w[0], sp[i]);
597
SetAttr(help.w[0], _NORMAL_);
598
WriteBinary(help.w[0], list->buf, list->offset);
599
SetAttr(help.w[0], _UNDERSCORE_);
600
Put(help.w[0], asked);
601
SetAttr(help.w[0], _NORMAL_);
603
RaiseWindow(help.w[0]);
609
/*==========================================================================
611
*==========================================================================*/
612
static int BadIndex()
614
.PURPOSE Display a message if index is too old. Execute the bad_index.
616
.REMARKS Replace \HelpIndex by \HelpLoad and replace arg. 2,3,4 by blanks
621
ERR_ED_STRING("File was modified: ", htex->ap);
623
ClearWindow(help.w[0]);
624
SetAttr(help.w[0], _BOLD_|_BLINK_|_REVERSE_);
625
PutCentered(help.w[0], " Index Invalid ");
626
SetAttr(help.w[0], _NORMAL_);
627
RaiseWindow(help.w[0]);
629
/* Modify \HelpIndex{0} to \HelpLoad{0} */
632
topc.pos = ((PIECE *)(help.buf->buf))->start;
634
oscopy(topc.pos+5, "Load ", 5);
635
topc.pos += 1 + oscloc(topc.pos, 200, '{');
637
{ topc.pos += oscloc(topc.pos, 200, '{');
639
oscfill(topc.pos, oscloc(topc.pos, 200, '{'), ' ');
642
if (help.bad_index) oshcmd(help.bad_index,
643
NULL_PTR(char), NULL_PTR(char), NULL_PTR(char));
648
/*==========================================================================
650
*==========================================================================*/
651
static int oFile(filename)
653
.PURPOSE Save filename in `filenames' buffer.
654
.RETURNS Position in `filenames' buffer where file name is saved.
655
.REMARKS Check if filname already exists. The default extension is added.
657
char *filename; /* IN: File to save */
660
char *p, *complete_filename;
662
complete_filename = NameFile(filename, default_ext);
663
l = strlen(complete_filename) + 1;
665
for (o=0; o < filenames->used; )
666
{ p = filenames->buf + o;
667
if (oscomp(p, complete_filename, l) == 0) break;
671
/* If not yet existing, add in buffer */
673
if (o >= filenames->used)
674
{ o = filenames->used;
675
BUF_AppendItems(filenames, char, complete_filename, l);
681
/*==========================================================================
683
*==========================================================================*/
684
static int load_file(filename)
686
.PURPOSE Load a file in a new allocated piece of memory.
687
This piece is detailed in the static loaded_file.
688
.RETURNS --- OK (no remaining text)
689
--- NOK (file not found)
690
.REMARKS Execute definitions in the loaded file, until the first \Help.
691
Default extension is .tex
693
char *filename; /* IN: File to load */
699
int (*old_act)(), (*old_out)();
701
/* Open first the File. If fails, return */
704
fname = strsave(NameFile(filename, default_ext));
706
fs = fi_size(fname); /* Size of File */
708
if_not(fid = fi_open(fname, READ|RECORD_MODE))
714
/* Allocate memory to copy file */
716
if_not ( b = MEM_GET(char, l))
719
loaded_file.start = b;
720
loaded_file.end = b + l;
722
/* Read file until first \Help */
724
for (fs=0; fi_gets(fid, b, loaded_file.end - b) > 0; fs = fi_tell(fid))
725
{ if (*b == '%') continue; /* Comment line... */
727
if (*(b + oscindex(b, lb, HELP_MACRO, sizeof(HELP_MACRO)-1)))
734
/* Execute the TeX definitions before the first \Help */
736
old_act = htex->action, old_out = htex->output;
737
htex->action = act0, htex->output = act0;
738
TeX_Execute(htex, loaded_file.start, b - loaded_file.start);
739
htex->action = old_act, htex->output = old_out;
741
/* Load the Remaining part of the File */
743
l = (loaded_file.end - loaded_file.start) - fs;
744
MEM_FREE(loaded_file.start);
745
b = MEM_GET(char, l);
746
loaded_file.start = b;
747
loaded_file.end = b + fi_load(fname, fs, b, l);
752
strfree(fname); /* Release the memory */
756
/*==========================================================================
758
*==========================================================================*/
759
static int load_help(filename, start_level)
761
.PURPOSE Load a new help file (triggered by \HelpLoad).
762
It modifies the levels of the loaded file.
763
.RETURNS OK / NOK (something failed)
766
char *filename; /* IN: File to load */
767
char start_level; /* IN: Lowest level */
773
if_not(load_file(filename)) FINISH;
776
if (start_level <= '0') FINISH;
778
b = loaded_file.start;
779
i = start_level - '0';
781
while (b < loaded_file.end)
782
{ b += next_help(b, loaded_file.end - b);
783
b += oscspan((unsigned char *)b, loaded_file.end - b, _ALPHA_|_PUNCT_|_SPACE_,
784
main_ascii); /* Skip until digit */
785
if (b >= loaded_file.end) break;
786
*b += i; /* Modify the Level */
793
/*==========================================================================
795
*==========================================================================*/
796
static int help_load(t)
798
.PURPOSE Treats the `\HelpLoad{lev}{filename}' macro
799
.RETURNS OK / NOK (something failed)
800
.REMARKS Filename is given as t->got_topic, level as t->level
802
TOPIC *t; /* IN: The current topic */
808
/* 1. The filename is in t->got_topic; load it */
812
b = t->pos + tex_tell(); /* Position just following the \Help */
813
t->flag = '.'; /* File is now loaded */
815
if_not(load_help(t->got_topic, t->level)) FINISH;
817
/* 2. Allocate two new PIECE items in help:
818
* - 1 for the new file
819
* - 1 for the second part following the \HelpLoad
820
* These items must be located where we are.
823
help.buf->offset = t->piece;
824
l = help.buf->used - help.buf->offset; /* Length of 2nd part */
826
if_not(BUF_AllocateItems(help.buf, PIECE, 2)) FINISH;
828
p = BUF_ItemPosition(help.buf, PIECE);
829
oscopy((char *)(p+2), (char *)p, l); /* Duplicates current piece */
831
/* 3. Modify the current length (stops just before \HelpLoad */
835
/* 4. Insert the loaded file */
839
/* 5. Modify the 2nd part (starts just after \HelpLoad */
851
/*==========================================================================
853
*==========================================================================*/
854
static int LocTop(lev, opt, optl)
856
.PURPOSE Locate the topic of specified level
857
.RETURNS Lev if found - another number otherwise
858
.REMARKS Comparison is case insensitive. On return, the current text
859
starts just after the \Help.
861
int lev; /* IN: Level to look for */
862
int opt; /* IN: 1 to add topic in title / 2 for Explanation */
863
int optl; /* IN: 1 to locate file with text / 0 otherwise */
867
for (topc = topics[lev]; (i = LocHelp(&topc)) >= lev; topc.pos += 1)
868
{ if (i > lev) continue;
869
/* Check if a file was found. If yes, load it */
870
if (topc.flag == '@')
874
if (osccomp(topc.topic, topc.got_topic, topc.ltopic) == 0)
875
break; /* Topic is found */
878
if (i != lev) return(i); /* Not Found */
880
if (opt & 2) get_tit3();
881
if (opt & 1) { /* Modify the title */
882
list->used = list->offset;
883
BUF_AppendString(list, topc.got_topic);
884
BUF_AppendItem(list, char, &blank);
885
list->offset = list->used ;
888
if ((topc.flag == ':') && (optl)) /* From Index: Load Parameters */
889
{ tex_getparm(6); topc.fpos = atol(htex->ap); /* Start of file */
890
tex_getparm(7); topc.ltext = atoi(htex->ap); /* Length in file */
891
tex_getparm(5); topc.ofile = oFile(htex->ap); /* Filename */
894
topc.pos += tex_tell(); /* Position after the \Help macro */
895
topics[lev] = topc; /* Copy found topic */
900
/*==========================================================================
902
*==========================================================================*/
903
static int GetSubTop(lev)
905
.PURPOSE Locate the subtopics of specified level
906
.RETURNS Number of subtopics
909
int lev; /* IN: Level of Topic */
912
static char ed[] = "\\CheckCols{00}\05\01";
916
BUF_AppendString(list,"\\vfill\n\\Rule\n");
919
for (n = 0; LocTop(i, 0, 0) == i; n++)
920
{ len = strlen(topics[i].got_topic);
921
ed[11] = '0' + len/10;
922
ed[12] = '0' + len%10;
923
BUF_AppendItems(list, char, ed, sizeof(ed)-1);
924
BUF_AppendItems(list, char, topics[i].got_topic, len);
925
BUF_AppendItems(list, char, "\05\02 \\tab", 7);
928
if (n == 0) list->used = list->offset; /* No subtopics */
929
else BUF_AppendItems(list, char, "\n\\SkipLine", 10);
934
/*==========================================================================
936
*==========================================================================*/
938
static WINDOW *CreateHelpWindow()
940
.PURPOSE Create the customized help window
941
.RETURNS The window created
947
static char help_1[] = "Answer by non-ambiguous (sub)topic(s)\
948
separated with blanks, or the keys:\n\\SkipLine\n\\begin{table}{c p}{3}\
949
{\\bf?}&to redisplay previous topic\\\\\
950
{\\bf\\b}&to list a summary\\\\\
951
{\\bf Ret}&to return to previous topic\\\\ ";
952
static char help_2[] = "{\\bf \\^A} & to Exit\\\\ ";
953
static char help_3[] = "\
954
\\end{table}\n\\SkipLine\nTopic names are {\\Vu case insensitive}.";
955
static char *help_text[] = {
956
help_1, help_1+sizeof(help_1)-1,
957
help_2, help_2+sizeof(help_2)-1,
958
help_3, help_3+sizeof(help_3)-1
961
/* Create Help Window */
962
help_2[7] = '@' + GetControl(TW_cc_EOF);
963
if (helpw = OpenWindow("Help Topics", 0, -29, -18, 29, _REVERSE_,
964
_TITLE_|_BORDER_|_BORDER2_|_DISPLAY_, 0))
965
DisplayArray(helpw, help_text, ITEMS(help_text)/2);
967
static char help_text[] = "\
968
Answer by non-ambiguous (sub)topics\n\
969
separated with blanks, or the keys\n\n\
970
\017^\04\016 to Exit\n\
971
\017Ret\016 to return to previous topic\n\
972
\017\\\016 to list a Summary\n\
973
\017?\016 to redisplay previous topic\n\
974
\017^B\016 to redisplay previous page\n\
975
\017.\016 to display one more line\n\n\
976
Topic names are \017case insensitive\016";
978
help_text[strloc(help_text, '\04')] = '@' | GetControl (TW_cc_EOF );
979
helpw = AdjustedWindow("Help on Help", help_text,
980
_REVERSE_, _BORDER_|_TITLE_, _UPRIGHT_);
986
static int Prompt1(opt)
988
.PURPOSE Prompt for Continuation
989
.RETURNS -1 to stop / _SUMMARY_ to list the Summary (triggered by \) /
990
_REDISPLAY_ to redisplay the parent topic /
991
_PROMPT_ when just Return was entered /
992
OK if a subtopic was typed in
995
int opt; /* IN: 1 if Bottom Reached / 2 for Exit with Q */
997
int status, at_bottom, old_pos;
998
static char specials[] = " \02\04\06\025.\r?\\"; /* Those stop input */
1000
/* Special Keys are ^B ^D ^F ^U */
1001
at_bottom = opt & 1;
1003
old_pos = GetPosition(help.w[2]);
1004
while (status == 0) {
1005
SetPosition(help.w[2], old_pos);
1006
ClearRight(help.w[2]);
1008
status = GetKey1(help.w[2], reply, specials);
1009
if (status > 0) status = 0;
1011
else status = Gets1(help.w[2], reply, sizeof(reply), specials);
1012
if ((status == OK) && (reply[0] == EOS))
1013
status = 0, reply[0] = ' ';
1014
if (status == 0) switch(reply[0]) {
1015
case '\\': status = _SUMMARY_; break;
1016
case '?': status = _REDISPLAY_; break;
1017
case '\r': case EOS:
1018
if (at_bottom) status = _PROMPT_;
1019
else reply[0] = ' '; break;
1021
if (status) continue;
1022
status = MoreDoc(TheDoc, reply[0]);
1023
at_bottom = atLastDocPage(TheDoc);
1024
if (status == NOK) Bell();
1025
if (status == OK) status = 0;
1029
ClearWindow(help.w[2]);
1030
return(status == 0 ? OK : status);
1033
static int Prompt(lev)
1035
.PURPOSE Inquire for a Topic
1036
.RETURNS -1 to stop / _SUMMARY_ to list the Summary (triggered by \),
1037
_REDISPLAY_ to redisplay the parent topic.
1038
.REMARKS A special Help window is used, in case of Control-K
1040
int lev; /* IN: Level / -1 for Continuation */
1044
RaiseWindow(help.w[2]);
1045
ActiveWindow(help.w[2]);
1046
SetAttr(help.w[2], _REVERSE_);
1049
{ WriteBinary(help.w[2], list->buf, list->offset);
1050
Put(help.w[2], "Subtopic ? ");
1052
else Put(help.w[2], " Topic ? ");
1054
SetAttr(help.w[2], _NORMAL_);
1055
WriteBinary(help.w[2], &blank, 1);
1056
status = Prompt1(1);
1061
static int PromptKey(opt)
1063
.PURPOSE Prompt for Continuation
1064
.RETURNS -1 to stop / _SUMMARY_ to list the Summary (triggered by \),
1065
_REDISPLAY_ to redisplay the parent topic.
1068
int opt; /* IN: non-zero to display the ? */
1072
RaiseWindow(help.w[2]);
1073
ActiveWindow(help.w[2]);
1074
SetAttr(help.w[2], _REVERSE_);
1075
Put(help.w[2], " <Return> to continue");
1076
Put(help.w[2], ", ");
1077
SetAttr(help.w[2], _REVERSE_|_BOLD_);
1078
opt1 = 0; /* Option for Prompt1 */
1080
Put(help.w[2], "?");
1081
SetAttr(help.w[2], _REVERSE_);
1082
Put(help.w[2], " for list of subtopics");
1085
Put(help.w[2], "q");
1086
SetAttr(help.w[2], _REVERSE_);
1087
Put(help.w[2], " to quit");
1088
opt1 = 2; /* Allow to Exit with Q */
1091
Put(help.w[2], " ");
1092
SetAttr(help.w[2], _NORMAL_);
1093
status = Prompt1(opt1);
1098
/*==========================================================================
1100
*==========================================================================*/
1101
static int GetSummary(lev)
1103
.PURPOSE Prepare complete list of all subtopics
1107
int lev; /* IN: Level of Topic */
1114
BUF_AppendString(list, "\\begin{table}{ l p }{$$}");
1115
m = 0; /* Size of first column */
1117
while ( (i = LocHelp(&topc)) > lev)
1118
{ if (topc.flag == '@')
1122
l = (i-lev-1)*4; /* Length of first column */
1123
b = buf + oscfill(buf, l, '~');
1125
if (l == 0) b += strcopy(b, "\\bf");
1126
*(b++) = '\05'; *(b++) = '\01'; /* begin{verbatim} */
1127
BUF_AppendItems(list, char, buf, b-buf);
1128
BUF_AppendString(list, topc.got_topic);
1129
BUF_AppendItems(list, char, "\05\02}&", 4);
1130
l += 1 + strlen(topc.got_topic);
1132
l3 = get_tit3(); /* The short explanation */
1133
if (l3 > 0) BUF_AppendItems(list, char, tit3, l3);
1134
BUF_AppendItems(list, char, "\\\\", sizeof("\\\\")-1);
1138
BUF_AppendString(list, "\n\\end{table}");
1139
b = list->buf + list->offset;
1140
b += oscloc(b, 80, '$');
1141
*(b++) = '0' + m/10, *(b++) = '0' + m%10;
1146
/*==========================================================================
1148
*==========================================================================*/
1149
static int EdTop(lev)
1151
.PURPOSE Edit the found Topic and list of Subtopics
1152
.RETURNS _EOF_ / _INTERRUPT_ / _PROMPT_ / OK (something was typed) /
1153
_REDISPLAY_ (no subtopic, and ? was typed) / _SUMMARY_
1154
.REMARKS The static subtopics contains in return the number of found subtopics.
1155
The relevant file is loaded if help is indexed.
1157
int lev; /* IN: Level of Topic */
1165
p = (PIECE *)(help.buf->buf + topics[lev].piece);
1167
/* If help is indexed, load the file */
1169
if (topics[lev].flag == ':')
1171
if ((loaded) && (loaded->fpos == topics[lev].fpos)
1172
&& (loaded->ofile== topics[lev].ofile))
1173
; /* Topic already loaded */
1175
{ loaded = (LOADED *)mm_expand(loaded, sizeof(LOADED)+
1177
loaded->ofile = topics[lev].ofile;
1178
if (fi_date(filenames->buf + loaded->ofile) > help.date)
1179
return(BadIndex()); /* File was modified... */
1180
loaded->fpos = topics[lev].fpos;
1181
loaded->ltext = topics[lev].ltext;
1182
as[0] = loaded->text;
1183
loaded->ltext = fi_load(filenames->buf + loaded->ofile,
1184
loaded->fpos, /* Pos in file */
1185
as[0], loaded->ltext);
1186
as[1] = as[0] + loaded->ltext;
1189
else as[0] = topics[lev].pos, as[1] = p->end;
1191
/* Edit the title in the help.w[0] window */
1193
ClearWindow(help.w[0]);
1194
SetAttr(help.w[0], _BOLD_),
1195
Put(help.w[0],help.title),
1196
Put(help.w[0],": "),
1197
SetAttr(help.w[0], _NORMAL_);
1199
if (help.flags & 2) /* Use Short Title */
1200
ShowString(help.w[0], tit3);
1201
else WriteBinary(help.w[0], list->buf, list->offset);
1202
TouchWindow(help.w[0]); /* Display the Title */
1204
/* Locate the Subtopics */
1206
subtopics = GetSubTop(lev);
1208
/* Now, edit the text + list of subtopics */
1210
as[2] = list->buf + list->offset, as[3] = list->buf + list->used;
1212
status = myOpenDocArray(as, 2);
1213
while(status == 0) {
1214
status = PromptKey(subtopics);
1215
if (status < 0) FINISH;
1217
case _REDISPLAY_ : /* Display subtopics */
1220
status = myOpenDocText(as[2], as[3] - as[2]);
1222
case _PROMPT_ : /* Display Continuation */
1227
default: /* A text was typed ahead */
1231
RaiseWindow(help.w[1]);
1239
/*==========================================================================
1241
*==========================================================================*/
1242
static int EdSummary(lev)
1244
.PURPOSE Display the Summary
1245
.RETURNS _EOF_ / _INTERRUPT_ / _PROMPT_ / OK (something was typed) /
1246
_REDISPLAY_ (no subtopic, and ? was typed)
1249
int lev; /* IN: Level of Topic */
1253
/* First, edit the title in the help.w[0] window */
1255
ClearWindow(help.w[0]);
1256
SetAttr(help.w[0], _BOLD_);
1257
Put(help.w[0], help.title);
1258
Put(help.w[0], " Summary:");
1259
SetAttr(help.w[0], _NORMAL_);
1260
WriteBinary(help.w[0], list->buf, list->offset);
1261
TouchWindow(help.w[0]); /* Display the Title */
1263
status = myOpenDocText(list->buf + list->offset, list->used - list->offset);
1265
while(status == 0) {
1266
status = PromptKey(1);
1267
if (status < 0) FINISH;
1269
case _REDISPLAY_ : /* Redisplay subtopics */
1271
status = myOpenDocText(list->buf + list->offset,
1272
list->used - list->offset);
1274
case _PROMPT_ : /* Terminated (at bottom) */
1277
MoreDoc(TheDoc, 'g'); /* Display Top */
1280
default: /* A text was typed ahead */
1284
RaiseWindow(help.w[1]);
1292
/***************************************************************
1293
* P U B L I C R O U T I N E S
1294
****************************************************************/
1296
/*==========================================================================
1298
*==========================================================================*/
1301
.PURPOSE Define the list of topic separator characters
1303
.REMARKS Default is blank.
1305
char *list; /* IN: Available characters as separators */
1307
strset(sep_table, list);
1308
sep_top = list; /* Tells it's initialized */
1312
/*==========================================================================
1314
*==========================================================================*/
1315
TWHELP *th_init(filename, wt, w, wd)
1317
.PURPOSE Initialize Help procedure: definition of \Help macro,
1318
set the three windows.
1320
--- NOK (error of file doesn't exist)
1321
.REMARKS Default extension for filename = .tex
1323
char *filename; /* IN: Name of help file */
1324
WINDOW *wt; /* IN: Window for Help titles */
1325
WINDOW *w; /* IN: Window for Help display */
1326
WINDOW *wd; /* IN: Window for dialogue */
1329
int (*old_act)(), (*old_out)();
1330
short int screen_size[2];
1331
static char definitions[] =
1332
"\\def\\Help#4{\\action{H.}}\\def\\HelpLoad#4{\\action{H@}}\
1333
\\def\\HelpIndex#7{\\action{H:}}\\def\\fromHelpFiles#1{}";
1337
TRACE_ED_STRING("Help file:", filename);
1339
/* Load the definitions */
1344
if (!sep_top) th_topsep(" "); /* Topic Separators */
1346
old_act = htex->action, old_out = htex->output;
1347
htex->action = act0, htex->output = act0;
1348
TeX_Execute(htex, definitions, sizeof(definitions)-1);
1349
htex->action = old_act, htex->output = old_out;
1350
list = BUF_Open(char, 256, 128);
1351
filenames = BUF_Open(char, 0, 128);
1355
/* Initialize the TWHELP structure */
1357
h = NULL_PTR(TWHELP);
1361
help.buf = NULL_PTR(BUFFER);
1362
help.date = FileDate(filename);
1363
help.title = default_title;
1364
help.context = NULL_PTR(char);
1365
help.bad_index = NULL_PTR(char);
1368
/* Load Help file */
1370
if_not (load_file(filename)) FINISH;
1372
if_not(help.buf = BUF_Open(PIECE, 1, 16)) /* Allocate buffer */
1376
/* Check if Help is Indexed */
1377
if (oscomp(loaded_file.start, HELP_INDEX, sizeof(HELP_INDEX)-1) == 0)
1380
BUF_AppendItem(help.buf, PIECE, &loaded_file);
1381
/* Add this piece to the buffer */
1384
/* If windows are NULL, use defaults */
1386
ScreenSize(screen_size);
1388
if_not(help.w[1]) /* No main Window for Help Display */
1389
{ help.w[1] = OpenWindow("$help", 0, 0, screen_size[0]-2, 0,
1390
_NORMAL_, _DISPLAY_, 0);
1391
CursorTo(help.w[1], 1, 0);
1392
SetAttr(help.w[1], _GRAPHICS_);
1393
Fill(help.w[1], RuleChar(_HORIZONTAL_), screen_size[1]);
1394
SetAttr(help.w[1], _NORMAL_);
1395
help.w[0] = OpenSubWindow(help.w[1], ".help", 0, 0, 1, 0,
1396
_NORMAL_, _DISPLAY_, 0); /* Title of Help Display */
1397
help.w[1] = OpenSubWindow(help.w[1], "=help", 2, 0, 0, 0,
1398
_NORMAL_, _DISPLAY_, 0);
1402
if_not(help.w[2]) /* No Dialogue Window for Help Display */
1403
help.w[2] = OpenWindow("?help", -2, 0, 2, 0, _NORMAL_, 0, 5);
1405
h = MEM_GET(TWHELP, 1);
1409
EXIT_PTR(TWHELP, h);
1412
int th_merge(help, filename)
1414
.PURPOSE Merge a Help with another one. The help must just have been
1415
opened, and the two help files MUST BE INDEXED.
1416
.RETURNS --- OK / NOK
1417
.REMARKS Default extension for filename = .tex
1419
TWHELP *help; /* MOD: Main Help */
1420
char *filename; /* IN: Name of help file */
1429
if_not (help->indexed) { ERROR("Help not Indexed"); FINISH; }
1431
if (b->used != sizeof(PIECE)) { ERROR("Help was used..."); FINISH; }
1433
if_not((load_file(filename))) FINISH;
1435
if ((p = MergeHelp((PIECE *)(b->buf)), &loaded_file)) {
1436
help->date = oshtime(); /* Be sure no Bad Index Error */
1438
BUF_AppendItem(b, PIECE, p);
1446
/*==========================================================================
1448
*==========================================================================*/
1449
char *th_set(helpin, context, opt)
1451
.PURPOSE Defines the Help Context / Title / What to do if index too old
1452
.RETURNS The old Context.
1453
.REMARKS Only address is kept... Use therefore e.g. strsave before calling...
1455
TWHELP *helpin; /* IN: The loaded Help */
1456
char *context; /* IN: Context */
1457
int opt; /* IN: 0 for Title / 1 for Context */
1459
char *old_context, **aa;
1463
/* Copy context to a new piece of memory */
1465
old_context = NULL_PTR(char);
1468
{ case 0: case 1: case 2: aa = &(helpin->title);
1470
default: ERR_ED_I("Bad option: ", opt);
1474
old_context = aa[opt];
1482
int th_oset(helpin, mask, opt)
1484
.PURPOSE Define the Option Context
1485
.RETURNS The old Option Context.
1487
TWHELP *helpin; /* IN: The loaded Help */
1488
int mask; /* IN: Which option */
1489
int opt; /* IN: 0 for Clear / 1 for Set */
1493
old_option = helpin->flags & mask;
1495
helpin->flags |= mask;
1496
else helpin->flags &= ~mask;
1501
/*==========================================================================
1503
*==========================================================================*/
1504
int th_help(helpin, topic, exit_option)
1506
.PURPOSE Display help on `topic'
1507
.RETURNS OK / NOK (error reported) / EOF (the user typed EOF) / -3 (Bad Index)
1510
TWHELP *helpin; /* IN: The loaded Help */
1511
char *topic; /* IN: Topics (separated by blanks) to display */
1512
int exit_option; /* IN: non-zero to exit immediately after \
1513
display, -1 for locate only */
1516
int level, level_step, i, status;
1521
strfree(located_help), located_help = (char *)0;
1523
{ TRACE_ED_STRING("Topic: ", topic);
1525
i = MIN(i, sizeof(reply)-1);
1526
oscopy(reply, topic, i);
1531
if (!helpw) helpw = CreateHelpWindow();
1532
old_helpw = help.w[2]->help;
1533
AttachHelpWindow(help.w[2],helpw);
1537
help.flags |= 1; /* Edit in Top Window */
1539
level = 0; /* Starting Level */
1540
level_step = 1; /* Decrease by this amount for _PROMPT_ */
1541
topics[0].piece = 0;
1542
topics[0].pos = ((PIECE *)(help.buf->buf))->start;
1544
BUF_Clear(filenames);
1545
LocTop(0, 0, 1); /* Find level 0 (start) */
1547
if_not(exit_option) ClearWindow(help.w[2]);
1550
BUF_AppendItem(list, char, &blank); /* Initialize list buffer */
1552
while ((status >= 0) && (level >= 0)) {
1554
if (level_step < 1) level_step = 1;
1562
case _PROMPT_: /* Get the topic */
1563
status = Prompt(level);
1564
if (status == _PROMPT_) level-= level_step, level_step = 1;
1567
case _SUMMARY_: /* List the Summary */
1569
status = EdSummary(level);
1573
/* Locate topics separated by blanks */
1575
TRACE_ED_STRING("Reply is: ", reply);
1577
for (b = reply; *b; ) {
1578
i = strspan_(b, 1, sep_table);
1580
if (*b != ' ') level_step += 1;
1585
if (++level > 9) level = 9;
1586
topics[level].topic = b;
1587
topics[level].ltopic = strscan_(b, 1, sep_table);
1588
if (LocTop(level, help.flags, 1) != level) {
1589
if (exit_option >= 0) Sorry(b, exit_option);
1590
if (exit_option) FINISH;
1591
level -= level_step, level_step = 1;
1595
b += topics[level].ltopic;
1597
if (status == _PROMPT_) continue;
1600
/* Edit located Topic */
1603
if (exit_option >= 0) status = EdTop(level);
1605
b = topics[level].pos; x = *b; *b = 0;
1606
located_help = strsave(topics[level].hpos);
1609
if (exit_option) FINISH;
1610
if (status < 0) FINISH;
1611
if (status == _REDISPLAY_) continue;
1612
if (subtopics == 0) level -= level_step, level_step = 1;
1616
AttachHelpWindow(help.w[2],old_helpw);
1617
CloseDoc(TheDoc), TheDoc = 0;
1619
if (status >= 0) status = OK;
1620
else if (status == _BAD_INDEX_) helpin->indexed = 0;
1621
if (loaded) /* Free allocated memory if Index */
1622
MEM_FREE(loaded), loaded = NULL_PTR(LOADED);
1626
/*==========================================================================
1628
*==========================================================================*/
1629
char *th_loc(helpin, topic, option)
1631
.PURPOSE Retrieve the named topic
1632
.RETURNS String starting at the \Help keyword \ NULL
1635
TWHELP *helpin; /* IN: The loaded Help */
1636
char *topic; /* IN: Topics (separated by blanks) to display */
1637
int option; /* For future use option */
1640
strfree(located_help); located_help = (char *)0;
1641
if (th_help(helpin, topic, -1) != OK)
1642
strfree(located_help), located_help = (char *)0;
1643
EXITp(located_help);