static char rcsid[] = "$Id: help.c,v 1.3 1992/11/08 23:12:34 mike Exp $"; /* $Log: help.c,v $ * Revision 1.3 1992/11/08 23:12:34 mike * - Changed the list of filename extensions which are ignored * for filename completion. * * Revision 1.2 1992/09/14 18:03:42 mike * - First set of changes for the Atari ST/TT version. * * Revision 1.1 1992/09/05 01:13:32 mike * Initial revision * */ /* * HELP.C: The "User Friendly" part of ME */ /* Copyright 1990, 1991, 1992 Craig Durland * Distributed under the terms of the GNU General Public License. * Distributed "as is", without warranties of any kind, but comments, * suggestions and bug reports are welcome. */ #include "me2.h" #include "mm.h" #include "bind.h" #include "config.h" extern Binding bindings[]; extern char *nanex(), *strcpy(), *strcat(), *strchr(); extern int msize, pbsize, sbsize, svsize; extern KeyTable gkeys; /* in bind.c */ extern MuttCmd mutcmds[], sysvars[]; extern PgmName pnames[]; /* mmaux.c */ /* ******************************************************************** */ /* ************** Help buffer ***************************************** */ /* ******************************************************************** */ /* Convert binding table entry to readable text form. * Lists all keys that are bound to a command i (a pgm or system command). * Returns ptr to start of buf. * Format of returned string: * name-of-function * name-of-function ..........C-3 */ static char *verbose(buf,i,type) char *buf; int i, type; /* SYS or PGM */ { int j, s, n; register UKey *key; if (type == PGM) { strcpy(buf,pnames[i].name); i = pnames[i].index; } else strcpy(buf,bindings[i].name); for (key = gkeys.table, n = sizeof_dTable(&gkeys), s = TRUE; n--; key++) if (type == key->type && key->index == i) { strcat(buf," "); if (s) { for (j = strlen(buf); j < 27; j++) buf[j] = '.'; buf[j] = '\0'; s = FALSE; } xpandkey(buf,key->keycode); } return buf; } static int dpunt; /* a global helper variable */ static void add_help_string(bp,apropos,pattern,text) Buffer *bp; char *text, *pattern; { extern char *str_in_str(); if (dpunt) return; if (!apropos || str_in_str(text, pattern)) dpunt = !buffer_append(bp,text); } /* * Create help buffer * This routine displays the help buffer. If one does not exist then the * one is created. The buffer is cleared and the strings from the binding * tables are written into the buffer. */ disp_help(apropos,word) int apropos; char *word; { register Buffer *bp; char text[128]; int i; dpunt = FALSE; /* create help buffer if don't exist */ if (!(bp = bfind("*Help*",TRUE,BFNOCARE))) return FALSE; clear_buffer(bp); set_buffer_modified(bp,FALSE); /* Buffer has not changed (even if it did) */ if (!buffer_append(bp,"PROGRAMS:")) return FALSE; for (i = 0; i < pbsize; i++) add_help_string(bp,apropos,word,verbose(text,i,PGM)); if (!buffer_append(bp,"") || !buffer_append(bp,"COMMANDS:")) return FALSE; for (i = 0; i < sbsize; i++) add_help_string(bp,apropos,word,verbose(text,i,SYS)); if (!buffer_append(bp,"") || !buffer_append(bp,"FUNCTIONS:")) return FALSE; for (i = 0; i < msize; i++) add_help_string(bp,apropos,word,mutcmds[i].name); if (!buffer_append(bp,"") || !buffer_append(bp,"SYSTEM VARS:")) return FALSE; for (i = 0; i < svsize; i++) add_help_string(bp,apropos,word,sysvars[i].name); return bpopup(bp,FALSE); } /* discribe-bindings. Not bound */ dscrib_bindings(f,n) { return disp_help(FALSE,""); } /* * Apropos: list commands with keyword in them. * Simular to dscib_bindings() */ apropos(f,n) int f,n; { char word[40]; int i; if ((i = mlreply("apropos keyword: ",word,sizeof(word),CC_SYS|CC_PGM))!= TRUE) return i; return disp_help(TRUE,word); } void dscrib_key(keyname,boundto) char *keyname, *boundto; { extern KeyCode to_keycode(); extern UKey *lookupkey(); KeyCode keycode; UKey *key; keycode = to_keycode(keyname,TRUE); *boundto = '\0'; if ((key = lookupkey(keycode))) { register int n, i; register PgmName *pn; i = key->index; if (PGM == key->type) { for (pn = pnames, n = pbsize; n--; pn++) if (pn->index == i) { strcpy(boundto,pn->name); break; } } else strcpy(boundto,bindings[i].name); } } int describe_key(f,n) int f; int n; { char s[64]; char two[2]; char *p; KeyCode kc; short ascii; mlputs("Describe Key: "); kc = getkey(); s[0] = '\0'; if ((ascii = kc & 0xff) >= ' ') { if (kc & PFIX1) strcat(s,"C-X"); if (kc & META) strcpy(s,"M-"); if (kc & PFIX2) strcat(s,"A-"); if (kc & CTRL) strcat(s,"C-"); if (kc & SHIFT) strcat(s,"S-"); if (kc & BUTTON) strcat(s,"B-"); if (kc & SOFKEY) strcat(s,"F-"); two[0] = ascii; two[1] = '\0'; strcat(s,two); } else { two[0] = ascii + 'A' - 1; two[1] = '\0'; strcat(s,two); } p = s + strlen(s); dscrib_key(s, p + 1); *p++ = ' '; if (!*p) strcpy(p,"not bound"); mlwrite(s); return TRUE; } /* ******************************************************************** */ /* ******** Command Completion **************************************** */ /* ******************************************************************** */ ranger2(word,matched,commonchars) /* buffer list */ char *word, *commonchars; int *matched; { char c, buf[80]; Buffer *a = NULL, *b = NULL, *bp; register int len; strcpy(buf,word); len = strlen(buf); *commonchars = '\0'; tryagain: for (bp = first_buffer; bp; bp = bp->nextb) { if (!(bp->b_flags & BFHIDDEN) && strncmp(buf,get_dString(bp->b_bname),len) == 0) if (a == NULL) a = bp; else b = bp; } if (a == NULL) /* no match */ if (len > 0) { buf[--len] = '\0'; goto tryagain; } else { *matched = 0; return FALSE; } *matched = len; if (b == NULL) /* only one instance of at least part of word */ { strcpy(commonchars,get_dString(a->b_bname)); return (0 == strcmp(word,commonchars)); /* maybe a commplete match */ } b = b->nextb; /* do it here so don't effect above test */ for (len--; c = *(get_dString(a->b_bname) + len); len++) for (bp = a->nextb; bp != b; bp = bp->nextb) if (!(bp->b_flags & BFHIDDEN) && *(get_dString(bp->b_bname)+len) != c) goto done; done: strcpy(commonchars,get_dString(a->b_bname)); commonchars[len] = '\0'; return FALSE; } /* file names for completation */ static declare_and_init_dTable(ftable,char *); static void zik(); /* selector: or the lists you want. */ #define RANGERS 6 /* number of lists I can complete */ complete(word,selector) char *word; unsigned int selector; { char *ptr, commonchars[128], completed_word[128]; int j, matched, max_matched = -1; unsigned int bit; *completed_word = '\0'; for (bit = 1, j = RANGERS; j--; bit <<= 1) { switch (selector & bit) { default: continue; /* (selector & bit)==0 means do nothing */ case CC_SYS: /* system bindings */ if (ranger1(&bindings[0].name,sbsize,sizeof(bindings[0]), word,&matched,commonchars)) return TRUE; break; case CC_PGM: /* programs */ if (ranger1(&pnames[0].name, pbsize,sizeof(PgmName), word,&matched,commonchars)) return TRUE; break; case CC_MUTT: /* Mutt cmds */ if (ranger1(&mutcmds[0].name,msize,sizeof(mutcmds[0]), word,&matched,commonchars)) return TRUE; break; case CC_BUF: /* buffer names */ if (ranger2(word,&matched,commonchars)) return TRUE; break; case CC_SYSVAR: /* system variables */ if (ranger1(&sysvars[0].name,svsize,sizeof(sysvars[0]), word,&matched,commonchars)) return TRUE; break; #if FILENAME_COMPLETION case CC_FNAME: /* file names */ ptr = nanex(word); /* just change the name & extension */ if (*ptr == '\0') return FALSE; zik(word); if (0 == sizeof_dTable(&ftable)) return FALSE; if (ranger1(ftable.table,sizeof_dTable(&ftable), dTable_BLOBSIZE(&ftable), ptr,&matched,commonchars)) return TRUE; break; #endif } if (0 == matched) continue; if (matched > max_matched) { max_matched = matched; strcpy(completed_word,commonchars); continue; } if (matched == max_matched) { while (completed_word[matched]!='\0' && completed_word[matched] == commonchars[matched]) matched++; completed_word[matched] = '\0'; } } /* if filename completion, don't change the path */ strcpy((selector & CC_FNAME) ? ptr : word, completed_word); return TRUE; } /* ******************************************************************** */ /* ************ Questionable help ************************************* */ /* ******************************************************************** */ #define MAX_HELP_LEN 40 static int drow, dcol, dink, dlen; /* global helper variables */ static void dumper(); /* spew match word list all over screen */ void hbomb(word,selector) char *word; unsigned int selector; { Buffer *bp; int j, len = strlen(word); drow = dcol = dink = dpunt = 0; dlen = MAX_HELP_LEN; if (selector & CC_PGM) /* pgms */ for (j = 0; j < pbsize; j++) dumper(pnames[j].name,word,len); if (selector & CC_SYS) /* system bindings */ for (j = 0; j < sbsize; j++) dumper(bindings[j].name,word,len); if (selector & CC_MUTT) /* Mutt cmds */ for (j = 0; j < msize; j++) dumper(mutcmds[j].name,word,len); if (selector & CC_BUF) /* buffer names */ for (bp = first_buffer; bp; bp = bp->nextb) if (!(bp->b_flags & BFHIDDEN)) dumper(get_dString(bp->b_bname),word,len); if (selector & CC_SYSVAR) /* system variables */ for (j = 0; j < svsize; j++) dumper(sysvars[j].name,word,len); #if FILENAME_COMPLETION if (selector & CC_FNAME) /* file names */ { zik(word); for (j = 0; j < sizeof_dTable(&ftable); j++) dumper(ftable.table[j],"",0); } #endif if (dcol == 0) dumper("------------------------","",0); } static void dumper(name,word,len) char *name, *word; { extern int t_nrow, t_ncol; char text[MAX_HELP_LEN+2]; if (dpunt) return; if (t_nrow-1 <= drow) /* this column hit the bottom of the screen */ { /* use next column */ dcol += dink +3; dlen = imin(t_ncol -dcol,MAX_HELP_LEN); if (dlen < 15) /* screen full, ask if they want more */ { if (dpunt = (mlyesno("More") != TRUE)) return; /* no, they don't */ dcol = 0; dlen = MAX_HELP_LEN; } drow = dink = 0; } if (strncmp(name,word,len)==0) { strncpy(text,name,dlen); text[dlen] = '\0'; dink = imax(dink,strlen(text)); vpputs(drow++,dcol, text); } } #if FILENAME_COMPLETION /* ******************************************************************** */ /* ************* File name completion and help ************************ */ /* ******************************************************************** */ /* Note: The memory used for the file names is kept around once its * allocated on the assumation that if its used once its going to be use * lots. Growth is limited by FHEAP_SIZE. This can greatly limit memory * trashing. */ extern char *ext(); #define FHEAP_SIZE 3072 static struct { int fnames, j; char heap[FHEAP_SIZE]; } fheap; static char *extensions_to_ignore[] = #if UX_OS { ".o", ".mco", NULL }; #endif #if MSDOZ { ".OBJ", ".MCO", NULL }; #endif #if ATARI { ".o", ".mco", ".prg", ".app", "tos", "ttp", NULL }; #endif static int build_fheap(fname) char *fname; { char **ptr = extensions_to_ignore; int n = strlen(fname) +1; if (fheap.j + n > FHEAP_SIZE) return 2; while (*ptr) if (strcmp(*(ptr++),ext(fname)) == 0) return 0; strcpy(fheap.heap +fheap.j,fname); fheap.j += n; fheap.fnames++; return 0; } static void build_ftable() { register char *ptr, **qtr; register int n = fheap.fnames; reset_dTable(&ftable); if (!xpand_dTable(&ftable, n, 100,20)) return; ptr = fheap.heap; qtr = ftable.table; while (n--) { #if MSDOZ lowercase(ptr); #endif *qtr++ = ptr; while (*ptr++) ; } } compare2strings(a,b) char **a, **b; { return strcmp(*a,*b); } static void zik(fname) char *fname; { char zim[256]; fheap.fnames = fheap.j = 0; strcpy(zim,fname); if (!strchr(nanex(fname),'*')) strcat(zim,"*"); fxpand(zim,FALSE,TRUE,TRUE,(char *)NULL,build_fheap); build_ftable(); ssort(ftable.table,sizeof_dTable(&ftable),dTable_BLOBSIZE(&ftable), compare2strings); } #endif