1238730Sdelphij/* 2330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 3238730Sdelphij * 4238730Sdelphij * You may distribute under the terms of either the GNU General Public 5238730Sdelphij * License or the Less License, as specified in the README file. 6238730Sdelphij * 7238730Sdelphij * For more information, see the README file. 8238730Sdelphij */ 960786Sps 1060786Sps 1160786Sps#include "less.h" 12330571Sdelphij#include "position.h" 1360786Sps 1460786Spsextern IFILE curr_ifile; 1560786Spsextern int sc_height; 1660786Spsextern int jump_sline; 1760786Sps 1860786Sps/* 1960786Sps * The table of marks. 2060786Sps * Each mark is identified by a lowercase or uppercase letter. 2160786Sps * The final one is lmark, for the "last mark"; addressed by the apostrophe. 2260786Sps */ 2360786Sps#define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ 2460786Sps#define LASTMARK (NMARKS-1) 2560786Spsstatic struct mark marks[NMARKS]; 2660786Sps 2760786Sps/* 2860786Sps * Initialize the mark table to show no marks are set. 2960786Sps */ 3060786Sps public void 3160786Spsinit_mark() 3260786Sps{ 3360786Sps int i; 3460786Sps 3560786Sps for (i = 0; i < NMARKS; i++) 3660786Sps marks[i].m_scrpos.pos = NULL_POSITION; 3760786Sps} 3860786Sps 3960786Sps/* 4060786Sps * See if a mark letter is valid (between a and z). 4160786Sps */ 4260786Sps static struct mark * 4360786Spsgetumark(c) 4460786Sps int c; 4560786Sps{ 4660786Sps if (c >= 'a' && c <= 'z') 4760786Sps return (&marks[c-'a']); 4860786Sps 4960786Sps if (c >= 'A' && c <= 'Z') 5060786Sps return (&marks[c-'A'+26]); 5160786Sps 5260786Sps error("Invalid mark letter", NULL_PARG); 5360786Sps return (NULL); 5460786Sps} 5560786Sps 5660786Sps/* 5760786Sps * Get the mark structure identified by a character. 5860786Sps * The mark struct may come either from the mark table 5960786Sps * or may be constructed on the fly for certain characters like ^, $. 6060786Sps */ 6160786Sps static struct mark * 6260786Spsgetmark(c) 6360786Sps int c; 6460786Sps{ 65330571Sdelphij struct mark *m; 6660786Sps static struct mark sm; 6760786Sps 6860786Sps switch (c) 6960786Sps { 7060786Sps case '^': 7160786Sps /* 7260786Sps * Beginning of the current file. 7360786Sps */ 7460786Sps m = &sm; 7560786Sps m->m_scrpos.pos = ch_zero(); 7660786Sps m->m_scrpos.ln = 0; 7760786Sps m->m_ifile = curr_ifile; 7860786Sps break; 7960786Sps case '$': 8060786Sps /* 8160786Sps * End of the current file. 8260786Sps */ 8360786Sps if (ch_end_seek()) 8460786Sps { 8560786Sps error("Cannot seek to end of file", NULL_PARG); 8660786Sps return (NULL); 8760786Sps } 8860786Sps m = &sm; 8960786Sps m->m_scrpos.pos = ch_tell(); 90330571Sdelphij m->m_scrpos.ln = sc_height; 9160786Sps m->m_ifile = curr_ifile; 9260786Sps break; 9360786Sps case '.': 9460786Sps /* 9560786Sps * Current position in the current file. 9660786Sps */ 9760786Sps m = &sm; 98330571Sdelphij get_scrpos(&m->m_scrpos, TOP); 9960786Sps m->m_ifile = curr_ifile; 10060786Sps break; 10160786Sps case '\'': 10260786Sps /* 10360786Sps * The "last mark". 10460786Sps */ 10560786Sps m = &marks[LASTMARK]; 10660786Sps break; 10760786Sps default: 10860786Sps /* 10960786Sps * Must be a user-defined mark. 11060786Sps */ 11160786Sps m = getumark(c); 11260786Sps if (m == NULL) 11360786Sps break; 11460786Sps if (m->m_scrpos.pos == NULL_POSITION) 11560786Sps { 11660786Sps error("Mark not set", NULL_PARG); 11760786Sps return (NULL); 11860786Sps } 11960786Sps break; 12060786Sps } 12160786Sps return (m); 12260786Sps} 12360786Sps 12460786Sps/* 12560786Sps * Is a mark letter is invalid? 12660786Sps */ 12760786Sps public int 12860786Spsbadmark(c) 12960786Sps int c; 13060786Sps{ 13160786Sps return (getmark(c) == NULL); 13260786Sps} 13360786Sps 13460786Sps/* 13560786Sps * Set a user-defined mark. 13660786Sps */ 13760786Sps public void 138330571Sdelphijsetmark(c, where) 13960786Sps int c; 140330571Sdelphij int where; 14160786Sps{ 142330571Sdelphij struct mark *m; 14360786Sps struct scrpos scrpos; 14460786Sps 14560786Sps m = getumark(c); 14660786Sps if (m == NULL) 14760786Sps return; 148330571Sdelphij get_scrpos(&scrpos, where); 14960786Sps m->m_scrpos = scrpos; 15060786Sps m->m_ifile = curr_ifile; 15160786Sps} 15260786Sps 15360786Sps/* 154330571Sdelphij * Clear a user-defined mark. 155330571Sdelphij */ 156330571Sdelphij public void 157330571Sdelphijclrmark(c) 158330571Sdelphij int c; 159330571Sdelphij{ 160330571Sdelphij struct mark *m; 161330571Sdelphij 162330571Sdelphij m = getumark(c); 163330571Sdelphij if (m == NULL) 164330571Sdelphij return; 165330571Sdelphij m->m_scrpos.pos = NULL_POSITION; 166330571Sdelphij} 167330571Sdelphij 168330571Sdelphij/* 16960786Sps * Set lmark (the mark named by the apostrophe). 17060786Sps */ 17160786Sps public void 17260786Spslastmark() 17360786Sps{ 17460786Sps struct scrpos scrpos; 17560786Sps 17660786Sps if (ch_getflags() & CH_HELPFILE) 17760786Sps return; 178330571Sdelphij get_scrpos(&scrpos, TOP); 17960786Sps if (scrpos.pos == NULL_POSITION) 18060786Sps return; 18160786Sps marks[LASTMARK].m_scrpos = scrpos; 18260786Sps marks[LASTMARK].m_ifile = curr_ifile; 18360786Sps} 18460786Sps 18560786Sps/* 18660786Sps * Go to a mark. 18760786Sps */ 18860786Sps public void 18960786Spsgomark(c) 19060786Sps int c; 19160786Sps{ 192330571Sdelphij struct mark *m; 19360786Sps struct scrpos scrpos; 19460786Sps 19560786Sps m = getmark(c); 19660786Sps if (m == NULL) 19760786Sps return; 19860786Sps 19960786Sps /* 20060786Sps * If we're trying to go to the lastmark and 20160786Sps * it has not been set to anything yet, 20260786Sps * set it to the beginning of the current file. 20360786Sps */ 20460786Sps if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) 20560786Sps { 20660786Sps m->m_ifile = curr_ifile; 20760786Sps m->m_scrpos.pos = ch_zero(); 20860786Sps m->m_scrpos.ln = jump_sline; 20960786Sps } 21060786Sps 21160786Sps /* 21260786Sps * If we're using lmark, we must save the screen position now, 21360786Sps * because if we call edit_ifile() below, lmark will change. 21460786Sps * (We save the screen position even if we're not using lmark.) 21560786Sps */ 21660786Sps scrpos = m->m_scrpos; 21760786Sps if (m->m_ifile != curr_ifile) 21860786Sps { 21960786Sps /* 22060786Sps * Not in the current file; edit the correct file. 22160786Sps */ 22260786Sps if (edit_ifile(m->m_ifile)) 22360786Sps return; 22460786Sps } 22560786Sps 22660786Sps jump_loc(scrpos.pos, scrpos.ln); 22760786Sps} 22860786Sps 22960786Sps/* 23060786Sps * Return the position associated with a given mark letter. 23160786Sps * 23260786Sps * We don't return which screen line the position 23360786Sps * is associated with, but this doesn't matter much, 23460786Sps * because it's always the first non-blank line on the screen. 23560786Sps */ 23660786Sps public POSITION 23760786Spsmarkpos(c) 23860786Sps int c; 23960786Sps{ 240330571Sdelphij struct mark *m; 24160786Sps 24260786Sps m = getmark(c); 24360786Sps if (m == NULL) 24460786Sps return (NULL_POSITION); 24560786Sps 24660786Sps if (m->m_ifile != curr_ifile) 24760786Sps { 24860786Sps error("Mark not in current file", NULL_PARG); 24960786Sps return (NULL_POSITION); 25060786Sps } 25160786Sps return (m->m_scrpos.pos); 25260786Sps} 25360786Sps 25460786Sps/* 255330571Sdelphij * Return the mark associated with a given position, if any. 256330571Sdelphij */ 257330571Sdelphij public char 258330571Sdelphijposmark(pos) 259330571Sdelphij POSITION pos; 260330571Sdelphij{ 261330571Sdelphij int i; 262330571Sdelphij 263330571Sdelphij /* Only lower case and upper case letters */ 264330571Sdelphij for (i = 0; i < 26*2; i++) 265330571Sdelphij { 266330571Sdelphij if (marks[i].m_ifile == curr_ifile && marks[i].m_scrpos.pos == pos) 267330571Sdelphij { 268330571Sdelphij if (i < 26) return 'a' + i; 269330571Sdelphij return 'A' + i - 26; 270330571Sdelphij } 271330571Sdelphij } 272330571Sdelphij return 0; 273330571Sdelphij} 274330571Sdelphij 275330571Sdelphij/* 27660786Sps * Clear the marks associated with a specified ifile. 27760786Sps */ 27860786Sps public void 27960786Spsunmark(ifile) 28060786Sps IFILE ifile; 28160786Sps{ 28260786Sps int i; 28360786Sps 28460786Sps for (i = 0; i < NMARKS; i++) 28560786Sps if (marks[i].m_ifile == ifile) 28660786Sps marks[i].m_scrpos.pos = NULL_POSITION; 28760786Sps} 288