int show_text(const char *directory, const char *file_name, const char *header) { struct stat sb; FILE *fp; int ch, cnt; char *p, lastc; int fd, nr; lastc = '\0'; (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || sb.st_size == 0) return(0); /* If short enough, and no newlines, show it on a single line.*/ if (sb.st_size <= LINE_LEN - strlen(header) - 5) { nr = read(fd, tbuf, sizeof(tbuf)); if (nr <= 0) { (void)close(fd); return(0); } for (p = tbuf, cnt = nr; cnt--; ++p) if (*p == '\n') break; if (cnt <= 1) { if (*header != '\0') (void)printf("%s: ", header); for (p = tbuf, cnt = nr; cnt--; ++p) if (*p != '\r') vputc(lastc = *p); if (lastc != '\n') (void)putchar('\n'); (void)close(fd); return(1); } else (void)lseek(fd, 0L, SEEK_SET); } if ((fp = fdopen(fd, "r")) == NULL) return(0); if (*header != '\0') (void)printf("%s:\n", header); while ((ch = getc(fp)) != EOF) if (ch != '\r') vputc(lastc = ch); if (lastc != '\n') (void)putchar('\n'); (void)fclose(fp); return(1); }
/* * Put out a control sequence to the terminal. */ static void vputs(char *cp) { while (*cp) vputc(*cp++); }
/* * Rrrrringgggggg. * If possible, use flash (VB). */ void beep(void) { if (VB) vputp(VB, 0); else vputc(CTRL('g')); }
/* * Put a character with possible tracing. */ int vputch(int c) { #ifdef TRACE if (trace) tracec(c); #endif return vputc(c); }
/* * Get a line into genbuf after gcursor. * Cnt limits the number of input characters * accepted and is used for handling the replace * single character command. Aescaped is the location * where we stick a termination indicator (whether we * ended with an ESCAPE or a newline/return. * * We do erase-kill type processing here and also * are careful about the way we do this so that it is * repeatable. (I.e. so that your kill doesn't happen, * when you repeat an insert if it was escaped with \ the * first time you did it. */ char * vgetline(int cnt, char *gcursor, bool *aescaped) { register int c, ch; register char *cp; int x, y, iwhite; char *iglobp; void (*OO)() = Outchar; /* * Clear the output state and counters * for autoindent backwards motion (counts of ^D, etc.) * Remember how much white space at beginning of line so * as not to allow backspace over autoindent. */ *aescaped = 0; ogcursor = gcursor; flusho(); CDCNT = 0; HADUP = 0; HADZERO = 0; gobbled = 0; iwhite = whitecnt(genbuf); iglobp = vglobp; /* * Carefully avoid using vinschar in the echo area. */ if (splitw) Outchar = vputchar; else { Outchar = vinschar; vprepins(); } for (;;) { if (gobblebl) gobblebl--; if (cnt != 0) { cnt--; if (cnt == 0) goto vadone; } ch = c = getkey() & (QUOTE|TRIM); if (!iglobp) { /* * Erase-kill type processing. * Only happens if we were not reading * from untyped input when we started. * Map users erase to ^H, kill to -1 for switch. */ if (c == tty.c_cc[VERASE]) c = CTRL('h'); else if (c == tty.c_cc[VKILL]) c = -1; switch (c) { /* * ^? Interrupt drops you back to visual * command mode with an unread interrupt * still in the input buffer. * * ^\ Quit does the same as interrupt. * If you are a ex command rather than * a vi command this will drop you * back to command mode for sure. */ case ATTN: case QUIT: ungetkey(c); goto vadone; /* * ^H Backs up a character in the input. * * BUG: Can't back around line boundaries. * This is hard because stuff has * already been saved for repeat. */ case CTRL('h'): bakchar: cp = gcursor - 1; if (cp < ogcursor) { beep(); continue; } goto vbackup; /* * ^W Back up a white/non-white word. */ case CTRL('w'): wdkind = 1; for (cp = gcursor; cp > ogcursor && isspace((int)cp[-1]); cp--) continue; for (c = wordch(cp - 1); cp > ogcursor && wordof(c, cp - 1); cp--) continue; goto vbackup; /* * users kill Kill input on this line, back to * the autoindent. */ case -1: cp = ogcursor; vbackup: if (cp == gcursor) { beep(); continue; } endim(); *cp = 0; c = cindent(); vgotoCL(qcolumn(cursor - 1, genbuf)); if (doomed >= 0) doomed += c - cindent(); gcursor = cp; continue; /* * \ Followed by erase or kill * maps to just the erase or kill. */ case '\\': x = destcol, y = destline; ex_putchar('\\'); vcsync(); c = getkey(); if (c == tty.c_cc[VERASE] || c == tty.c_cc[VKILL]) { vgoto(y, x); if (doomed >= 0) doomed++; goto def; } ungetkey(c), c = '\\'; goto noput; /* * ^Q Super quote following character * Only ^@ is verboten (trapped at * a lower level) and \n forces a line * split so doesn't really go in. * * ^V Synonym for ^Q */ case CTRL('q'): case CTRL('v'): x = destcol, y = destline; ex_putchar('^'); vgoto(y, x); c = getkey(); if (c != NL) { if (doomed >= 0) doomed++; goto def; } break; } } /* * If we get a blank not in the echo area * consider splitting the window in the wrapmargin. */ if (c == ' ' && !splitw) { if (gobblebl) { gobbled = 1; continue; } if (value(WRAPMARGIN) && outcol >= WCOLS - value(WRAPMARGIN)) { c = NL; gobblebl = 2; } } switch (c) { /* * ^M Except in repeat maps to \n. */ case CR: if (vglobp) goto def; c = '\n'; /* presto chango ... */ /* * \n Start new line. */ case NL: *aescaped = c; goto vadone; /* * escape End insert unless repeat and more to repeat. */ case ESCAPE: if (vglobp && *vglobp) goto def; goto vadone; /* * ^D Backtab. * ^T Software forward tab. * * Unless in repeat where this means these * were superquoted in. */ case CTRL('d'): case CTRL('t'): if (vglobp) goto def; /* fall into ... */ /* * ^D|QUOTE Is a backtab (in a repeated command). */ case CTRL('d') | QUOTE: *gcursor = 0; cp = vpastwh(genbuf); c = whitecnt(genbuf); if (ch == CTRL('t')) { /* * ^t just generates new indent replacing * current white space rounded up to soft * tab stop increment. */ if (cp != gcursor) /* * BUG: Don't hack ^T except * right after initial * white space. */ continue; cp = genindent(iwhite = backtab(c + value(SHIFTWIDTH) + 1)); ogcursor = cp; goto vbackup; } /* * ^D works only if we are at the (end of) the * generated autoindent. We count the ^D for repeat * purposes. */ if (c == iwhite && c != 0) { if (cp == gcursor) { iwhite = backtab(c); CDCNT++; ogcursor = cp = genindent(iwhite); goto vbackup; } else if (&cp[1] == gcursor && (*cp == '^' || *cp == '0')) { /* * ^^D moves to margin, then back * to current indent on next line. * * 0^D moves to margin and then * stays there. */ HADZERO = *cp == '0'; ogcursor = cp = genbuf; HADUP = 1 - HADZERO; CDCNT = 1; endim(); back1(); vputc(' '); goto vbackup; } } if (vglobp && vglobp - iglobp >= 2 && (vglobp[-2] == '^' || vglobp[-2] == '0') && gcursor == ogcursor + 1) goto bakchar; continue; default: /* * Possibly discard control inputs. */ if (!vglobp && junk(c)) { beep(); continue; } def: ex_putchar(c); noput: if (gcursor > &genbuf[LBSIZE - 2]) error("Line too long"); *gcursor++ = c & TRIM; vcsync(); #ifdef LISP if (value(SHOWMATCH) && !iglobp) if (c == ')' || c == '}') lsmatch(gcursor); #endif continue; } } vadone: *gcursor = 0; Outchar = OO; endim(); return (gcursor); }
// Build and pop up a buffer containing a list of all screens and their associated buffers. Render buffer and return status. int showScreens(Value *rp,int n) { Buffer *slistp; EScreen *scrp; // Pointer to current screen to list. EWindow *winp; // Pointer into current screens window list. uint wnum; StrList rpt; int windcol = 7; int filecol = 37; char *strp,wkbuf[filecol + 16]; // Get a buffer and open a string list. if(sysbuf(text160,&slistp) != SUCCESS) // "Screens" return rc.status; if(vopen(&rpt,NULL,false) != 0) return vrcset(); // Construct the header lines. if(vputs(text89,&rpt) != 0 || vputc('\n',&rpt) != 0 || // "Screen Window Buffer File" vputs("------ ------ -------------------- -------------------------------",&rpt) != 0) return vrcset(); // For all screens... scrp = sheadp; do { // Store the screen number. sprintf(wkbuf,"\n%4hu ",scrp->s_num); strp = strchr(wkbuf,'\0'); // List screen's window numbers and buffer names. wnum = 0; winp = scrp->s_wheadp; do { Buffer *bufp = winp->w_bufp; // Indent if not first time through. if(wnum != 0) { wkbuf[0] = '\n'; strp = wkbuf + 1; do { *strp++ = ' '; } while(strp <= wkbuf + windcol); } // Store window number, buffer name, and filename. sprintf(strp,"%4u %c%s",++wnum,(bufp->b_flags & BFCHGD) ? '*' : ' ',bufp->b_bname); strp = strchr(strp,'\0'); if(bufp->b_fname != NULL) // Pad if filename exists. do { *strp++ = ' '; } while(strp <= wkbuf + filecol); *strp = '\0'; // Save buffer and add filename. if(vputs(wkbuf,&rpt) != 0 || (bufp->b_fname != NULL && vputs(bufp->b_fname,&rpt) != 0)) return vrcset(); // On to the next window. } while((winp = winp->w_nextp) != NULL); // On to the next screen. } while((scrp = scrp->s_nextp) != NULL); // Add the results to the buffer. if(vclose(&rpt) != 0) return vrcset(); if(bappend(slistp,rpt.sl_vp->v_strp) != SUCCESS) return rc.status; // Display results. return render(rp,n < 0 ? -2 : n,slistp,RENDRESET | (n != INT_MIN && n < -1 ? RENDALTML : 0)); }
/* * Move cursor to line y, column x, handling wraparound and scrolling. */ void vgoto(register int y, register int x) { register cell *tp; register int c; /* * Fold the possibly too large value of x. */ if (x >= WCOLS) { y += x / WCOLS; x %= WCOLS; } #ifdef MB if (y >= 0 && y <= WLINES && mb_cur_max > 1 && !insmode) { while (x > 0 && (vtube[y][x]&(MULTICOL|TRIM)) == MULTICOL && vtube[y][x-1] & MULTICOL && (vtube[y][x-1]&(MULTICOL|TRIM)) != MULTICOL) x--; } #endif /* MB */ if (y < 0) error(catgets(catd, 1, 238, "Internal error: vgoto")); if (outcol >= WCOLS) { if (AM) { outline += outcol / WCOLS; outcol %= WCOLS; } else outcol = WCOLS - 1; } /* * In a hardcopy or glass crt open, print the stuff * implied by a motion, or backspace. */ if (state == HARDOPEN || state == ONEOPEN) { if (y != outline) error(catgets(catd, 1, 239, "Line too long for open")); if (x + 1 < outcol - x || (outcol > x && !BS)) destcol = 0, fgoto(); tp = vtube[WBOT] + outcol; while (outcol != x) if (outcol < x) { if (*tp == 0) *tp = ' '; c = *tp++ & TRIM; vputc(c && (!OS || EO) ? c : ' '); outcol++; } else { if (BC) vputp(BC, 0); else vputc('\b'); outcol--; } destcol = outcol = x; destline = outline; return; } /* * If the destination position implies a scroll, do it. */ destline = y; if (destline > WBOT && (!splitw || destline > WECHO)) { endim(); vrollup(destline); } /* * If there really is a motion involved, do it. * The check here is an optimization based on profiling. */ destcol = x; if ((destline - outline) * WCOLS != destcol - outcol) { if (!MI) endim(); fgoto(); } }
/* * Put the character c on the screen at the current cursor position. * This routine handles wraparound and scrolling and understands not * to roll when splitw is set, i.e. we are working in the echo area. * There is a bunch of hacking here dealing with the difference between * QUOTE, QUOTE|' ', and ' ' for CONCEPT-100 like terminals, and also * code to deal with terminals which overstrike, including CRT's where * you can erase overstrikes with some work. CRT's which do underlining * implicitly which has to be erased (like CONCEPTS) are also handled. */ int vputchar(register int c) { register cell *tp; register int d, m, n; #ifndef BIT8 c &= (QUOTE|TRIM); #endif #ifdef TRACE if (trace) tracec(c); #endif /* Fix problem of >79 chars on echo line. */ if (destcol >= WCOLS-1 && splitw && destline == WECHO) pofix(); #ifdef MB if (mb_cur_max > 1) { if (c == MULTICOL) return c; /* * If a multicolumn character extends beyond the screen * width, it must be put on the next line. A tilde is * printed as an indicator but must disappear when the * text is moved at a later time. */ if (c == ('~'|INVBIT|QUOTE)) c = '~'|INVBIT; else if (c == ('~'|INVBIT)) return c; else if (destcol < WCOLS && destcol + colsc(c==QUOTE ? ' ' : c&TRIM&~MULTICOL) - 1 >= WCOLS) vputchar('~'|INVBIT|QUOTE); } #endif /* MB */ if (destcol >= WCOLS) { destline += destcol / WCOLS; destcol %= WCOLS; } if (destline > WBOT && (!splitw || destline > WECHO)) vrollup(destline); tp = vtube[destline] + destcol; if (c == QUOTE) { if (insmode) { /* * When in insert mode, tabs have to expand * to real, printed blanks. */ c = ' ' | QUOTE; goto def; } if (*tp == 0) { /* * A ``space''. */ if ((hold & HOLDPUPD) == 0) *tp = QUOTE; destcol++; return c; } /* * A ``space'' ontop of a part of a tab. */ if (*tp & QUOTE) { destcol++; return c; } c = ' ' | QUOTE; goto def; } #ifdef notdef #ifdef BIT8 if (c == ' ' | QUOTE) { c = ' '; goto def; } #endif #endif switch (c) { case '\t': vgotab(); return c; case ' ': /* * We can get away without printing a space in a number * of cases, but not always. We get away with doing nothing * if we are not in insert mode, and not on a CONCEPT-100 * like terminal, and either not in hardcopy open or in hardcopy * open on a terminal with no overstriking, provided, * in all cases, that nothing has ever been displayed * at this position. Ugh. */ if (!insmode && !IN && (state != HARDOPEN || OS) && (*tp"E)) { *tp = ' '; destcol++; return c; } goto def; def: default: d = *tp & TRIM; /* * Now get away with doing nothing if the characters * are the same, provided we are not in insert mode * and if we are in hardopen, that the terminal has overstrike. */ if ((d & ~MULTICOL) == (c & TRIM & ~MULTICOL) && !insmode && (state != HARDOPEN || OS) && c != MULTICOL) { n = colsc(d); for (m = 1; m < n; m++) if ((tp[m] & (MULTICOL|TRIM)) != MULTICOL) break; if (m == n) { if ((hold & HOLDPUPD) == 0) *tp = c | (n > 1 ? MULTICOL : 0); destcol += n; return c; } } /* * Backwards looking optimization. * The low level cursor motion routines will use * a cursor motion right sequence to step 1 character * right. On, e.g., a DM3025A this is 2 characters * and printing is noticeably slower at 300 baud. * Since the low level routines are not allowed to use * spaces for positioning, we discover the common * case of a single space here and force a space * to be printed. */ if (destcol == outcol + 1 && tp[-1] == ' ' && outline == destline) { vputc(' '); outcol++; } /* * This is an inline expansion a call to vcsync() dictated * by high frequency in a profile. */ if (outcol != destcol || outline != destline) vgoto(destline, destcol); /* * Deal with terminals which have overstrike. * We handle erasing general overstrikes, erasing * underlines on terminals (such as CONCEPTS) which * do underlining correctly automatically (e.g. on nroff * output), and remembering, in hardcopy mode, * that we have overstruct something. */ if (!insmode && d && d != ' ' && d != (c & TRIM)) { if (EO && (OS || UL && (c == '_' || d == '_'))) { vputc(' '); outcol++, destcol++; back1(); } else rubble = 1; } /* * Unless we are just bashing characters around for * inner working of insert mode, update the display. */ if ((hold & HOLDPUPD) == 0) *tp = c; /* * In insert mode, put out the IC sequence, padded * based on the depth of the current line. * A terminal which had no real insert mode, rather * opening a character position at a time could do this. * Actually should use depth to end of current line * but this rarely matters. */ #ifdef notdef if (insmode) #else /* * It seems today's termcap writers consider this * an either-or situation; if both im and ic * are used vi puts out additional spaces. * * SVR4 ex does not include this change. If it hits * your terminal, change back to the old way and * mail me a description. * * GR July 2000 */ if (insmode && (!IM || !*IM)) #endif /* !notdef */ { n = colsc(c&TRIM); for (m = 0; m < n; m++) vputp(IC, DEPTH(vcline)); } vputc(c & TRIM); /* * In insert mode, IP is a post insert pad. */ if (insmode) vputp(IP, DEPTH(vcline)); destcol++, outcol++; /* * CONCEPT braindamage in early models: after a wraparound * the next newline is eaten. It's hungry so we just * feed it now rather than worrying about it. * Fixed to use return linefeed to work right * on vt100/tab132 as well as concept. */ if (XN && outcol % WCOLS == 0) { vputc('\r'); vputc('\n'); } } #ifdef MB if (mb_cur_max > 1 && (d = colsc(c&TRIM&~MULTICOL)) > 1) { if ((hold & HOLDPUPD) == 0) *tp |= MULTICOL; while (--d) { if ((hold & HOLDPUPD) == 0) *++tp = MULTICOL; destcol++; outcol++; } } #endif /* MB */ return c; }