mark.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps#include "less.h" 1360786Sps 1460786Spsextern IFILE curr_ifile; 1560786Spsextern int sc_height; 1660786Spsextern int jump_sline; 1760786Sps 1860786Sps/* 1960786Sps * A mark is an ifile (input file) plus a position within the file. 2060786Sps */ 2160786Spsstruct mark { 2260786Sps IFILE m_ifile; 2360786Sps struct scrpos m_scrpos; 2460786Sps}; 2560786Sps 2660786Sps/* 2760786Sps * The table of marks. 2860786Sps * Each mark is identified by a lowercase or uppercase letter. 2960786Sps * The final one is lmark, for the "last mark"; addressed by the apostrophe. 3060786Sps */ 3160786Sps#define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ 3260786Sps#define LASTMARK (NMARKS-1) 3360786Spsstatic struct mark marks[NMARKS]; 3460786Sps 3560786Sps/* 3660786Sps * Initialize the mark table to show no marks are set. 3760786Sps */ 3860786Sps public void 3960786Spsinit_mark() 4060786Sps{ 4160786Sps int i; 4260786Sps 4360786Sps for (i = 0; i < NMARKS; i++) 4460786Sps marks[i].m_scrpos.pos = NULL_POSITION; 4560786Sps} 4660786Sps 4760786Sps/* 4860786Sps * See if a mark letter is valid (between a and z). 4960786Sps */ 5060786Sps static struct mark * 5160786Spsgetumark(c) 5260786Sps int c; 5360786Sps{ 5460786Sps if (c >= 'a' && c <= 'z') 5560786Sps return (&marks[c-'a']); 5660786Sps 5760786Sps if (c >= 'A' && c <= 'Z') 5860786Sps return (&marks[c-'A'+26]); 5960786Sps 6060786Sps error("Invalid mark letter", NULL_PARG); 6160786Sps return (NULL); 6260786Sps} 6360786Sps 6460786Sps/* 6560786Sps * Get the mark structure identified by a character. 6660786Sps * The mark struct may come either from the mark table 6760786Sps * or may be constructed on the fly for certain characters like ^, $. 6860786Sps */ 6960786Sps static struct mark * 7060786Spsgetmark(c) 7160786Sps int c; 7260786Sps{ 7360786Sps register struct mark *m; 7460786Sps static struct mark sm; 7560786Sps 7660786Sps switch (c) 7760786Sps { 7860786Sps case '^': 7960786Sps /* 8060786Sps * Beginning of the current file. 8160786Sps */ 8260786Sps m = &sm; 8360786Sps m->m_scrpos.pos = ch_zero(); 8460786Sps m->m_scrpos.ln = 0; 8560786Sps m->m_ifile = curr_ifile; 8660786Sps break; 8760786Sps case '$': 8860786Sps /* 8960786Sps * End of the current file. 9060786Sps */ 9160786Sps if (ch_end_seek()) 9260786Sps { 9360786Sps error("Cannot seek to end of file", NULL_PARG); 9460786Sps return (NULL); 9560786Sps } 9660786Sps m = &sm; 9760786Sps m->m_scrpos.pos = ch_tell(); 9860786Sps m->m_scrpos.ln = sc_height-1; 9960786Sps m->m_ifile = curr_ifile; 10060786Sps break; 10160786Sps case '.': 10260786Sps /* 10360786Sps * Current position in the current file. 10460786Sps */ 10560786Sps m = &sm; 10660786Sps get_scrpos(&m->m_scrpos); 10760786Sps m->m_ifile = curr_ifile; 10860786Sps break; 10960786Sps case '\'': 11060786Sps /* 11160786Sps * The "last mark". 11260786Sps */ 11360786Sps m = &marks[LASTMARK]; 11460786Sps break; 11560786Sps default: 11660786Sps /* 11760786Sps * Must be a user-defined mark. 11860786Sps */ 11960786Sps m = getumark(c); 12060786Sps if (m == NULL) 12160786Sps break; 12260786Sps if (m->m_scrpos.pos == NULL_POSITION) 12360786Sps { 12460786Sps error("Mark not set", NULL_PARG); 12560786Sps return (NULL); 12660786Sps } 12760786Sps break; 12860786Sps } 12960786Sps return (m); 13060786Sps} 13160786Sps 13260786Sps/* 13360786Sps * Is a mark letter is invalid? 13460786Sps */ 13560786Sps public int 13660786Spsbadmark(c) 13760786Sps int c; 13860786Sps{ 13960786Sps return (getmark(c) == NULL); 14060786Sps} 14160786Sps 14260786Sps/* 14360786Sps * Set a user-defined mark. 14460786Sps */ 14560786Sps public void 14660786Spssetmark(c) 14760786Sps int c; 14860786Sps{ 14960786Sps register struct mark *m; 15060786Sps struct scrpos scrpos; 15160786Sps 15260786Sps m = getumark(c); 15360786Sps if (m == NULL) 15460786Sps return; 15560786Sps get_scrpos(&scrpos); 15660786Sps m->m_scrpos = scrpos; 15760786Sps m->m_ifile = curr_ifile; 15860786Sps} 15960786Sps 16060786Sps/* 16160786Sps * Set lmark (the mark named by the apostrophe). 16260786Sps */ 16360786Sps public void 16460786Spslastmark() 16560786Sps{ 16660786Sps struct scrpos scrpos; 16760786Sps 16860786Sps if (ch_getflags() & CH_HELPFILE) 16960786Sps return; 17060786Sps get_scrpos(&scrpos); 17160786Sps if (scrpos.pos == NULL_POSITION) 17260786Sps return; 17360786Sps marks[LASTMARK].m_scrpos = scrpos; 17460786Sps marks[LASTMARK].m_ifile = curr_ifile; 17560786Sps} 17660786Sps 17760786Sps/* 17860786Sps * Go to a mark. 17960786Sps */ 18060786Sps public void 18160786Spsgomark(c) 18260786Sps int c; 18360786Sps{ 18460786Sps register struct mark *m; 18560786Sps struct scrpos scrpos; 18660786Sps 18760786Sps m = getmark(c); 18860786Sps if (m == NULL) 18960786Sps return; 19060786Sps 19160786Sps /* 19260786Sps * If we're trying to go to the lastmark and 19360786Sps * it has not been set to anything yet, 19460786Sps * set it to the beginning of the current file. 19560786Sps */ 19660786Sps if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) 19760786Sps { 19860786Sps m->m_ifile = curr_ifile; 19960786Sps m->m_scrpos.pos = ch_zero(); 20060786Sps m->m_scrpos.ln = jump_sline; 20160786Sps } 20260786Sps 20360786Sps /* 20460786Sps * If we're using lmark, we must save the screen position now, 20560786Sps * because if we call edit_ifile() below, lmark will change. 20660786Sps * (We save the screen position even if we're not using lmark.) 20760786Sps */ 20860786Sps scrpos = m->m_scrpos; 20960786Sps if (m->m_ifile != curr_ifile) 21060786Sps { 21160786Sps /* 21260786Sps * Not in the current file; edit the correct file. 21360786Sps */ 21460786Sps if (edit_ifile(m->m_ifile)) 21560786Sps return; 21660786Sps } 21760786Sps 21860786Sps jump_loc(scrpos.pos, scrpos.ln); 21960786Sps} 22060786Sps 22160786Sps/* 22260786Sps * Return the position associated with a given mark letter. 22360786Sps * 22460786Sps * We don't return which screen line the position 22560786Sps * is associated with, but this doesn't matter much, 22660786Sps * because it's always the first non-blank line on the screen. 22760786Sps */ 22860786Sps public POSITION 22960786Spsmarkpos(c) 23060786Sps int c; 23160786Sps{ 23260786Sps register struct mark *m; 23360786Sps 23460786Sps m = getmark(c); 23560786Sps if (m == NULL) 23660786Sps return (NULL_POSITION); 23760786Sps 23860786Sps if (m->m_ifile != curr_ifile) 23960786Sps { 24060786Sps error("Mark not in current file", NULL_PARG); 24160786Sps return (NULL_POSITION); 24260786Sps } 24360786Sps return (m->m_scrpos.pos); 24460786Sps} 24560786Sps 24660786Sps/* 24760786Sps * Clear the marks associated with a specified ifile. 24860786Sps */ 24960786Sps public void 25060786Spsunmark(ifile) 25160786Sps IFILE ifile; 25260786Sps{ 25360786Sps int i; 25460786Sps 25560786Sps for (i = 0; i < NMARKS; i++) 25660786Sps if (marks[i].m_ifile == ifile) 25760786Sps marks[i].m_scrpos.pos = NULL_POSITION; 25860786Sps} 25960786Sps