|
|
1.1 root 1: /*
2: * This is a library module for help file subject lookup. There are
3: * three externally available functions and two externally available
4: * pointers.
5: *
6: * The two externally available pointers must be defined and given a
7: * value by the program that calls this module, and are
8: * char *helpfile; The name of the help file
9: * char *helpindex; The name of the help index file
10: *
11: * The functions that are available are:
12: *
13: * char *name_gen(basename, pathvar, defpath) char *basename, *pathvar;
14: * Returns the full name (including path info) of the
15: * file "basename" looked up on pathvar, if found or
16: * defpath. The name is returned in a malloc'ed chunk
17: * of memory which should be free'd when you are done
18: * with it. Returns NULL on failure.
19: *
20: * int help(topic, output) char *topic; int (*output)();
21: * Lookup the topic and call output with each line of it.
22: * Returns 1 if the topic could not be found, -1 if the
23: * file could not be accessed.
24: *
25: * int helpclose();
26: * Close help files and clean up the rest of the world.
27: *
28: */
29: #include <stdio.h>
30: #include <sys/stat.h>
31: #include <path.h>
32: #include "ed.h"
33:
34: #define PATHSIZE 64 /* Longest path name */
35:
36: #if GEMDOS
37: #define DEFHELPATH DEFLIBPATH
38: #endif
39:
40: #if MSDOS
41: #define DEFHELPATH DEFLIBPATH
42: #endif
43:
44: #ifdef COHERENT
45: #define DEFHELPATH ".:/usr/lib:/etc:/lib:"
46: #endif
47:
48: #ifndef HELPSEP
49: #define HELPSEP '@' /* marks a new help entry */
50: #endif
51:
52: extern uchar *helpfile; /* Help file name */
53: extern uchar *helpindex; /* Help file index */
54:
55: static FILE *helpfp; /* Our helpfile */
56: static uchar *helpline; /* Our help buffer */
57:
58: /*
59: * Structure to speed lookup time.
60: */
61: struct look {
62: long l_seek;
63: uchar *l_name;
64: };
65:
66: struct look *lread();
67:
68: uchar *getenv();
69: char *path();
70:
71: /*
72: * Create a file name from a basename and an environment variable.
73: */
74: uchar *
75: name_gen(name, pathvar, defpath)
76: register uchar *name;
77: uchar *pathvar;
78: uchar *defpath;
79: {
80: register uchar *fullname;
81: register uchar *libpath;
82:
83: if ((fullname = (char *)malloc(PATHSIZE)) == NULL)
84: return NULL;
85: if ((libpath = getenv(pathvar)) == NULL)
86: libpath = defpath;
87: if ((libpath = path(libpath, name, AREAD)) == NULL)
88: strcpy(fullname, name);
89: else
90: strcpy(fullname, libpath);
91: return fullname;
92: }
93:
94: /*
95: * Get name of flex bind file.
96: */
97: uchar *
98: flexName()
99: {
100: #ifdef COHERENT
101: return (name_gen(".emacs.rc", "HOME", DEFHELPATH));
102: #else
103: return (name_gen("emacs.rc", "LIBPATH", DEFHELPATH));
104: #endif
105: }
106:
107: /* Open the help file "name" with access "acs" along the current
108: * libpath.
109: */
110: static FILE *
111: hfopen(name, acs)
112: uchar *name;
113: uchar *acs;
114: {
115: uchar *fullname;
116: FILE *fp = NULL;
117:
118: if ((fullname = name_gen(name, "LIBPATH", DEFHELPATH)) == NULL)
119: return NULL; /* Can't get full name */
120: fp = fopen(fullname, acs); /* Open the file. */
121: mlwrite(fullname);
122: free(fullname); /* Free the namebuffer */
123: return fp; /* return the file ptr */
124: }
125:
126: /*
127: * Get the "stat" of the help file...
128: */
129: static hstat(name, sb)
130: uchar *name;
131: struct stat *sb;
132: {
133: uchar *fullname;
134: register int s;
135:
136: if ((fullname = name_gen(name, "LIBPATH", DEFHELPATH)) == NULL)
137: return -1; /* could not get the name */
138: s = stat(fullname, sb); /* stat the file. */
139: free(fullname);
140: return s;
141: }
142:
143: helpclose() {
144: if (helpfp != NULL)
145: fclose(helpfp);
146: if (helpline != NULL)
147: free(helpline);
148: helpfp = helpline = NULL;
149: }
150:
151: /*
152: * program interface to the help file. open file(s) as needed.
153: * subsequent calls will not need to search and open them
154: * again -- output function takes a string arg and does something
155: * with it. Non-zero return means no help found.
156: */
157: help(topic, output)
158: uchar *topic;
159: int (*output)();
160: {
161: if (helpfp == NULL)
162: if ((helpfp = hfopen(helpfile, "r")) == NULL)
163: return -1;
164: if (helpline == NULL)
165: if ((helpline = malloc(NLINE)) == NULL)
166: return -1;
167: return (lookup(topic, helpfp, helpindex, output));
168: }
169:
170: /*
171: * Make an index of help for a given topic.
172: * Non-zero return means no topics found.
173: */
174: indexhelp(topic, output)
175: uchar *topic;
176: int (*output)();
177: {
178: if (helpfp == NULL)
179: if ((helpfp = hfopen(helpfile, "r")) == NULL)
180: return -1;
181: if (helpline == NULL)
182: if ((helpline = malloc(NLINE)) == NULL)
183: return -1;
184: return (doindex(topic, helpfp, output));
185: }
186:
187: /*
188: * Lookup a command in the given file.
189: * The format is to look for HELPSEP (@) lines.
190: * The optional index-file is provided to speed up
191: * the lookup in situations where there is a very
192: * large system help file.
193: */
194: static lookup(com, fp, ind, output)
195: register uchar *com;
196: FILE *fp;
197: uchar *ind;
198: int (*output)();
199: {
200: if (fp == NULL)
201: return (1);
202: fseek(fp, 0L, 0);
203: fastlook(com, fp, ind);
204: while (fgets(helpline, NLINE, fp) != NULL)
205: if (helpline[0] == HELPSEP) {
206: helpline[strlen(helpline)-1] = '\0';
207: if (strcmp(com, helpline+1) == 0) {
208: while (fgets(helpline, NLINE, fp) != NULL) {
209: if (helpline[0] == HELPSEP)
210: break;
211: helpline[strlen(helpline)-1] = '\0';
212: (*output)(helpline);
213: }
214: return (0);
215: }
216: }
217: return (1);
218: }
219:
220: /*
221: * Possibly seek the helpfile to the right place based on an index file.
222: * Return non-zero only when it is impossible to find it.
223: */
224: static fastlook(com, fp, ind)
225: uchar *com;
226: FILE *fp;
227: uchar *ind;
228: {
229: register struct look *lp;
230: FILE *ifp;
231: static struct stat sb;
232: #if !MSDOS
233: long htime;
234:
235: fstat(fileno(fp), &sb);
236: htime = sb.st_mtime;
237: #endif
238: if (ind == NULL) /* No index file? */
239: return;
240: if (hstat(ind, &sb) < 0) /* not found ? */
241: return;
242: #if !MSDOS
243: if (htime < sb.st_mtime) {
244: #endif
245: if ((ifp = hfopen(ind, "rb")) == NULL)
246: return;
247: while ((lp = lread(ifp)) != NULL)
248: if (strcmp(com, lp->l_name) == 0) {
249: fseek(fp, lp->l_seek, 0);
250: break;
251: }
252: fclose(ifp);
253: #if !MSDOS
254: }
255: #endif
256: return;
257: }
258:
259: /*
260: * Read in a look structure. Return NULL
261: * on end of file or error.
262: */
263: static struct look *
264: lread(fp)
265: register FILE *fp;
266: {
267: register uchar *cp;
268: register int c;
269: static struct look look;
270: static uchar name[50];
271:
272: look.l_name = name;
273: if (fread(&look.l_seek, sizeof look.l_seek, 1, fp) != 1)
274: return (NULL);
275: for (cp = name; cp<&name[49]; cp++) {
276: if ((c = getc(fp)) == EOF)
277: return (NULL);
278: *cp = c;
279: if (c == '\0')
280: break;
281: }
282: return (&look);
283: }
284:
285: /* Return 0 if s1 found in s2 */
286: static subcmp(s1, s2)
287: uchar *s1;
288: register uchar *s2;
289: {
290: register uchar *st;
291: register uchar *se;
292:
293: st = s1;
294: for (;;) {
295: while (*st != *s2++)
296: if (*s2 == '\0')
297: return 1;
298: if (*st++ == '\0')
299: return 0;
300: se = s2;
301: while (*st++ == *se++) {
302: if (*st == '\0')
303: return 0;
304: if (*se == '\0')
305: return 1;
306: }
307: st = s1;
308: }
309: }
310:
311: static int doindex(com, fp, output)
312: register uchar *com;
313: FILE *fp;
314: int (*output)();
315: {
316: register int t = 0;
317:
318: if (fp == NULL)
319: return (1);
320: fseek(fp, 0L, 0);
321: while (fgets(helpline, NLINE, fp) != NULL) {
322: if (helpline[0] == HELPSEP) {
323: helpline[strlen(helpline)-1] = '\0';
324: if (subcmp(com, helpline+1) == 0) {
325: if (fgets(helpline, NLINE, fp) == NULL)
326: return t == 0;
327: helpline[strlen(helpline)-1] = '\0';
328: (*output)(helpline);
329: t++;
330: }
331: }
332: }
333: if (t == 0)
334: return 1;
335: return 0;
336: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.