/* * 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); }
/* * Make sure the screen is displayed. */ static void make_display(void) { /* * If nothing is displayed yet, display starting from initial_scrpos. */ if (empty_screen()) { if (initial_scrpos.pos == -1) /* * {{ Maybe this should be: * jump_loc(ch_zero(), jump_sline); * but this behavior seems rather unexpected * on the first screen. }} */ jump_loc(ch_zero(), 1); else jump_loc(initial_scrpos.pos, initial_scrpos.ln); } else if (screen_trashed) { int save_top_scroll = top_scroll; int save_ignore_eoi = ignore_eoi; top_scroll = 1; ignore_eoi = 0; if (screen_trashed == 2) { /* * Special case used by ignore_eoi: re-open the input * file and jump to the end of the file. */ reopen_curr_ifile(); jump_forw(); } repaint(); top_scroll = save_top_scroll; ignore_eoi = save_ignore_eoi; } }
/* * 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); }
/* * Go to a mark. */ void gomark(int c) { struct mark *m; struct scrpos scrpos; m = getmark(c); if (m == NULL) return; /* * If we're trying to go to the lastmark and * it has not been set to anything yet, * set it to the beginning of the current file. */ if (m == &marks[LASTMARK] && m->m_scrpos.pos == -1) { m->m_ifile = curr_ifile; m->m_scrpos.pos = ch_zero(); m->m_scrpos.ln = jump_sline; } /* * If we're using lmark, we must save the screen position now, * because if we call edit_ifile() below, lmark will change. * (We save the screen position even if we're not using lmark.) */ scrpos = m->m_scrpos; if (m->m_ifile != curr_ifile) { /* * Not in the current file; edit the correct file. */ if (edit_ifile(m->m_ifile)) return; } jump_loc(scrpos.pos, scrpos.ln); }
/* * Decode a "percent" prototype character. * A prototype string may include various "percent" escapes; * that is, a percent sign followed by a single letter. * Here we decode that letter and take the appropriate action, * usually by appending something to the message being built. */ static void protochar(int c, int where) { off_t pos; off_t len; int n; off_t linenum; off_t last_linenum; IFILE h; #undef PAGE_NUM #define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - 1)) + 1) switch (c) { case 'b': /* Current byte offset */ pos = curr_byte(where); if (pos != -1) ap_pos(pos); else ap_quest(); break; case 'c': ap_int(hshift); break; case 'd': /* Current page number */ linenum = currline(where); if (linenum > 0 && sc_height > 1) ap_pos(PAGE_NUM(linenum)); else ap_quest(); break; case 'D': /* Final page number */ /* Find the page number of the last byte in the file (len-1). */ len = ch_length(); if (len == -1) { ap_quest(); } else if (len == 0) { /* An empty file has no pages. */ ap_pos(0); } else { linenum = find_linenum(len - 1); if (linenum <= 0) ap_quest(); else ap_pos(PAGE_NUM(linenum)); } break; case 'E': /* Editor name */ ap_str(editor); break; case 'f': /* File name */ ap_str(get_filename(curr_ifile)); break; case 'F': /* Last component of file name */ ap_str(last_component(get_filename(curr_ifile))); break; case 'i': /* Index into list of files */ if (ntags()) ap_int(curr_tag()); else ap_int(get_index(curr_ifile)); break; case 'l': /* Current line number */ linenum = currline(where); if (linenum != 0) ap_pos(linenum); else ap_quest(); break; case 'L': /* Final line number */ len = ch_length(); if (len == -1 || len == ch_zero() || (linenum = find_linenum(len)) <= 0) ap_quest(); else ap_pos(linenum-1); break; case 'm': /* Number of files */ n = ntags(); if (n) ap_int(n); else ap_int(nifile()); break; case 'p': /* Percent into file (bytes) */ pos = curr_byte(where); len = ch_length(); if (pos != -1 && len > 0) ap_int(percentage(pos, len)); else ap_quest(); break; case 'P': /* Percent into file (lines) */ linenum = currline(where); if (linenum == 0 || (len = ch_length()) == -1 || len == ch_zero() || (last_linenum = find_linenum(len)) <= 0) ap_quest(); else ap_int(percentage(linenum, last_linenum)); break; case 's': /* Size of file */ case 'B': len = ch_length(); if (len != -1) ap_pos(len); else ap_quest(); break; case 't': /* Truncate trailing spaces in the message */ while (mp > message && mp[-1] == ' ') mp--; *mp = '\0'; break; case 'T': /* Type of list */ if (ntags()) ap_str("tag"); else ap_str("file"); break; case 'x': /* Name of next file */ h = next_ifile(curr_ifile); if (h != NULL) ap_str(get_filename(h)); else ap_quest(); break; } }