/* * Analogous to back_line(), but deals with "raw lines". * {{ This is supposed to be more efficient than back_line(). }} */ off_t back_raw_line(off_t curr_pos, char **linep, int *line_lenp) { int n; int c; off_t new_pos; if (curr_pos == -1 || curr_pos <= ch_zero() || ch_seek(curr_pos - 1)) return (-1); n = size_linebuf; linebuf[--n] = '\0'; for (;;) { c = ch_back_get(); if (c == '\n' || ABORT_SIGS()) { /* * This is the newline ending the previous line. * We have hit the beginning of the line. */ new_pos = ch_tell() + 1; break; } if (c == EOI) { /* * We have hit the beginning of the file. * This must be the first line in the file. * This must, of course, be the beginning of the line. */ new_pos = ch_zero(); break; } if (n <= 0) { int old_size_linebuf = size_linebuf; char *fm; char *to; if (expand_linebuf()) { /* * Overflowed the input buffer. * Pretend the line ended here. */ new_pos = ch_tell() + 1; break; } /* * Shift the data to the end of the new linebuf. */ for (fm = linebuf + old_size_linebuf - 1, to = linebuf + size_linebuf - 1; fm >= linebuf; fm--, to--) *to = *fm; n = size_linebuf - old_size_linebuf; } linebuf[--n] = c; } if (linep != NULL) *linep = &linebuf[n]; if (line_lenp != NULL) *line_lenp = size_linebuf - 1 - n; return (new_pos); }
/* * Get the next line. * A "current" position is passed and a "new" position is returned. * The current position is the position of the first character of * a line. The new position is the position of the first character * of the NEXT line. The line obtained is the line starting at curr_pos. */ off_t forw_line(off_t curr_pos) { off_t new_pos; int c; if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) return (NULL_POSITION); c = ch_forw_get(); if (c == EOI) return (NULL_POSITION); prewind(); for (;;) { if (sigs) return (NULL_POSITION); if (c == '\n' || c == EOI) { /* * End of the line. */ new_pos = ch_tell(); break; } /* * Append the char to the line and get the next char. */ if (pappend(c)) { /* * The char won't fit in the line; the line * is too long to print in the screen width. * End the line here. */ new_pos = ch_tell() - 1; break; } c = ch_forw_get(); } (void) pappend('\0'); if (squeeze && *line == '\0') { /* * This line is blank. * Skip down to the last contiguous blank line * and pretend it is the one which we are returning. */ while ((c = ch_forw_get()) == '\n') if (sigs) return (NULL_POSITION); if (c != EOI) (void) ch_back_get(); new_pos = ch_tell(); } return (new_pos); }
/* * Analogous to back_line(), but deals with "raw lines". * {{ This is supposed to be more efficient than back_line(). }} */ off_t back_raw_line(off_t curr_pos) { char *p; int c; off_t new_pos; if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || ch_seek(curr_pos-1)) return (NULL_POSITION); p = &linebuf[sizeof(linebuf)]; *--p = '\0'; for (;;) { c = ch_back_get(); if (c == '\n') { /* * This is the newline ending the previous line. * We have hit the beginning of the line. */ new_pos = ch_tell() + 1; break; } if (c == EOI) { /* * We have hit the beginning of the file. * This must be the first line in the file. * This must, of course, be the beginning of the line. */ new_pos = (off_t)0; break; } if (p <= linebuf) { /* * Overflowed the input buffer. * Pretend the line ended here. */ new_pos = ch_tell() + 1; break; } *--p = c; } line = p; return (new_pos); }
/* * Get the mark structure identified by a character. * The mark struct may come either from the mark table * or may be constructed on the fly for certain characters like ^, $. */ static struct mark * getmark(int c) { register struct mark *m; static struct mark sm; switch (c) { case '^': /* * Beginning of the current file. */ m = &sm; m->m_scrpos.pos = ch_zero(); m->m_scrpos.ln = 0; m->m_ifile = curr_ifile; break; case '$': /* * End of the current file. */ if (ch_end_seek()) { error("Cannot seek to end of file", NULL_PARG); return (NULL); } m = &sm; m->m_scrpos.pos = ch_tell(); m->m_scrpos.ln = sc_height-1; m->m_ifile = curr_ifile; break; case '.': /* * Current position in the current file. */ m = &sm; get_scrpos(&m->m_scrpos); m->m_ifile = curr_ifile; break; case '\'': /* * The "last mark". */ m = &marks[LASTMARK]; break; default: /* * Must be a user-defined mark. */ m = getumark(c); if (m == NULL) break; if (m->m_scrpos.pos == -1) { error("Mark not set", NULL_PARG); return (NULL); } break; } return (m); }
/* * Analogous to forw_line(), but deals with "raw lines": * lines which are not split for screen width. * {{ This is supposed to be more efficient than forw_line(). }} */ off_t forw_raw_line(off_t curr_pos, char **linep, int *line_lenp) { int n; int c; off_t new_pos; if (curr_pos == -1 || ch_seek(curr_pos) || (c = ch_forw_get()) == EOI) return (-1); n = 0; for (;;) { if (c == '\n' || c == EOI || ABORT_SIGS()) { new_pos = ch_tell(); break; } if (n >= size_linebuf-1) { if (expand_linebuf()) { /* * Overflowed the input buffer. * Pretend the line ended here. */ new_pos = ch_tell() - 1; break; } } linebuf[n++] = (char)c; c = ch_forw_get(); } linebuf[n] = '\0'; if (linep != NULL) *linep = linebuf; if (line_lenp != NULL) *line_lenp = n; return (new_pos); }
/* * Analogous to forw_line(), but deals with "raw lines": * lines which are not split for screen width. * {{ This is supposed to be more efficient than forw_line(). }} */ off_t forw_raw_line(off_t curr_pos) { char *p; int c; off_t new_pos; if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || (c = ch_forw_get()) == EOI) return (NULL_POSITION); p = linebuf; for (;;) { if (c == '\n' || c == EOI) { new_pos = ch_tell(); break; } if (p >= &linebuf[sizeof(linebuf)-1]) { /* * Overflowed the input buffer. * Pretend the line ended here. * {{ The line buffer is supposed to be big * enough that this never happens. }} */ new_pos = ch_tell() - 1; break; } *p++ = c; c = ch_forw_get(); } *p = '\0'; line = linebuf; return (new_pos); }
/* * Get the previous line. * A "current" position is passed and a "new" position is returned. * The current position is the position of the first character of * a line. The new position is the position of the first character * of the PREVIOUS line. The line obtained is the one starting at new_pos. */ off_t back_line(off_t curr_pos) { off_t new_pos, begin_new_pos; int c; if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || ch_seek(curr_pos-1)) return (NULL_POSITION); if (squeeze) { /* * Find out if the "current" line was blank. */ (void) ch_forw_get(); /* Skip the newline */ c = ch_forw_get(); /* First char of "current" line */ (void) ch_back_get(); /* Restore our position */ (void) ch_back_get(); if (c == '\n') { /* * The "current" line was blank. * Skip over any preceeding blank lines, * since we skipped them in forw_line(). */ while ((c = ch_back_get()) == '\n') if (sigs) return (NULL_POSITION); if (c == EOI) return (NULL_POSITION); (void) ch_forw_get(); } } /* * Scan backwards until we hit the beginning of the line. */ for (;;) { if (sigs) return (NULL_POSITION); c = ch_back_get(); if (c == '\n') { /* * This is the newline ending the previous line. * We have hit the beginning of the line. */ new_pos = ch_tell() + 1; break; } if (c == EOI) { /* * We have hit the beginning of the file. * This must be the first line in the file. * This must, of course, be the beginning of the line. */ new_pos = ch_tell(); break; } } /* * Now scan forwards from the beginning of this line. * We keep discarding "printable lines" (based on screen width) * until we reach the curr_pos. * * {{ This algorithm is pretty inefficient if the lines * are much longer than the screen width, * but I don't know of any better way. }} */ if (ch_seek(new_pos)) return (NULL_POSITION); loop: begin_new_pos = new_pos; prewind(); do { c = ch_forw_get(); if (c == EOI || sigs) return (NULL_POSITION); new_pos++; if (c == '\n') break; if (pappend(c)) { /* * Got a full printable line, but we haven't * reached our curr_pos yet. Discard the line * and start a new one. */ (void) pappend('\0'); (void) ch_back_get(); new_pos--; goto loop; } } while (new_pos < curr_pos); (void) pappend('\0'); return (begin_new_pos); }