/* ARGSUSED */ int apropos_command(int f, int n) { struct buffer *bp; struct list *fnames, *el; char string[32]; if (eread("apropos: ", string, sizeof(string), EFNUL | EFNEW) == NULL) return (ABORT); /* FALSE means we got a 0 character string, which is fine */ bp = bfind("*help*", TRUE); if (bclear(bp) == FALSE) return (FALSE); fnames = complete_function_list(""); for (el = fnames; el != NULL; el = el->l_next) { char buf[32]; if (strstr(el->l_name, string) == NULL) continue; buf[0] = '\0'; findbind(fundamental_map, name_function(el->l_name), buf, sizeof(buf)); if (addlinef(bp, "%-32s%s", el->l_name, buf) == FALSE) { free_file_list(fnames); return (FALSE); } } free_file_list(fnames); return (popbuftop(bp, WNONE)); }
/* * Multiplex read, write on socket fd passed. Put output in outbp * Poll on the fd for both read and write readiness. */ int iomux(int fd, char* const text, int len, struct buffer *outbp) { struct pollfd pfd[1]; int nfds; char *textcopy; textcopy = text; fcntl(fd, F_SETFL, O_NONBLOCK); pfd[0].fd = fd; /* There is nothing to write if len is zero * but the cmd's output should be read so shutdown * the socket for writing only and don't wait for POLLOUT */ if (len == 0) { shutdown(fd, SHUT_WR); pfd[0].events = POLLIN; } else pfd[0].events = POLLIN | POLLOUT; while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 || (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) { if (pfd[0].revents & POLLOUT && len > 0) pwriteout(fd, &textcopy, &len); else if (pfd[0].revents & POLLIN) if (preadin(fd, outbp) == FALSE) break; if (len == 0 && pfd[0].events & POLLOUT) pfd[0].events = POLLIN; } close(fd); /* In case if last line doesn't have a '\n' add the leftover * characters to buffer. */ if (leftover[0] != '\0') { addline(outbp, leftover); leftover[0] = '\0'; } if (nfds == 0) { dobeep(); ewprintf("poll timed out"); return (FALSE); } else if (nfds == -1) { dobeep(); ewprintf("poll error"); return (FALSE); } return (popbuftop(outbp, WNONE)); }
/* ARGSUSED */ int wallchart(int f, int n) { int m; struct buffer *bp; bp = bfind("*help*", TRUE); if (bclear(bp) != TRUE) /* clear it out */ return (FALSE); bp->b_flag |= BFREADONLY; for (m = curbp->b_nmodes; m > 0; m--) { if ((addlinef(bp, "Local keybindings for mode %s:", curbp->b_modes[m]->p_name) == FALSE) || (showall(bp, curbp->b_modes[m]->p_map, "") == FALSE) || (addline(bp, "") == FALSE)) return (FALSE); } if ((addline(bp, "Global bindings:") == FALSE) || (showall(bp, fundamental_map, "") == FALSE)) return (FALSE); return (popbuftop(bp, WNONE)); }
/* * Do completion on a list of objects, listing instead of completing. */ static int complt_list(int flags, char *buf, int cpos) { struct list *lh, *lh2, *lh3; struct list *wholelist = NULL; struct buffer *bp; int i, maxwidth, width; int preflen = 0; int oldrow = ttrow; int oldcol = ttcol; int oldhue = tthue; char *linebuf; size_t linesize, len; char *cp; lh = NULL; ttflush(); /* The results are put into a completion buffer. */ bp = bfind("*Completions*", TRUE); if (bclear(bp) == FALSE) return (FALSE); /* * First get the list of objects. This list may contain only * the ones that complete what has been typed, or may be the * whole list of all objects of this type. They are filtered * later in any case. Set wholelist if the list has been * cons'ed up just for us, so we can free it later. We have * to copy the buffer list for this function even though we * didn't for complt. The sorting code does destructive * changes to the list, which we don't want to happen to the * main buffer list! */ if ((flags & EFBUF) != 0) wholelist = lh = copy_list(&(bheadp->b_list)); else if ((flags & EFFUNC) != 0) { buf[cpos] = '\0'; wholelist = lh = complete_function_list(buf); } else if ((flags & EFFILE) != 0) { buf[cpos] = '\0'; wholelist = lh = make_file_list(buf); /* * We don't want to display stuff up to the / for file * names preflen is the list of a prefix of what the * user typed that should not be displayed. */ cp = strrchr(buf, '/'); if (cp) preflen = cp - buf + 1; } else panic("broken complt call: flags"); /* * Sort the list, since users expect to see it in alphabetic * order. */ lh2 = lh; while (lh2 != NULL) { lh3 = lh2->l_next; while (lh3 != NULL) { if (strcmp(lh2->l_name, lh3->l_name) > 0) { cp = lh2->l_name; lh2->l_name = lh3->l_name; lh3->l_name = cp; } lh3 = lh3->l_next; } lh2 = lh2->l_next; } /* * First find max width of object to be displayed, so we can * put several on a line. */ maxwidth = 0; lh2 = lh; while (lh2 != NULL) { for (i = 0; i < cpos; ++i) { if (buf[i] != lh2->l_name[i]) break; } if (i == cpos) { width = strlen(lh2->l_name); if (width > maxwidth) maxwidth = width; } lh2 = lh2->l_next; } maxwidth += 1 - preflen; /* * Now do the display. Objects are written into linebuf until * it fills, and then put into the help buffer. */ linesize = MAX(ncol, maxwidth) + 1; if ((linebuf = malloc(linesize)) == NULL) { free_file_list(wholelist); return (FALSE); } width = 0; /* * We're going to strlcat() into the buffer, so it has to be * NUL terminated. */ linebuf[0] = '\0'; for (lh2 = lh; lh2 != NULL; lh2 = lh2->l_next) { for (i = 0; i < cpos; ++i) { if (buf[i] != lh2->l_name[i]) break; } /* if we have a match */ if (i == cpos) { /* if it wraps */ if ((width + maxwidth) > ncol) { addline(bp, linebuf); linebuf[0] = '\0'; width = 0; } len = strlcat(linebuf, lh2->l_name + preflen, linesize); width += maxwidth; if (len < width && width < linesize) { /* pad so the objects nicely line up */ memset(linebuf + len, ' ', maxwidth - strlen(lh2->l_name + preflen)); linebuf[width] = '\0'; } } } if (width > 0) addline(bp, linebuf); free(linebuf); /* * Note that we free lists only if they are put in wholelist lists * that were built just for us should be freed. However when we use * the buffer list, obviously we don't want it freed. */ free_file_list(wholelist); popbuftop(bp, WEPHEM); /* split the screen and put up the help * buffer */ update(CMODE); /* needed to make the new stuff actually * appear */ ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */ ttcolor(oldhue); /* with arbitrary color */ ttflush(); return (0); }