joe-3.1jupp31.tgz (die zweite Klappe…)
[alioth/jupp.git] / help.c
1 /* $MirOS: contrib/code/jupp/help.c,v 1.10 2017/01/10 23:59:32 tg Exp $ */
2 /*
3  *      Help system
4  *      Copyright
5  *              (C) 1992 Joseph H. Allen
6  *              (C) 2001 Marek 'Marx' Grac
7  *
8  *      This file is part of JOE (Joe's Own Editor)
9  */
10 #include "config.h"
11 #include "types.h"
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #ifdef HAVE_BSD_STRING_H
18 #include <bsd/string.h>
19 #endif
20
21 #include "blocks.h"
22 #include "builtin.h"
23 #include "scrn.h"
24 #include "utils.h"
25 #include "vs.h"
26 #include "utf8.h"
27 #include "w.h"
28
29 extern void outatr_help(SCRN *,int *,int *,int,int,int,int);
30
31 #define NOT_ENOUGH_MEMORY -11
32
33 struct help *help_actual = NULL;                        /* actual help screen */
34
35 /* 
36  * Process help file
37  * Returns 0 if the help file was succefully processed
38  *        -1 if the help file couldn't be opened 
39  *        NOT_ENOUGH_MEMORY if there is not enough memory
40  */
41
42 int help_init(unsigned char *filename)
43 {
44         JFILE *fd;                                      /* help file */
45         unsigned char buf[1024];                        /* input buffer */
46
47         struct help *tmp;
48         unsigned int bfl;                               /* buffer length */
49         unsigned int hlpsiz, hlpbsz;                    /* number of used/allocated bytes for tmp->text */
50         unsigned char *tempbuf;
51
52         if (!(fd = jfopen((char *)filename, "r")))              /* open the help file */
53                 return -1;                              /* return if we couldn't open the file */
54
55         fprintf(stderr, "Processing '%s'...", filename);
56         fflush(stderr);
57
58         while (jfgets((char *)buf, sizeof(buf), fd)) {
59                 if (buf[0] == '{') {                    /* start of help screen */
60                         if (!(tmp = (struct help *) joe_malloc(sizeof(struct help)))) {
61                                 return NOT_ENOUGH_MEMORY;
62                         }
63
64                         tmp->text = NULL;
65                         tmp->lines = 0;
66                         hlpsiz = 0;
67                         hlpbsz = 0;
68                         tmp->name = vsncpy(NULL, 0, sz(buf + 1) - 1);
69
70                         while ((jfgets((char *)buf, sizeof(buf), fd)) && (buf[0] != '}')) {
71                                 bfl = strlen((char *)buf);
72                                 if (hlpsiz + bfl > hlpbsz) {
73                                         if (tmp->text) {
74                                                 tempbuf = (unsigned char *) joe_realloc(tmp->text, hlpbsz + bfl + 1024);
75                                                 if (!tempbuf) {
76                                                         joe_free(tmp->text);
77                                                         joe_free(tmp);
78                                                         return NOT_ENOUGH_MEMORY;
79                                                 } else {
80                                                         tmp->text = tempbuf;
81                                                 }
82                                         } else {
83                                                 tmp->text = (unsigned char *) joe_malloc(bfl + 1024);
84                                                 if (!tmp->text) {
85                                                         joe_free(tmp);
86                                                         return NOT_ENOUGH_MEMORY;
87                                                 } else {
88                                                         tmp->text[0] = 0;
89                                                 }
90                                         }
91                                         hlpbsz += bfl + 1024;
92                                 }
93                                 strlcpy((char *)(tmp->text + hlpsiz), (char *)buf, 1024);
94                                 hlpsiz += bfl;
95                                 ++tmp->lines;
96                         }
97                         if (buf[0] == '}') {            /* set new help screen as actual one */
98                                 tmp->prev = help_actual;
99                                 tmp->next = NULL;
100                                 if (help_actual) {
101                                         help_actual->next = tmp;
102                                 }
103                                 help_actual = tmp;
104                         } else {
105                                 fprintf(stderr, "\nHelp file '%s' is not properly ended with } on new line.\n", filename);
106                                 fprintf(stderr, "Do you want to accept incomplete help screen (y/n)?");
107                                 fflush(stderr);
108                                 if (fgets((char *)buf, 8, stdin) == NULL ||
109                                     (!((buf[0] == 'y') || (buf[0] == 'Y')))) {
110                                         joe_free(tmp->text);
111                                         joe_free(tmp);
112                                         return 0;
113                                 } else {
114                                         tmp->prev = help_actual;
115                                         tmp->next = NULL;
116                                         if (help_actual) {
117                                                 help_actual->next = tmp;
118                                         }
119                                         help_actual = tmp;
120                                 }
121                         }
122                 }
123         }
124         jfclose(fd);                                    /* close help file */
125
126         fprintf(stderr, "done\n");
127         
128         while (help_actual && help_actual->prev) {      /* move to first help screen */
129                 help_actual = help_actual->prev;
130         }
131
132         return 0;
133 }
134
135 /*
136  * Find context help - find help entry with the same name
137  */
138
139 struct help *find_context_help(const unsigned char *name)
140 {
141         struct help *tmp = help_actual;
142
143         while (tmp->prev != NULL)       /* find the first help entry */
144                 tmp = tmp->prev;
145
146         while (tmp != NULL && strcmp(tmp->name, name) != 0)
147                 tmp = tmp->next;
148
149         return tmp;
150 }
151
152 /*
153  * Display help text
154  */
155 void help_display(SCREEN *t)
156 {
157         unsigned char *str;
158         int y, x, z;
159         int atr = 0;
160
161         if (help_actual) {
162                 str = help_actual->text;
163         } else {
164                 str = NULL;
165         }
166
167         for (y = skiptop; y != t->wind; ++y) {
168                 if (t->t->updtab[y]) {
169                         unsigned char *start = str;
170                         int width=0;
171                         int nspans=0;
172                         int spanwidth;
173                         int spancount=0;
174                         int spanextra;
175                         /* First pass: count no. springs \| and determine minimum width */
176                         while(*str && *str!='\n')
177                                 if (*str++ == '\\')
178                                         switch(*str) {
179                                                 case 'i':
180                                                 case 'I':
181                                                 case 'u':
182                                                 case 'U':
183                                                 case 'd':
184                                                 case 'D':
185                                                 case 'b':
186                                                 case 'B':
187                                                 case 'f':
188                                                 case 'F':
189                                                         ++str;
190                                                         break;
191                                                 case '|':
192                                                         ++str;
193                                                         ++nspans;
194                                                         break;
195                                                 case 0:
196                                                         break;
197                                                 default:
198                                                         ++str;
199                                                         ++width;
200                                         }
201                                 else
202                                         ++width;
203                         str = start;
204                         /* Now calculate span width */
205                         if (width >= t->w - 1 || nspans==0) {
206                                 spanwidth = 0;
207                                 spanextra = nspans;
208                         } else {
209                                 spanwidth = ((t->w - 1) - width)/nspans;
210                                 spanextra = nspans - ((t->w - 1) - width - nspans*spanwidth);
211                         }
212                         /* Second pass: display text */
213                         for (x = 0; x != t->w - 1; ++x) {
214                                 if (*str == '\n' || !*str) {
215                                         if (eraeol(t->t, x, y)) {
216                                                 return;
217                                         } else {
218                                                 break;
219                                         }
220                                 } else {
221                                         if (*str == '\\') {
222                                                 switch (*++str) {
223                                                 case '|':
224                                                         ++str;
225                                                         for (z=0;z!=spanwidth;++z)
226                                                                 outatr(locale_map,t->t,t->t->scrn+x+y*t->w+z,t->t->attr+x+y*t->w+z,x+z,y,' ',atr);
227                                                         if (spancount++ >= spanextra) {
228                                                                 outatr(locale_map,t->t,t->t->scrn+x+y*t->w+z,t->t->attr+x+y*t->w+z,x+z,y,' ',atr);
229                                                                 ++z;
230                                                         }
231                                                         x += z-1;
232                                                         continue;
233                                                 case 'i':
234                                                 case 'I':
235                                                         atr ^= INVERSE;
236                                                         ++str;
237                                                         --x;
238                                                         continue;
239                                                 case 'u':
240                                                 case 'U':
241                                                         atr ^= UNDERLINE;
242                                                         ++str;
243                                                         --x;
244                                                         continue;
245                                                 case 'd':
246                                                 case 'D':
247                                                         atr ^= DIM;
248                                                         ++str;
249                                                         --x;
250                                                         continue;
251                                                 case 'b':
252                                                 case 'B':
253                                                         atr ^= BOLD;
254                                                         ++str;
255                                                         --x;
256                                                         continue;
257                                                 case 'f':
258                                                 case 'F':
259                                                         atr ^= BLINK;
260                                                         ++str;
261                                                         --x;
262                                                         continue;
263                                                 case 0: 
264                                                         --x;
265                                                         continue;
266                                                 }
267                                         }
268                                         outatr_help(t->t,
269                                             t->t->scrn + x + y * t->w,
270                                             t->t->attr + x + y * t->w,
271                                             x, y, *str++, atr);
272                                 }
273                         }
274                         atr = 0;
275                         t->t->updtab[y] = 0;
276                 }
277
278                 while (*str && *str != '\n')
279                         ++str;
280                 if (*str == '\n')
281                         ++str;
282         }
283 }
284
285 /*
286  * Show help screen 
287  */
288 int help_on(SCREEN *t)
289 {
290         if (help_actual) {
291                 t->wind = help_actual->lines + skiptop;
292                 if ((t->h - t->wind) < FITHEIGHT) {
293                         t->wind = t->h - FITHEIGHT;
294                 }
295                 if (t->wind < 0) {
296                         t->wind = skiptop;
297                         return -1;
298                 }
299                 wfit(t);
300                 msetI(t->t->updtab + skiptop, 1, t->wind);
301                 return 0;
302         } else {
303                 return -1;
304         }
305 }
306
307 /*
308  * Hide help screen
309  */
310 void help_off(SCREEN *t)
311 {
312         t->wind = skiptop;
313         wfit(t);
314 }
315
316 /*
317  * Show/hide current help screen
318  */
319 int u_help(BASE *base)
320 {
321         W *w = base->parent;
322         struct help *new_help;
323
324         if (w->huh && (new_help = find_context_help(w->huh)) != NULL) {
325                 if (help_actual != new_help) {
326                         if (w->t->wind != skiptop)
327                                 help_off(w->t);
328                         help_actual = new_help;         /* prepare context help */
329                 }
330         }
331         if (w->t->wind == skiptop) {
332                 return help_on(w->t);                   /* help screen is hidden, so show the actual one */
333         } else {
334                 help_off(w->t);                         /* hide actual help screen */
335                 return 0;
336         }
337 }
338
339 /*
340  * Show next help screen (if it is possible)
341  */
342 int u_help_next(BASE *base)
343 {
344         W *w = base->parent;
345
346         if (help_actual && help_actual->next) {         /* is there any next help screen? */
347                 if (w->t->wind != skiptop) {
348                         help_off(w->t);                 /* if help screen was visible, then hide it */
349                 }
350                 help_actual = help_actual->next;        /* change to next help screen */
351                 return help_on(w->t);                   /* show actual help screen */
352         } else {
353                 return -1;
354         }
355 }
356
357 /*
358  * Show previous help screen (if it is possible)
359  */
360 int u_help_prev(BASE *base)
361 {
362         W *w = base->parent;
363
364         if (help_actual && help_actual->prev) {         /* is there any previous help screen? */
365                 if (w->t->wind != skiptop)
366                         help_off(w->t);                 /* if help screen was visible, then hide it */
367                 help_actual = help_actual->prev;        /* change to previous help screen */
368                 return help_on(w->t);                   /* show actual help screen */
369         } else {
370                 return -1;
371         }
372 }