/* * Help system * Copyright * (C) 1992 Joseph H. Allen * (C) 2001 Marek 'Marx' Grac * * This file is part of JOE (Joe's Own Editor) */ #include "config.h" #include "types.h" __RCSID("$MirOS: contrib/code/jupp/help.c,v 1.15 2017/12/08 03:24:15 tg Exp $"); #include #include #ifdef HAVE_BSD_STRING_H #include #endif #include "blocks.h" #include "builtin.h" #include "help.h" #include "scrn.h" #include "utils.h" #include "vs.h" #include "utf8.h" #include "w.h" #define NOT_ENOUGH_MEMORY -11 struct help *help_actual = NULL; /* actual help screen */ /* * Process help file * Returns 0 if the help file was succefully processed * -1 if the help file couldn't be opened * NOT_ENOUGH_MEMORY if there is not enough memory */ int help_init(const unsigned char *filename) { JFILE *fd; /* help file */ unsigned char buf[1024]; /* input buffer */ struct help *tmp; unsigned int bfl; /* buffer length */ unsigned int hlpsiz, hlpbsz; /* number of used/allocated bytes for tmp->text */ unsigned char *tempbuf; if (!(fd = jfopen((const char *)filename, "r")))/* open the help file */ return -1; /* return if we couldn't open the file */ fprintf(stderr, "Processing '%s'...", filename); fflush(stderr); while (jfgets((char *)buf, sizeof(buf), fd)) { if (buf[0] == '{') { /* start of help screen */ if (!(tmp = malloc(sizeof(struct help)))) { return NOT_ENOUGH_MEMORY; } tmp->text = NULL; tmp->lines = 0; hlpsiz = 0; hlpbsz = 0; tmp->name = vsncpy(NULL, 0, sz(buf + 1) - 1); while ((jfgets((char *)buf, sizeof(buf), fd)) && (buf[0] != '}')) { bfl = strlen((char *)buf); if (hlpsiz + bfl > hlpbsz) { if (tmp->text) { tempbuf = realloc(tmp->text, hlpbsz + bfl + 1024); if (!tempbuf) { free(tmp->text); free(tmp); return NOT_ENOUGH_MEMORY; } else { tmp->text = tempbuf; } } else { tmp->text = malloc(bfl + 1024); if (!tmp->text) { free(tmp); return NOT_ENOUGH_MEMORY; } else { tmp->text[0] = 0; } } hlpbsz += bfl + 1024; } strlcpy((char *)(tmp->text + hlpsiz), (char *)buf, 1024); hlpsiz += bfl; ++tmp->lines; } if (buf[0] == '}') { /* set new help screen as actual one */ tmp->prev = help_actual; tmp->next = NULL; if (help_actual) { help_actual->next = tmp; } help_actual = tmp; } else { fprintf(stderr, "\nHelp file '%s' is not properly ended with } on new line.\n", filename); fprintf(stderr, "Do you want to accept incomplete help screen (y/n)?"); fflush(stderr); if (fgets((char *)buf, 8, stdin) == NULL || (buf[0] | 0x20) != 'y') { free(tmp->text); free(tmp); return 0; } else { tmp->prev = help_actual; tmp->next = NULL; if (help_actual) { help_actual->next = tmp; } help_actual = tmp; } } } } jfclose(fd); /* close help file */ fprintf(stderr, "done\n"); while (help_actual && help_actual->prev) { /* move to first help screen */ help_actual = help_actual->prev; } return 0; } /* * Find context help - find help entry with the same name */ struct help * find_context_help(const unsigned char *name) { struct help *tmp = help_actual; while (tmp->prev != NULL) /* find the first help entry */ tmp = tmp->prev; while (tmp != NULL && strcmp(tmp->name, name) != 0) tmp = tmp->next; return tmp; } /* * Display help text */ void help_display(SCREEN *t) { unsigned char *str; int y, x, z; int atr = 0; if (help_actual) { str = help_actual->text; } else { str = NULL; } for (y = skiptop; y != t->wind; ++y) { if (t->t->updtab[y]) { unsigned char *start = str; int width=0; int nspans=0; int spanwidth; int spancount=0; int spanextra; /* First pass: count no. springs \| and determine minimum width */ while(*str && *str!='\n') if (*str++ == '\\') switch(*str) { case 'i': case 'I': case 'u': case 'U': case 'd': case 'D': case 'b': case 'B': case 'f': case 'F': ++str; break; case '|': ++str; ++nspans; break; case 0: break; default: ++str; ++width; } else ++width; str = start; /* Now calculate span width */ if (width >= t->w - 1 || nspans==0) { spanwidth = 0; spanextra = nspans; } else { spanwidth = ((t->w - 1) - width)/nspans; spanextra = nspans - ((t->w - 1) - width - nspans*spanwidth); } /* Second pass: display text */ for (x = 0; x != t->w - 1; ++x) { if (*str == '\n' || !*str) { if (eraeol(t->t, x, y)) { return; } else { break; } } else { if (*str == '\\') { switch (*++str) { case '|': ++str; for (z=0;z!=spanwidth;++z) 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); if (spancount++ >= spanextra) { 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); ++z; } x += z-1; continue; case 'i': case 'I': atr ^= INVERSE; ++str; --x; continue; case 'u': case 'U': atr ^= UNDERLINE; ++str; --x; continue; case 'd': case 'D': atr ^= DIM; ++str; --x; continue; case 'b': case 'B': atr ^= BOLD; ++str; --x; continue; case 'f': case 'F': atr ^= BLINK; ++str; --x; continue; case 0: --x; continue; } } outatr_help(t->t, t->t->scrn + x + y * t->w, t->t->attr + x + y * t->w, x, y, *str++, atr); } } atr = 0; t->t->updtab[y] = 0; } while (*str && *str != '\n') ++str; if (*str == '\n') ++str; } } /* * Show help screen */ int help_on(SCREEN *t) { if (help_actual) { t->wind = help_actual->lines + skiptop; if ((t->h - t->wind) < FITHEIGHT) { t->wind = t->h - FITHEIGHT; } if (t->wind < 0) { t->wind = skiptop; return -1; } wfit(t); msetI(t->t->updtab + skiptop, 1, t->wind); return 0; } else { return -1; } } /* * Hide help screen */ void help_off(SCREEN *t) { t->wind = skiptop; wfit(t); } /* * Show/hide current help screen */ int u_help(BASE *base) { W *w = base->parent; struct help *new_help; if (w->huh && (new_help = find_context_help(w->huh)) != NULL) { if (help_actual != new_help) { if (w->t->wind != skiptop) help_off(w->t); help_actual = new_help; /* prepare context help */ } } if (w->t->wind == skiptop) { return help_on(w->t); /* help screen is hidden, so show the actual one */ } else { help_off(w->t); /* hide actual help screen */ return 0; } } /* * Show next help screen (if it is possible) */ int u_help_next(BASE *base) { W *w = base->parent; if (help_actual && help_actual->next) { /* is there any next help screen? */ if (w->t->wind != skiptop) { help_off(w->t); /* if help screen was visible, then hide it */ } help_actual = help_actual->next; /* change to next help screen */ return help_on(w->t); /* show actual help screen */ } else { return -1; } } /* * Show previous help screen (if it is possible) */ int u_help_prev(BASE *base) { W *w = base->parent; if (help_actual && help_actual->prev) { /* is there any previous help screen? */ if (w->t->wind != skiptop) help_off(w->t); /* if help screen was visible, then hide it */ help_actual = help_actual->prev; /* change to previous help screen */ return help_on(w->t); /* show actual help screen */ } else { return -1; } }