1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * CP hypertext help viewer
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -fg980812 Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
22 * -first alpha (hey, and it was written on my BIRTHDAY!)
23 * -some pages of html documentation converted
24 * -fg980813 Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
25 * -added pgup/pgdown support
26 * -changed drawing method. stopped all flickering this way. but the code
27 * did not get better during this bugfix... :)
28 * -changed helpfile loader to load in "boot" phase, not in first use
29 * I did this because the helpfile was sometimes not found when you
30 * changed the directory via DOS shell.
31 * -some speedups
32 * -the "description" field is now displayed at top/right of the window
33 * -again converted some documentation
34 * -fg980814 Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
35 * -added support for compressed helpfiles
36 * -added percentage display at right side of description
37 * -added jumping to Contents page via Alt-C
38 * -added jumping to Index page via Alt-I
39 * -added jumping to License page via Alt-L
40 * -html conversion again
41 * -fg980820 Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
42 * -now searches CP.HLP in data path
43 * -decided that code could be much cleaner but too lazy to change it :)
44 * -maybe i'll add context sensitivity (if there is interest)
45 * -well, uhm, html documentation is still not fully converted (shame
46 * over me... :))
47 * -fg_dunno Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
48 * -added support for CP.HLP in CP.PAK because kb said CPHELPER would be
49 * part of the next release
50 * -fg980924 Fabian Giesen <gfabian@jdcs.su.nw.schule.de>
51 * -changed keyboard use/handling a lot based on advices (commands? :)
52 * from kb.
53 * -finally the help compiler supports colour codes (i don't know why I
54 * write this here).
55 * -added fileselector support (yes!)
56 * -made this possible by splitting this up in one "host" and two
57 * "wrappers" for fileselector/player interface
58 * -and, you won't believe, it still works :)
59 * -kbwhenever Tammo Hinrichs <opencp@gmx.net>
60 * -some minor cosmetical changes
61 * -fg981118 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
62 * -note: please use this email now (the old one still works, but I don't
63 * give promises about how long this will be)
64 * -changed keyboard control again according to suggestions kb made
65 * (1. kannst du mir das nicht einfach mailen? 2. warum sagst du mir
66 * nicht sofort, das du lynx-keyboard-handling willst 3. sag mal, bin
67 * ich eigentlich dein codesklave? :)
68 * -detailed changes: up/down now also selects links
69 * this ugly tab/shift-tab handling removed
70 * pgup/pgdown updates current link
71 * keyboard handling much more lynx-like
72 * -this code even got worse during change of the keyboard-handling
73 * (but using it got even nicer)
74 * -hope kb likes this as it is (nich wahr, meister, sei ma zufrieden! :)
75 * -fixed this nasty bug which crashed opencp (seemed to be some un-
76 * initialized pointer, or something else...)
77 * -ryg981121 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
78 * -now i'm using my handle instead of my name for changelog (big change,
79 * eh?)
80 * -fixed some stupid bugs with pgup/pgdown handling
81 * -also fixed normal scrolling (hope it works correctly now...)
82 * -no comment from kb about my "lynx style key handling" yet...
83 * -fd981205 Felix Domke <tmbinc@gmx.net>
84 * -included the stdlib.h AGAIN AND AGAIN. hopefully this version will now
85 * finally reach the repository ;)
86 * (still using my realname... ;)
87 * -fd981206 Felix Domke <tmbinc@gmx.net>
88 * -edited for new binfile
89 * -ss040911 Stian Skjelstad <stian@nixia.no>
90 * -stupid misstake prevented cp.hlp to be imported from cp.pak
91 */
92
93 #include "config.h"
94 #include <errno.h>
95 #include <stdlib.h>
96 #include <stdio.h>
97 #include <string.h>
98 #include <unistd.h>
99 #include <zlib.h>
100 #include "boot/psetting.h"
101 #include "boot/plinkman.h"
102 #include "cpiface/cpiface.h"
103 #include "help/cphelper.h"
104 #include "stuff/compat.h"
105 #include "stuff/err.h"
106 #include "stuff/poutput.h"
107 #include "types.h"
108
109 static unsigned int plWinFirstLine, plWinHeight, plHelpHeight, plHelpScroll;
110
111 static const uint32_t Helpfile_ID=1213219663;
112 static const uint32_t Helpfile_Ver=0x011000;
113 static uint32_t Helppages;
114 static int HelpfileErr=hlpErrNoFile;
115 static helppage *Page, *curpage;
116 static help_link *curlink;
117 static int link_ind;
118
119 /* Helpfile Commands */
120
121 #define CMD_NORMAL 1
122 #define CMD_BRIGHT 2
123 #define CMD_HYPERLINK 3
124 #define CMD_CENTERED 4
125 #define CMD_CHCOLOUR 5
126 #define CMD_RAWCHAR 6
127 #define CMD_LINEFEED 10 /* this is a pseudo-command... */
128 #define CMD_MAX 31
129
130 /* Useful macros... */
131
132 #define MIN(a,b) ((a)<(b)?(a):(b))
133 #define MAX(a,b) ((a)>(b)?(a):(b))
134 #define ABS(a) ((a)<0?-(a):(a))
135
136 /* ---------------------------- here starts the viewer */
137
doReadVersion100Helpfile(FILE * file)138 static int doReadVersion100Helpfile(FILE *file)
139 {
140 unsigned int i;
141 if (fread(&Helppages, sizeof(Helppages), 1, file) != 1)
142 {
143 perror(__FILE__ ": fread failed #1: ");
144 return hlpErrBadFile;
145 }
146 Page=calloc(Helppages, sizeof(Page[0]));
147
148 for (i=0; i<Helppages; i++)
149 {
150 unsigned char len;
151
152 memset(Page[i].name, 0, 128);
153 if (fread(&len, sizeof(len), 1, file) != 1)
154 {
155 perror(__FILE__ ": fread failed #2: ");
156 return hlpErrBadFile;
157 }
158 if (fread(Page[i].name, len, 1, file) != 1)
159 {
160 perror(__FILE__ ": fread failed #3: ");
161 return hlpErrBadFile;
162 }
163
164 memset(Page[i].desc, 0, 128);
165 if (fread(&len, sizeof(len), 1, file) != 1)
166 {
167 perror(__FILE__ ": fread failed #4: ");
168 return hlpErrBadFile;
169 }
170
171 if (fread(Page[i].desc, len, 1, file) != 1)
172 {
173 perror(__FILE__ ": fread failed #5: ");
174 return hlpErrBadFile;
175 }
176
177 if (fread(&Page[i].size, sizeof(Page[i].size), 1, file) != 1)
178 {
179 perror(__FILE__ ": fread failed #6: ");
180 return hlpErrBadFile;
181 }
182
183 Page[i].size = uint32_little (Page[i].size);
184 if (fread(&Page[i].lines, sizeof(Page[i].lines), 1, file) != 1)
185 {
186 perror(__FILE__ ": fread failed #7: ");
187 return hlpErrBadFile;
188 }
189
190 Page[i].lines = uint32_little (Page[i].lines);
191
192 Page[i].links=NULL;
193 Page[i].rendered=NULL;
194 };
195
196 for (i=0; i<Helppages; i++)
197 {
198 Page[i].data=calloc(Page[i].size, 1);
199 if (fread(Page[i].data, Page[i].size, 1, file) != 1)
200 {
201 perror(__FILE__ ": fread failed #8: ");
202 return hlpErrBadFile;
203 }
204 };
205
206 return hlpErrOk;
207 }
208
doReadVersion110Helpfile(FILE * file)209 static int doReadVersion110Helpfile(FILE *file)
210 {
211 int *compdatasize;
212 char *inbuf;
213 unsigned int i;
214
215 if (fread(&Helppages, sizeof(Helppages), 1, file) != 1)
216 {
217 perror(__FILE__ ": fread failed #9: ");
218 return hlpErrBadFile;
219 }
220 Helppages = uint32_little (Helppages);
221 Page = calloc(Helppages, sizeof(Page[0]));
222
223 compdatasize=calloc(Helppages, sizeof(int));
224
225 for (i=0; i<Helppages; i++)
226 {
227 unsigned char len;
228
229 memset(Page[i].name, 0, 128);
230 if (fread(&len, sizeof(len), 1, file) != 1)
231 {
232 perror(__FILE__ ": fread failed #10: ");
233 free(compdatasize);
234 return hlpErrBadFile;
235 }
236 if (fread(Page[i].name, len, 1, file) != 1)
237 {
238 perror(__FILE__ ": fread failed #11: ");
239 free(compdatasize);
240 return hlpErrBadFile;
241 }
242
243 memset(Page[i].desc, 0, 128);
244 if (fread(&len, sizeof(len), 1, file) != 1)
245 {
246 perror(__FILE__ ": fread failed #12: ");
247 free(compdatasize);
248 return hlpErrBadFile;
249 }
250 if (fread(Page[i].desc, len, 1, file) != 1)
251 {
252 perror(__FILE__ ": fread failed #13: ");
253 free(compdatasize);
254 return hlpErrBadFile;
255 }
256
257 if (fread(&Page[i].size, sizeof(Page[i].size), 1, file) != 1)
258 {
259 perror(__FILE__ ": fread failed #14: ");
260 free(compdatasize);
261 return hlpErrBadFile;
262 }
263 Page[i].size = uint32_little (Page[i].size);
264 if (fread(&Page[i].lines, sizeof(Page[i].lines), 1, file) != 1)
265 {
266 perror(__FILE__ ": fread failed #15: ");
267 free(compdatasize);
268 return hlpErrBadFile;
269 }
270 Page[i].lines = uint32_little (Page[i].lines);
271
272 if (fread(&compdatasize[i], sizeof(compdatasize[i]), 1, file) != 1)
273 {
274 perror(__FILE__ ": fread failed #16: ");
275 free(compdatasize);
276 return hlpErrBadFile;
277 }
278 compdatasize[i]=uint32_little(compdatasize[i]);
279 Page[i].links=NULL;
280 Page[i].rendered=NULL;
281 };
282
283 for (i=0; i<Helppages; i++)
284 {
285 uLongf temp=Page[i].size;
286 Page[i].data=calloc(Page[i].size, 1);
287 inbuf=calloc(compdatasize[i], 1);
288 if (fread(inbuf, compdatasize[i], 1, file) != 1)
289 {
290 perror(__FILE__ ": fread failed #17: ");
291 free(compdatasize);
292 free(inbuf);
293 return hlpErrBadFile;
294 }
295 uncompress((Bytef *)Page[i].data, &temp, (Bytef *)inbuf, compdatasize[i]);
296 Page[i].size=temp;
297 free(inbuf);
298 }
299 free(compdatasize);
300
301 return hlpErrOk;
302 }
303
doReadHelpFile(FILE * file)304 static int doReadHelpFile(FILE *file)
305 {
306 uint32_t version;
307 uint32_t temp;
308
309 if (fread(&temp, sizeof(temp), 1, file) != 1)
310 {
311 perror(__FILE__ ": fread failed #18: ");
312 return hlpErrBadFile;
313 }
314 temp = uint32_little (temp);
315 if (temp!=Helpfile_ID)
316 return hlpErrBadFile;
317
318 if (fread(&version, sizeof(version), 1, file) != 1)
319 {
320 perror(__FILE__ ": fread failed #19: ");
321 return hlpErrBadFile;
322 }
323 version = uint32_little (version);
324
325 if (version>Helpfile_Ver)
326 return hlpErrTooNew;
327 if (version<0x10000)
328 return hlpErrBadFile;
329
330 switch (version >> 8)
331 {
332 case 0x100:
333 return doReadVersion100Helpfile(file);
334 case 0x110:
335 return doReadVersion110Helpfile(file);
336 default:
337 return hlpErrBadFile;
338 };
339 }
340
plReadHelpExternal(void)341 static char plReadHelpExternal(void)
342 {
343 char *helpname;
344 FILE *bf;
345
346 if (Page && (HelpfileErr==hlpErrOk))
347 return 1;
348
349 makepath_malloc (&helpname, 0, cfDataDir, "ocp.hlp", 0);
350 if ((bf=fopen(helpname, "r")))
351 {
352 free (helpname);
353 HelpfileErr=doReadHelpFile(bf);
354 fclose(bf);
355 } else {
356 fprintf (stderr, "Failed to open(%s): %s\n", helpname, strerror (errno));
357 free (helpname);
358 HelpfileErr=hlpErrNoFile;
359 return 0;
360 };
361
362 return (HelpfileErr==hlpErrOk);
363 }
364
brDecodeRef(char * name)365 helppage *brDecodeRef(char *name)
366 {
367 unsigned int i;
368 for (i=0; i<Helppages; i++)
369 if (!strcasecmp(Page[i].name, name))
370 return &Page[i];
371 return NULL;
372 }
373
firstLinkOnPage(helppage * pg)374 static help_link *firstLinkOnPage(helppage *pg)
375 {
376 if (!pg->linkcount)
377 return NULL;
378 return &pg->links[0];
379 }
380
linkOnCurrentPage(help_link * lnk)381 static int linkOnCurrentPage(help_link *lnk)
382 {
383 unsigned int y;
384
385 if (!lnk)
386 return 0;
387
388 y=lnk->posy;
389 if ((y>=plHelpScroll) && (y<plHelpScroll+plWinHeight))
390 return 1;
391
392 return 0;
393 }
394
brRenderPage(helppage * pg)395 void brRenderPage(helppage *pg)
396 {
397 link_list *lst, *endlst;
398 int lcount;
399 uint16_t linebuf[80];
400 char *data;
401 char attr;
402 int x, y, i;
403
404 if (pg->rendered)
405 {
406 free(pg->rendered);
407 pg->rendered=NULL;
408 };
409
410 if (pg->links)
411 {
412 free(pg->links);
413 pg->links=NULL;
414 };
415
416 lst=endlst=NULL;
417 lcount=0;
418 x=y=0;
419 attr=0x07;
420
421 pg->rendered=calloc(80*MAX(pg->lines, 1), sizeof(uint16_t));;
422 memset(pg->rendered, 0, 160*MAX(pg->lines, 1));
423 memset(linebuf, 0, 160);
424
425 data=pg->data;
426 i=pg->size;
427
428 while (i>0)
429 {
430 if ((uint8_t)*data<CMD_MAX)
431 {
432 switch (*data)
433 {
434 case CMD_NORMAL:
435 attr=0x07;
436 break;
437 case CMD_BRIGHT:
438 attr=0x0f;
439 break;
440 case CMD_HYPERLINK:
441 {
442 char linkbuf[256];
443 int llen;
444
445 data++;
446 i--;
447 strcpy(linkbuf, data);
448
449 if (!endlst)
450 {
451 lst=calloc(sizeof(link_list), 1);
452 endlst=lst;
453 } else {
454 endlst->next=calloc(sizeof(link_list), 1);
455 endlst=endlst->next;
456 };
457
458 *strchr(linkbuf, ',')=0;
459 endlst->ref=(void *) brDecodeRef(linkbuf);
460
461 i-=strchr(data, ',')-data+1;
462 data+=strchr(data, ',')-data+1;
463
464 llen=0;
465
466 endlst->posx=x;
467 endlst->posy=y;
468
469 while (*data)
470 {
471 if ((x<80)&&(*data!=CMD_RAWCHAR))
472 {
473 linebuf[x]=(*data)|0x0300;
474 x++;
475 llen++;
476 };
477
478 data++; i--;
479 };
480
481 endlst->len=llen;
482
483 lcount++;
484
485 break;
486 }
487 case CMD_CENTERED:
488 data++;
489 i--;
490
491 x=40-(strlen(data) >> 1);
492 if (x<0)
493 x=0;
494
495 while (*data)
496 {
497 if (x<80)
498 {
499 linebuf[x]=(*data)|(attr<<8);
500 x++;
501 };
502
503 data++;
504 i--;
505 };
506
507 break;
508 case CMD_CHCOLOUR:
509 data++;
510 i--;
511 attr=*data;
512 break;
513 case CMD_RAWCHAR:
514 data++;
515 i--;
516
517 if (x<80)
518 {
519 linebuf[x]=(*data)|(attr<<8);
520 x++;
521 };
522
523 break;
524 case CMD_LINEFEED:
525 memcpy(&pg->rendered[y*80], linebuf, 160);
526 x=0;
527 y++;
528 memset(linebuf, 0, 160);
529 break;
530 };
531
532 data++; i--;
533 } else {
534 if (x<80)
535 {
536 linebuf[x]=((uint8_t)*data)|(attr<<8);
537 x++;
538 };
539
540 data++;
541 i--;
542 };
543 };
544
545 pg->links=calloc(sizeof(help_link), lcount);
546 pg->linkcount=lcount;
547
548 for (i=0; i<lcount; i++)
549 {
550 pg->links[i].posx=lst->posx;
551 pg->links[i].posy=lst->posy;
552 pg->links[i].len=lst->len;
553 pg->links[i].ref=lst->ref;
554
555 endlst=lst;
556 lst=lst->next;
557 free(endlst);
558 }
559 }
560
brSetPage(helppage * page)561 void brSetPage(helppage *page)
562 {
563 if (!page)
564 return;
565
566 if (curpage)
567 {
568 if (curpage->rendered)
569 {
570 free(curpage->rendered);
571 curpage->rendered=NULL;
572 };
573
574 if (curpage->links)
575 {
576 free(curpage->links);
577 curpage->links=NULL;
578 };
579 };
580
581 curpage=page;
582 brRenderPage(curpage);
583
584 plHelpHeight=curpage->lines;
585 plHelpScroll=0;
586
587 curlink=firstLinkOnPage(curpage);
588 if (!curlink)
589 link_ind=-1;
590 else
591 link_ind=0;
592 }
593
brDisplayHelp(void)594 void brDisplayHelp(void)
595 {
596 unsigned int curlinky;
597 char destbuffer[60];
598 char strbuffer[256];
599 char numbuffer[4];
600 int descxp;
601 unsigned int y;
602
603 if ((plHelpScroll+plWinHeight)>plHelpHeight)
604 plHelpScroll=plHelpHeight-plWinHeight;
605
606 if ((signed)plHelpScroll<0)
607 plHelpScroll=0;
608
609 if (curlink)
610 curlinky=(curlink->posy)-plHelpScroll;
611 else
612 curlinky=-1;
613
614 displaystr(plWinFirstLine-1, 0, 0x09, " OpenCP help ][ ", 20);
615
616
617 if (HelpfileErr==hlpErrOk)
618 strcpy(strbuffer, curpage->desc);
619 else
620 strcpy(strbuffer, "Error!");
621
622 _convnum(100*plHelpScroll/MAX(plHelpHeight-plWinHeight, 1), numbuffer, 10, 3);
623
624 strcat(strbuffer, "-");
625 strcat(strbuffer, numbuffer);
626 strcat(strbuffer, "%");
627
628 memset(destbuffer, 0x20, 60);
629 descxp=MAX(0, 59-(signed)strlen(strbuffer));
630
631 strncpy(&destbuffer[descxp], strbuffer, 59-descxp);
632 displaystr(plWinFirstLine-1, 20, 0x08, destbuffer, 59);
633
634
635 if (HelpfileErr!=hlpErrOk)
636 {
637 char errormsg[80];
638
639 strcpy(errormsg, "Error: ");
640
641 switch (HelpfileErr)
642 {
643 case hlpErrNoFile:
644 strcat(errormsg, "Helpfile \"OCP.HLP\" is not present");
645 break;
646 case hlpErrBadFile:
647 strcat(errormsg, "Helpfile \"OCP.HLP\" is corrupted");
648 break;
649 case hlpErrTooNew:
650 strcat(errormsg, "Helpfile version is too new. Please update.");
651 break;
652 default:
653 strcat(errormsg, "Currently undefined help error");
654 };
655
656 displayvoid(plWinFirstLine, 0, CONSOLE_MAX_X);
657
658 displaystr(plWinFirstLine+1, 4, 0x04, errormsg, 74);
659
660 for (y=2; y<plWinHeight; y++)
661 displayvoid(y+plWinFirstLine, 0, CONSOLE_MAX_X);
662 } else {
663 int addx = (plScrWidth - 80) / 2;
664 for (y=0; y<plWinHeight; y++)
665 {
666 if ((y+plHelpScroll)>=plHelpHeight)
667 {
668 displayvoid(y+plWinFirstLine, 0, plScrWidth);
669 continue;
670 }
671 if (y!=curlinky)
672 {
673 displayvoid(y+plWinFirstLine, 0, addx);
674 displaystrattr(y+plWinFirstLine, 0+addx, &curpage->rendered[(y+plHelpScroll)*80], 80);
675 displayvoid(y+plWinFirstLine, 80+addx, plScrWidth-80-addx);
676 } else {
677 int yp=(y+plHelpScroll)*80;
678 int xp;
679 char dummystr[82];
680 int i, off;
681
682 displayvoid(y+plWinFirstLine, 0, addx);
683 if (curlink->posx!=0)
684 {
685 displaystrattr(y+plWinFirstLine, addx, &curpage->rendered[yp], curlink->posx);
686 };
687
688 xp=curlink->posx+curlink->len;
689
690 displaystrattr(y+plWinFirstLine, xp+addx,
691 &curpage->rendered[yp+xp],
692 79-xp);
693
694
695 for (i=0, off=yp+curlink->posx; curpage->rendered[off] & 0xff; i++, off++)
696 dummystr[i]=curpage->rendered[off] & 0xff;
697
698 dummystr[i]=0;
699
700 displaystr(y+plWinFirstLine, curlink->posx+addx, 4, dummystr, curlink->len);
701
702 displayvoid(y+plWinFirstLine, 80+addx, plScrWidth-80-addx);
703
704 /* and all this just to prevent flickering. ARG! */
705 }
706 }
707 }
708 }
709
processActiveHyperlink(void)710 static void processActiveHyperlink(void)
711 {
712 if (curlink)
713 brSetPage((helppage *) curlink->ref);
714 }
715
brSetWinStart(int fl)716 void brSetWinStart(int fl)
717 {
718 plWinFirstLine=fl;
719 }
720
brSetWinHeight(int h)721 void brSetWinHeight(int h)
722 {
723 plWinHeight=h;
724 }
725
brHelpKey(uint16_t key)726 int brHelpKey(uint16_t key)
727 {
728 help_link *link2;
729
730 if(!curpage)
731 return 1;
732
733 switch (key)
734 {
735 case KEY_ALT_K:
736 cpiKeyHelp(KEY_UP, "Scroll help page up");
737 cpiKeyHelp(KEY_DOWN, "Scroll help page down");
738 cpiKeyHelp(KEY_PPAGE, "Scroll help page, a page up");
739 cpiKeyHelp(KEY_NPAGE, "Scroll help page, a page down");
740 cpiKeyHelp(KEY_HOME, "Scroll help page, to the start");
741 cpiKeyHelp(KEY_END, "Scroll help page, to the bottom");
742 cpiKeyHelp(KEY_ALT_C, "Goto contents help page");
743 cpiKeyHelp(KEY_ALT_I, "Goto index help page");
744 cpiKeyHelp(KEY_ALT_L, "Goto licence help page");
745 cpiKeyHelp(KEY_TAB, "Goto next link");
746 cpiKeyHelp(KEY_SHIFT_TAB, "Goto previous link");
747 return 0;
748 /*case 0x4800: //up*/
749 case KEY_UP:
750 if (curpage->linkcount)
751 {
752 link2=&curpage->links[MAX(link_ind-1, 0)];
753
754 if (link2!=curlink)
755 {
756 if ((signed)(plHelpScroll-link2->posy)>1)
757 plHelpScroll--;
758 else {
759 link_ind=MAX(link_ind-1, 0);
760 curlink=link2;
761
762 if (link2->posy<plHelpScroll)
763 plHelpScroll=link2->posy;
764 }
765 } else
766 if (plHelpScroll>0)
767 plHelpScroll--;
768 } else
769 if (plHelpScroll>0)
770 plHelpScroll--;
771 break;
772 /*case 0x5000: //down*/
773 case KEY_DOWN:
774 if (curpage->linkcount)
775 {
776 link2=&curpage->links[MIN(link_ind+1, curpage->linkcount-1)];
777
778 if (link2->posy-plHelpScroll>plWinHeight)
779 plHelpScroll++;
780 else {
781 link_ind=MIN(link_ind+1, curpage->linkcount-1);
782 curlink=link2;
783
784 if (link2->posy>(plHelpScroll+plWinHeight))
785 plHelpScroll=link2->posy;
786 else
787 if (link2->posy==(plHelpScroll+plWinHeight))
788 plHelpScroll++;
789 }
790 } else
791 if (plHelpScroll<plHelpHeight-1)
792 plHelpScroll++;
793
794 break;
795 /*case 0x4900: //pgup*/
796 case KEY_PPAGE:
797 plHelpScroll-=plWinHeight;
798 if ((signed)plHelpScroll<0)
799 plHelpScroll=0;
800
801 if (curpage->linkcount)
802 {
803 if (!linkOnCurrentPage(curlink))
804 {
805 int bestmatch, bestd;
806 int i;
807
808 bestd=2000000;
809 bestmatch=-1;
810
811 for (i=curpage->linkcount-1; i>=0; i--)
812 {
813 int d=ABS((signed)plHelpScroll+(signed)plWinHeight-(signed)curpage->links[i].posy-1);
814 if (d<bestd)
815 {
816 bestd=d;
817 bestmatch=i;
818 };
819 };
820 link_ind=bestmatch;
821 curlink=&curpage->links[link_ind];
822 };
823 };
824 break;
825 /*case 0x5100: //pgdn*/
826 case KEY_NPAGE:
827 plHelpScroll+=plWinHeight;
828
829 if (plHelpScroll>(plHelpHeight-plWinHeight))
830 plHelpScroll=plHelpHeight-plWinHeight;
831
832 if (curpage->linkcount)
833 {
834 if (!linkOnCurrentPage(curlink))
835 {
836 int bestmatch, bestd;
837 int i;
838
839 bestd=2000000;
840 bestmatch=-1;
841
842 for (i=0; i<curpage->linkcount; i++)
843 {
844 int d=ABS((signed)plHelpScroll-(signed)curpage->links[i].posy);
845 if (d<bestd)
846 {
847 bestd=d;
848 bestmatch=i;
849 };
850 };
851
852 link_ind=bestmatch;
853 curlink=&curpage->links[link_ind];
854 };
855 };
856 break;
857 /*case 0x4700: //home*/
858 case KEY_HOME:
859 plHelpScroll=0;
860 break;
861 /*case 0x4F00: //end*/
862 case KEY_END:
863 plHelpScroll=plHelpHeight-plWinHeight;
864 break;
865 case KEY_ALT_C:
866 brSetPage(brDecodeRef("Contents"));
867 break;
868 case KEY_ALT_I:
869 brSetPage(brDecodeRef("Index"));
870 break;
871 case KEY_ALT_L:
872 brSetPage(brDecodeRef("License"));
873 break;
874 case KEY_TAB:
875 if (curpage->linkcount)
876 {
877 if (linkOnCurrentPage(curlink))
878 {
879 link_ind=(link_ind+1)%curpage->linkcount;
880 curlink=&curpage->links[link_ind];
881 }
882 if (!linkOnCurrentPage(curlink))
883 plHelpScroll=curlink->posy;
884 }
885 break;
886 case KEY_SHIFT_TAB: /* 0x0f00: //shift-tab*/
887 if (curpage->linkcount)
888 {
889 if (linkOnCurrentPage(curlink))
890 {
891 link_ind--;
892 if (link_ind<0)
893 link_ind=curpage->linkcount-1;
894 curlink=&curpage->links[link_ind];
895 }
896 if (!linkOnCurrentPage(curlink))
897 plHelpScroll=curlink->posy;
898 }
899 break;
900 /* case 0x3920: case 0x3900: case 0x0020: case 0x000D: // space/enter*/
901 case KEY_CTRL_J: case _KEY_ENTER: case ' ':
902 processActiveHyperlink();
903 break;
904 default:
905 return 0;
906 }
907 if ((plHelpScroll+plWinHeight)>plHelpHeight)
908 plHelpScroll=plHelpHeight-plWinHeight;
909 if ((signed)plHelpScroll<0)
910 plHelpScroll=0;
911 return 1;
912 }
913
hlpGlobalInit(void)914 static int hlpGlobalInit(void)
915 {
916 helppage *pg;
917
918 plHelpHeight=plHelpScroll=0;
919
920 if (!plReadHelpExternal())
921 {
922 fprintf(stderr, "Warning. Failed to read help files\n");
923 return errOk; /* this error is not fatal to rest of the player */
924 };
925
926 curpage=NULL;
927
928
929 pg=brDecodeRef("Contents");
930 if (!pg)
931 HelpfileErr=hlpErrBadFile;
932 else
933 brSetPage(pg);
934
935 return errOk;
936 }
937
hlpFreePages(void)938 void hlpFreePages(void)
939 {
940 unsigned int i;
941 for (i=0; i<Helppages; i++)
942 {
943 if (Page[i].data)
944 {
945 free(Page[i].data);
946 Page[i].data=NULL;
947 };
948
949 if (Page[i].rendered)
950 {
951 free(Page[i].rendered);
952 Page[i].rendered=NULL;
953 };
954
955 if (Page[i].links)
956 {
957 free(Page[i].links);
958 Page[i].links=NULL;
959 };
960 };
961
962 free(Page);
963 Page=NULL;
964
965 curpage=NULL;
966 curlink=NULL;
967
968 Helppages=link_ind=0;
969 HelpfileErr=hlpErrNoFile;
970 }
971
hlpGlobalClose(void)972 static void hlpGlobalClose(void)
973 {
974 hlpFreePages();
975 }
976
977 #ifndef SUPPORT_STATIC_PLUGINS
978 char *dllinfo = "";
979 #endif
980 DLLEXTINFO_PREFIX struct linkinfostruct dllextinfo = {.name = "cphelper", .desc = "OpenCP help browser (c) 1998-09 Fabian Giesen", .ver = DLLVERSION, .size = 0, .Init = hlpGlobalInit, .Close = hlpGlobalClose};
981