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