xref: /dflybsd-src/bin/mined/mined2.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
1f5812cdfSMatthew Dillon /*
2f5812cdfSMatthew Dillon  *      Copyright (c) 1987,1997, Prentice Hall
3f5812cdfSMatthew Dillon  *      All rights reserved.
4f5812cdfSMatthew Dillon  *
5f5812cdfSMatthew Dillon  *      Redistribution and use of the MINIX operating system in source and
6f5812cdfSMatthew Dillon  *      binary forms, with or without modification, are permitted provided
7f5812cdfSMatthew Dillon  *      that the following conditions are met:
8f5812cdfSMatthew Dillon  *
9f5812cdfSMatthew Dillon  *         * Redistributions of source code must retain the above copyright
10f5812cdfSMatthew Dillon  *           notice, this list of conditions and the following disclaimer.
11f5812cdfSMatthew Dillon  *
12f5812cdfSMatthew Dillon  *         * Redistributions in binary form must reproduce the above
13f5812cdfSMatthew Dillon  *           copyright notice, this list of conditions and the following
14f5812cdfSMatthew Dillon  *           disclaimer in the documentation and/or other materials provided
15f5812cdfSMatthew Dillon  *           with the distribution.
16f5812cdfSMatthew Dillon  *
17f5812cdfSMatthew Dillon  *         * Neither the name of Prentice Hall nor the names of the software
18f5812cdfSMatthew Dillon  *           authors or contributors may be used to endorse or promote
19f5812cdfSMatthew Dillon  *           products derived from this software without specific prior
20f5812cdfSMatthew Dillon  *           written permission.
21f5812cdfSMatthew Dillon  *
22f5812cdfSMatthew Dillon  *      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
23f5812cdfSMatthew Dillon  *      CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24f5812cdfSMatthew Dillon  *      INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25f5812cdfSMatthew Dillon  *      MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26f5812cdfSMatthew Dillon  *      IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
27f5812cdfSMatthew Dillon  *      LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28f5812cdfSMatthew Dillon  *      CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29f5812cdfSMatthew Dillon  *      SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30f5812cdfSMatthew Dillon  *      BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31f5812cdfSMatthew Dillon  *      WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32f5812cdfSMatthew Dillon  *      OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33f5812cdfSMatthew Dillon  *      EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34f5812cdfSMatthew Dillon  *
35f5812cdfSMatthew Dillon  * [original code from minix codebase]
361f0f7b35SSascha Wildner  * $DragonFly: src/bin/mined/mined2.c,v 1.6 2005/11/06 11:44:02 swildner Exp $*
37f5812cdfSMatthew Dillon  */
384f73fc56SMatthew Dillon /*
394f73fc56SMatthew Dillon  * Part 2 of the mined editor.
404f73fc56SMatthew Dillon  */
414f73fc56SMatthew Dillon 
424f73fc56SMatthew Dillon /*  ========================================================================  *
434f73fc56SMatthew Dillon  *				Move Commands				      *
444f73fc56SMatthew Dillon  *  ========================================================================  */
454f73fc56SMatthew Dillon 
464f73fc56SMatthew Dillon #include "mined.h"
475ce3bad5SMatthew Dillon #include <signal.h>
484f73fc56SMatthew Dillon #include <string.h>
494f73fc56SMatthew Dillon 
504f73fc56SMatthew Dillon /*
514f73fc56SMatthew Dillon  * Move one line up.
524f73fc56SMatthew Dillon  */
538ecf459dSSascha Wildner void
UP(int u __unused)548ecf459dSSascha Wildner UP(int u __unused)
554f73fc56SMatthew Dillon {
564f73fc56SMatthew Dillon   if (y == 0) {		/* Top line of screen. Scroll one line */
578ecf459dSSascha Wildner   	reverse_scroll();
584f73fc56SMatthew Dillon   	move_to(x, y);
594f73fc56SMatthew Dillon   }
604f73fc56SMatthew Dillon   else			/* Move to previous line */
614f73fc56SMatthew Dillon   	move_to(x, y - 1);
624f73fc56SMatthew Dillon }
634f73fc56SMatthew Dillon 
648ecf459dSSascha Wildner static const char *help_string=
659f83a2b6SSimon Schubert "			Mined (Minix Editor), DragonFly version.\n"
66f5812cdfSMatthew Dillon "------------------------+-------------------------------+---------------------\n"
67f5812cdfSMatthew Dillon "	CURSOR MOTION	|		EDITING		|	MISC\n"
685ce3bad5SMatthew Dillon " Up			| ^N	Delete next word	| ^L	Erase & redraw\n"
69f5812cdfSMatthew Dillon " Down	cursor keys	| ^P	Delete prev. word	|	screen\n"
70f5812cdfSMatthew Dillon " Left			| ^T	Delete to EOL		| ^\\	Abort current\n"
71f5812cdfSMatthew Dillon " Right			+-------------------------------+	operation\n"
72f5812cdfSMatthew Dillon " ^A	start of line	|		BLOCKS		| Esc	repeat last\n"
735ce3bad5SMatthew Dillon " ^E	end of line	| ^@	Set mark		|	cmd # times\n"
74f5812cdfSMatthew Dillon " ^^	screen top	| ^K	Delete mark <--> cursor	| F2	file status\n"
75f5812cdfSMatthew Dillon " ^_	screen bottom	| ^C	Save mark <--> cursor	+=====================\n"
76f5812cdfSMatthew Dillon " ^F	word fwd.	| ^Y	Insert the contents of	| ^X	EXIT\n"
77f5812cdfSMatthew Dillon " ^B	word back	| 	the save file at cursor | ^S	run shell\n"
78f5812cdfSMatthew Dillon "------------------------+ ^Q	Insert the contents of	+=====================\n"
79f5812cdfSMatthew Dillon "	SCREEN MOTION	|	the save file into new	|   SEARCH & REPLACE\n"
80f5812cdfSMatthew Dillon "  Home	file top	|	file			| F3	fwd. search\n"
81f5812cdfSMatthew Dillon "  End	file bottom	+-------------------------------+ SF3	bck. search\n"
82f5812cdfSMatthew Dillon "  PgUp	page up		|		FILES		| F4	Global replace\n"
83f5812cdfSMatthew Dillon "  PgD	page down	| ^G	Insert a file at cursor | SF4	Line replace\n"
84f5812cdfSMatthew Dillon "  ^D	rev. scroll	| ^V	Visit another file	+---------------------\n"
85f5812cdfSMatthew Dillon "  ^U	fwd. scroll	| ^W	Write current file	| F1	HELP\n"
86f5812cdfSMatthew Dillon "  ^]	goto line #	|				|\n"
87f5812cdfSMatthew Dillon "------------------------+-------------------------------+---------------------\n"
88f5812cdfSMatthew Dillon "Press any key to continue...";
89f5812cdfSMatthew Dillon /*
90f5812cdfSMatthew Dillon  * Help
91f5812cdfSMatthew Dillon  */
928ecf459dSSascha Wildner void
HLP(int u __unused)938ecf459dSSascha Wildner HLP(int u __unused)
94f5812cdfSMatthew Dillon {
95f5812cdfSMatthew Dillon 	string_print(enter_string);
96f5812cdfSMatthew Dillon 	string_print(help_string);
97f5812cdfSMatthew Dillon 	flush();
98*50a61867SJohn Marino 	getchar();
998ecf459dSSascha Wildner 	RD(0);
100f5812cdfSMatthew Dillon 	return;
101f5812cdfSMatthew Dillon }
102f5812cdfSMatthew Dillon 
1038ecf459dSSascha Wildner void
ST(int u __unused)1048ecf459dSSascha Wildner ST(int u __unused)
1055ce3bad5SMatthew Dillon {
1065ce3bad5SMatthew Dillon 	raw_mode(OFF);
1075ce3bad5SMatthew Dillon 	kill(getpid(), SIGTSTP);
1085ce3bad5SMatthew Dillon 	raw_mode(ON);
1098ecf459dSSascha Wildner 	RD(0);
1105ce3bad5SMatthew Dillon }
1115ce3bad5SMatthew Dillon 
1124f73fc56SMatthew Dillon /*
1134f73fc56SMatthew Dillon  * Move one line down.
1144f73fc56SMatthew Dillon  */
1158ecf459dSSascha Wildner void
DN(int u __unused)1168ecf459dSSascha Wildner DN(int u __unused)
1174f73fc56SMatthew Dillon {
1184f73fc56SMatthew Dillon   if (y == last_y) {	/* Last line of screen. Scroll one line */
1194f73fc56SMatthew Dillon 	if (bot_line->next == tail && bot_line->text[0] != '\n') {
1204f73fc56SMatthew Dillon 		dummy_line();		/* Create new empty line */
1218ecf459dSSascha Wildner 		DN(0);
1224f73fc56SMatthew Dillon 		return;
1234f73fc56SMatthew Dillon 	}
1244f73fc56SMatthew Dillon 	else {
1258ecf459dSSascha Wildner 		forward_scroll();
1264f73fc56SMatthew Dillon 		move_to(x, y);
1274f73fc56SMatthew Dillon 	}
1284f73fc56SMatthew Dillon   }
1294f73fc56SMatthew Dillon   else			/* Move to next line */
1304f73fc56SMatthew Dillon   	move_to(x, y + 1);
1314f73fc56SMatthew Dillon }
1324f73fc56SMatthew Dillon 
1334f73fc56SMatthew Dillon /*
1344f73fc56SMatthew Dillon  * Move left one position.
1354f73fc56SMatthew Dillon  */
1368ecf459dSSascha Wildner void
LF(int u __unused)1378ecf459dSSascha Wildner LF(int u __unused)
1384f73fc56SMatthew Dillon {
1394f73fc56SMatthew Dillon   if (x == 0 && get_shift(cur_line->shift_count) == 0) {/* Begin of line */
1404f73fc56SMatthew Dillon 	if (cur_line->prev != header) {
1418ecf459dSSascha Wildner 		UP(0);					/* Move one line up */
1424f73fc56SMatthew Dillon 		move_to(LINE_END, y);
1434f73fc56SMatthew Dillon 	}
1444f73fc56SMatthew Dillon   }
1454f73fc56SMatthew Dillon   else
1464f73fc56SMatthew Dillon   	move_to(x - 1, y);
1474f73fc56SMatthew Dillon }
1484f73fc56SMatthew Dillon 
1494f73fc56SMatthew Dillon /*
1504f73fc56SMatthew Dillon  * Move right one position.
1514f73fc56SMatthew Dillon  */
1528ecf459dSSascha Wildner void
RT(int u __unused)1538ecf459dSSascha Wildner RT(int u __unused)
1544f73fc56SMatthew Dillon {
1554f73fc56SMatthew Dillon   if (*cur_text == '\n') {
1564f73fc56SMatthew Dillon   	if (cur_line->next != tail) {		/* Last char of file */
1578ecf459dSSascha Wildner 		DN(0);				/* Move one line down */
1584f73fc56SMatthew Dillon 		move_to(LINE_START, y);
1594f73fc56SMatthew Dillon 	}
1604f73fc56SMatthew Dillon   }
1614f73fc56SMatthew Dillon   else
1624f73fc56SMatthew Dillon   	move_to(x + 1, y);
1634f73fc56SMatthew Dillon }
1644f73fc56SMatthew Dillon 
1654f73fc56SMatthew Dillon /*
1664f73fc56SMatthew Dillon  * Move to coordinates [0, 0] on screen.
1674f73fc56SMatthew Dillon  */
1688ecf459dSSascha Wildner void
HIGH(int u __unused)1698ecf459dSSascha Wildner HIGH(int u __unused)
1704f73fc56SMatthew Dillon {
1714f73fc56SMatthew Dillon   move_to(0, 0);
1724f73fc56SMatthew Dillon }
1734f73fc56SMatthew Dillon 
1744f73fc56SMatthew Dillon /*
1754f73fc56SMatthew Dillon  * Move to coordinates [0, YMAX] on screen.
1764f73fc56SMatthew Dillon  */
1778ecf459dSSascha Wildner void
LOW(int u __unused)1788ecf459dSSascha Wildner LOW(int u __unused)
1794f73fc56SMatthew Dillon {
1804f73fc56SMatthew Dillon   move_to(0, last_y);
1814f73fc56SMatthew Dillon }
1824f73fc56SMatthew Dillon 
1834f73fc56SMatthew Dillon /*
1844f73fc56SMatthew Dillon  * Move to begin of line.
1854f73fc56SMatthew Dillon  */
1868ecf459dSSascha Wildner void
BL(int u __unused)1878ecf459dSSascha Wildner BL(int u __unused)
1884f73fc56SMatthew Dillon {
1894f73fc56SMatthew Dillon   move_to(LINE_START, y);
1904f73fc56SMatthew Dillon }
1914f73fc56SMatthew Dillon 
1924f73fc56SMatthew Dillon /*
1934f73fc56SMatthew Dillon  * Move to end of line.
1944f73fc56SMatthew Dillon  */
1958ecf459dSSascha Wildner void
EL(int u __unused)1968ecf459dSSascha Wildner EL(int u __unused)
1974f73fc56SMatthew Dillon {
1984f73fc56SMatthew Dillon   move_to(LINE_END, y);
1994f73fc56SMatthew Dillon }
2004f73fc56SMatthew Dillon 
2014f73fc56SMatthew Dillon /*
2024f73fc56SMatthew Dillon  * GOTO() prompts for a linenumber and moves to that line.
2034f73fc56SMatthew Dillon  */
2048ecf459dSSascha Wildner void
GOTO(int u __unused)2058ecf459dSSascha Wildner GOTO(int u __unused)
2064f73fc56SMatthew Dillon {
2074f73fc56SMatthew Dillon   int number;
2084f73fc56SMatthew Dillon   LINE *line;
2094f73fc56SMatthew Dillon 
2104f73fc56SMatthew Dillon   if (get_number("Please enter line number.", &number) == ERRORS)
2114f73fc56SMatthew Dillon   	return;
2124f73fc56SMatthew Dillon 
2134f73fc56SMatthew Dillon   if (number <= 0 || (line = proceed(header->next, number - 1)) == tail)
2144f73fc56SMatthew Dillon   	error("Illegal line number: ", num_out((long) number));
2154f73fc56SMatthew Dillon   else
2164f73fc56SMatthew Dillon   	move_to(x, find_y(line));
2174f73fc56SMatthew Dillon }
2184f73fc56SMatthew Dillon 
2194f73fc56SMatthew Dillon /*
2204f73fc56SMatthew Dillon  * Scroll forward one page or to eof, whatever comes first. (Bot_line becomes
2214f73fc56SMatthew Dillon  * top_line of display.) Try to leave the cursor on the same line. If this is
2224f73fc56SMatthew Dillon  * not possible, leave cursor on the line halfway the page.
2234f73fc56SMatthew Dillon  */
2248ecf459dSSascha Wildner void
PD(int u __unused)2258ecf459dSSascha Wildner PD(int u __unused)
2264f73fc56SMatthew Dillon {
2278ecf459dSSascha Wildner   int i;
2284f73fc56SMatthew Dillon 
2294f73fc56SMatthew Dillon   for (i = 0; i < screenmax; i++)
2304f73fc56SMatthew Dillon   	if (forward_scroll() == ERRORS)
2314f73fc56SMatthew Dillon   		break;			/* EOF reached */
2324f73fc56SMatthew Dillon   if (y - i < 0)				/* Line no longer on screen */
2334f73fc56SMatthew Dillon   	move_to(0, screenmax >> 1);
2344f73fc56SMatthew Dillon   else
2354f73fc56SMatthew Dillon   	move_to(0, y - i);
2364f73fc56SMatthew Dillon }
2374f73fc56SMatthew Dillon 
2384f73fc56SMatthew Dillon 
2394f73fc56SMatthew Dillon /*
2404f73fc56SMatthew Dillon  * Scroll backwards one page or to top of file, whatever comes first. (Top_line
2414f73fc56SMatthew Dillon  * becomes bot_line of display).  The very bottom line (YMAX) is always blank.
2424f73fc56SMatthew Dillon  * Try to leave the cursor on the same line. If this is not possible, leave
2434f73fc56SMatthew Dillon  * cursor on the line halfway the page.
2444f73fc56SMatthew Dillon  */
2458ecf459dSSascha Wildner void
PU(int u __unused)2468ecf459dSSascha Wildner PU(int u __unused)
2474f73fc56SMatthew Dillon {
2488ecf459dSSascha Wildner   int i;
2494f73fc56SMatthew Dillon 
2504f73fc56SMatthew Dillon   for (i = 0; i < screenmax; i++)
2514f73fc56SMatthew Dillon   	if (reverse_scroll() == ERRORS)
2524f73fc56SMatthew Dillon   		break;			/* Top of file reached */
2534f73fc56SMatthew Dillon   set_cursor(0, ymax);			/* Erase very bottom line */
2544f73fc56SMatthew Dillon #ifdef UNIX
2554f73fc56SMatthew Dillon   tputs(CE, 0, _putchar);
2564f73fc56SMatthew Dillon #else
2574f73fc56SMatthew Dillon   string_print(blank_line);
2584f73fc56SMatthew Dillon #endif /* UNIX */
2594f73fc56SMatthew Dillon   if (y + i > screenmax)			/* line no longer on screen */
2604f73fc56SMatthew Dillon   	move_to(0, screenmax >> 1);
2614f73fc56SMatthew Dillon   else
2624f73fc56SMatthew Dillon   	move_to(0, y + i);
2634f73fc56SMatthew Dillon }
2644f73fc56SMatthew Dillon 
2654f73fc56SMatthew Dillon /*
2664f73fc56SMatthew Dillon  * Go to top of file, scrolling if possible, else redrawing screen.
2674f73fc56SMatthew Dillon  */
2688ecf459dSSascha Wildner void
HO(int u __unused)2698ecf459dSSascha Wildner HO(int u __unused)
2704f73fc56SMatthew Dillon {
2714f73fc56SMatthew Dillon   if (proceed(top_line, -screenmax) == header)
2728ecf459dSSascha Wildner   	PU(0);			/* It fits. Let PU do it */
2734f73fc56SMatthew Dillon   else {
2744f73fc56SMatthew Dillon   	reset(header->next, 0);/* Reset top_line, etc. */
2758ecf459dSSascha Wildner   	RD(0);			/* Display full page */
2764f73fc56SMatthew Dillon   }
2774f73fc56SMatthew Dillon   move_to(LINE_START, 0);
2784f73fc56SMatthew Dillon }
2794f73fc56SMatthew Dillon 
2804f73fc56SMatthew Dillon /*
2814f73fc56SMatthew Dillon  * Go to last line of file, scrolling if possible, else redrawing screen
2824f73fc56SMatthew Dillon  */
2838ecf459dSSascha Wildner void
EF(int u __unused)2848ecf459dSSascha Wildner EF(int u __unused)
2854f73fc56SMatthew Dillon {
2864f73fc56SMatthew Dillon   if (tail->prev->text[0] != '\n')
2874f73fc56SMatthew Dillon 	dummy_line();
2884f73fc56SMatthew Dillon   if (proceed(bot_line, screenmax) == tail)
2898ecf459dSSascha Wildner   	PD(0);			/* It fits. Let PD do it */
2904f73fc56SMatthew Dillon   else {
2914f73fc56SMatthew Dillon   	reset(proceed(tail->prev, -screenmax), screenmax);
2928ecf459dSSascha Wildner   	RD(0);			/* Display full page */
2934f73fc56SMatthew Dillon   }
2944f73fc56SMatthew Dillon   move_to(LINE_START, last_y);
2954f73fc56SMatthew Dillon }
2964f73fc56SMatthew Dillon 
2974f73fc56SMatthew Dillon /*
2984f73fc56SMatthew Dillon  * Scroll one line up. Leave the cursor on the same line (if possible).
2994f73fc56SMatthew Dillon  */
3008ecf459dSSascha Wildner void
SU(int u __unused)3018ecf459dSSascha Wildner SU(int u __unused)
3024f73fc56SMatthew Dillon {
3034f73fc56SMatthew Dillon   if (top_line->prev == header)	/* Top of file. Can't scroll */
3044f73fc56SMatthew Dillon   	return;
3054f73fc56SMatthew Dillon 
3068ecf459dSSascha Wildner   reverse_scroll();
3074f73fc56SMatthew Dillon   set_cursor(0, ymax);		/* Erase very bottom line */
3084f73fc56SMatthew Dillon #ifdef UNIX
3094f73fc56SMatthew Dillon   tputs(CE, 0, _putchar);
3104f73fc56SMatthew Dillon #else
3114f73fc56SMatthew Dillon   string_print(blank_line);
3124f73fc56SMatthew Dillon #endif /* UNIX */
3134f73fc56SMatthew Dillon   move_to(x, (y == screenmax) ? screenmax : y + 1);
3144f73fc56SMatthew Dillon }
3154f73fc56SMatthew Dillon 
3164f73fc56SMatthew Dillon /*
3174f73fc56SMatthew Dillon  * Scroll one line down. Leave the cursor on the same line (if possible).
3184f73fc56SMatthew Dillon  */
3198ecf459dSSascha Wildner void
SD(int u __unused)3208ecf459dSSascha Wildner SD(int u __unused)
3214f73fc56SMatthew Dillon {
3224f73fc56SMatthew Dillon   if (forward_scroll() != ERRORS)
3234f73fc56SMatthew Dillon   	move_to(x, (y == 0) ? 0 : y - 1);
3244f73fc56SMatthew Dillon   else
3254f73fc56SMatthew Dillon   	set_cursor(x, y);
3264f73fc56SMatthew Dillon }
3274f73fc56SMatthew Dillon 
3284f73fc56SMatthew Dillon /*
3294f73fc56SMatthew Dillon  * Perform a forward scroll. It returns ERRORS if we're at the last line of the
3304f73fc56SMatthew Dillon  * file.
3314f73fc56SMatthew Dillon  */
3328ecf459dSSascha Wildner int
forward_scroll(void)3338ecf459dSSascha Wildner forward_scroll(void)
3344f73fc56SMatthew Dillon {
3354f73fc56SMatthew Dillon   if (bot_line->next == tail)		/* Last line of file. No dice */
3364f73fc56SMatthew Dillon   	return ERRORS;
3374f73fc56SMatthew Dillon   top_line = top_line->next;
3384f73fc56SMatthew Dillon   bot_line = bot_line->next;
3394f73fc56SMatthew Dillon   cur_line = cur_line->next;
3404f73fc56SMatthew Dillon   set_cursor(0, ymax);
3414f73fc56SMatthew Dillon   line_print(bot_line);
3424f73fc56SMatthew Dillon 
3434f73fc56SMatthew Dillon   return FINE;
3444f73fc56SMatthew Dillon }
3454f73fc56SMatthew Dillon 
3464f73fc56SMatthew Dillon /*
3474f73fc56SMatthew Dillon  * Perform a backwards scroll. It returns ERRORS if we're at the first line
3484f73fc56SMatthew Dillon  * of the file.
3494f73fc56SMatthew Dillon  */
3508ecf459dSSascha Wildner int
reverse_scroll(void)3518ecf459dSSascha Wildner reverse_scroll(void)
3524f73fc56SMatthew Dillon {
3534f73fc56SMatthew Dillon   if (top_line->prev == header)
3544f73fc56SMatthew Dillon   	return ERRORS;		/* Top of file. Can't scroll */
3554f73fc56SMatthew Dillon 
3564f73fc56SMatthew Dillon   if (last_y != screenmax)	/* Reset last_y if necessary */
3574f73fc56SMatthew Dillon   	last_y++;
3584f73fc56SMatthew Dillon   else
3594f73fc56SMatthew Dillon   	bot_line = bot_line->prev;	/* Else adjust bot_line */
3604f73fc56SMatthew Dillon   top_line = top_line->prev;
3614f73fc56SMatthew Dillon   cur_line = cur_line->prev;
3624f73fc56SMatthew Dillon 
3634f73fc56SMatthew Dillon /* Perform the scroll */
3644f73fc56SMatthew Dillon   set_cursor(0, 0);
3654f73fc56SMatthew Dillon #ifdef UNIX
3664f73fc56SMatthew Dillon   tputs(AL, 0, _putchar);
3674f73fc56SMatthew Dillon #else
3684f73fc56SMatthew Dillon   string_print(rev_scroll);
3694f73fc56SMatthew Dillon #endif /* UNIX */
3704f73fc56SMatthew Dillon   set_cursor(0, 0);
3714f73fc56SMatthew Dillon   line_print(top_line);
3724f73fc56SMatthew Dillon 
3734f73fc56SMatthew Dillon   return FINE;
3744f73fc56SMatthew Dillon }
3754f73fc56SMatthew Dillon 
3764f73fc56SMatthew Dillon /*
3774f73fc56SMatthew Dillon  * A word is defined as a number of non-blank characters separated by tabs
3784f73fc56SMatthew Dillon  * spaces or linefeeds.
3794f73fc56SMatthew Dillon  */
3804f73fc56SMatthew Dillon 
3814f73fc56SMatthew Dillon /*
3824f73fc56SMatthew Dillon  * MP() moves to the start of the previous word. A word is defined as a
3834f73fc56SMatthew Dillon  * number of non-blank characters separated by tabs spaces or linefeeds.
3844f73fc56SMatthew Dillon  */
3858ecf459dSSascha Wildner void
MP(int u __unused)3868ecf459dSSascha Wildner MP(int u __unused)
3874f73fc56SMatthew Dillon {
3884f73fc56SMatthew Dillon   move_previous_word(NO_DELETE);
3894f73fc56SMatthew Dillon }
3904f73fc56SMatthew Dillon 
3918ecf459dSSascha Wildner void
move_previous_word(FLAG remove)3928ecf459dSSascha Wildner move_previous_word(FLAG remove)
3934f73fc56SMatthew Dillon {
3948ecf459dSSascha Wildner   char *begin_line;
3958ecf459dSSascha Wildner   char *textp;
3964f73fc56SMatthew Dillon   char start_char = *cur_text;
3974f73fc56SMatthew Dillon   char *start_pos = cur_text;
3984f73fc56SMatthew Dillon 
3994f73fc56SMatthew Dillon /* Fist check if we're at the beginning of line. */
4004f73fc56SMatthew Dillon   if (cur_text == cur_line->text) {
4014f73fc56SMatthew Dillon   	if (cur_line->prev == header)
4024f73fc56SMatthew Dillon   		return;
4034f73fc56SMatthew Dillon   	start_char = '\0';
4044f73fc56SMatthew Dillon   }
4054f73fc56SMatthew Dillon 
4068ecf459dSSascha Wildner   LF(0);
4074f73fc56SMatthew Dillon 
4084f73fc56SMatthew Dillon   begin_line = cur_line->text;
4094f73fc56SMatthew Dillon   textp = cur_text;
4104f73fc56SMatthew Dillon 
4114f73fc56SMatthew Dillon /* Check if we're in the middle of a word. */
4124f73fc56SMatthew Dillon   if (!alpha(*textp) || !alpha(start_char)) {
4134f73fc56SMatthew Dillon   	while (textp != begin_line && (white_space(*textp) || *textp == '\n'))
4144f73fc56SMatthew Dillon   		textp--;
4154f73fc56SMatthew Dillon   }
4164f73fc56SMatthew Dillon 
4174f73fc56SMatthew Dillon /* Now we're at the end of previous word. Skip non-blanks until a blank comes */
4184f73fc56SMatthew Dillon   while (textp != begin_line && alpha(*textp))
4194f73fc56SMatthew Dillon   	textp--;
4204f73fc56SMatthew Dillon 
4214f73fc56SMatthew Dillon /* Go to the next char if we're not at the beginning of the line */
4224f73fc56SMatthew Dillon   if (textp != begin_line && *textp != '\n')
4234f73fc56SMatthew Dillon   	textp++;
4244f73fc56SMatthew Dillon 
4254f73fc56SMatthew Dillon /* Find the x-coordinate of this address, and move to it */
4264f73fc56SMatthew Dillon   move_address(textp);
4274f73fc56SMatthew Dillon   if (remove == DELETE)
4284f73fc56SMatthew Dillon   	delete(cur_line, textp, cur_line, start_pos);
4294f73fc56SMatthew Dillon }
4304f73fc56SMatthew Dillon 
4314f73fc56SMatthew Dillon /*
4324f73fc56SMatthew Dillon  * MN() moves to the start of the next word. A word is defined as a number of
4334f73fc56SMatthew Dillon  * non-blank characters separated by tabs spaces or linefeeds. Always keep in
4344f73fc56SMatthew Dillon  * mind that the pointer shouldn't pass the '\n'.
4354f73fc56SMatthew Dillon  */
4368ecf459dSSascha Wildner void
MN(int u __unused)4378ecf459dSSascha Wildner MN(int u __unused)
4384f73fc56SMatthew Dillon {
4394f73fc56SMatthew Dillon   move_next_word(NO_DELETE);
4404f73fc56SMatthew Dillon }
4414f73fc56SMatthew Dillon 
4428ecf459dSSascha Wildner void
move_next_word(FLAG remove)4438ecf459dSSascha Wildner move_next_word(FLAG remove)
4444f73fc56SMatthew Dillon {
4458ecf459dSSascha Wildner   char *textp = cur_text;
4464f73fc56SMatthew Dillon 
4474f73fc56SMatthew Dillon /* Move to the end of the current word. */
4484f73fc56SMatthew Dillon   while (*textp != '\n' && alpha(*textp))
4494f73fc56SMatthew Dillon   	textp++;
4504f73fc56SMatthew Dillon 
4514f73fc56SMatthew Dillon /* Skip all white spaces */
4524f73fc56SMatthew Dillon   while (*textp != '\n' && white_space(*textp))
4534f73fc56SMatthew Dillon   	textp++;
4544f73fc56SMatthew Dillon /* If we're deleting. delete the text in between */
4554f73fc56SMatthew Dillon   if (remove == DELETE) {
4564f73fc56SMatthew Dillon   	delete(cur_line, cur_text, cur_line, textp);
4574f73fc56SMatthew Dillon   	return;
4584f73fc56SMatthew Dillon   }
4594f73fc56SMatthew Dillon 
4604f73fc56SMatthew Dillon /* If we're at end of line. move to the first word on the next line. */
4614f73fc56SMatthew Dillon   if (*textp == '\n' && cur_line->next != tail) {
4628ecf459dSSascha Wildner   	DN(0);
4634f73fc56SMatthew Dillon   	move_to(LINE_START, y);
4644f73fc56SMatthew Dillon   	textp = cur_text;
4654f73fc56SMatthew Dillon   	while (*textp != '\n' && white_space(*textp))
4664f73fc56SMatthew Dillon   		textp++;
4674f73fc56SMatthew Dillon   }
4684f73fc56SMatthew Dillon   move_address(textp);
4694f73fc56SMatthew Dillon }
4704f73fc56SMatthew Dillon 
4714f73fc56SMatthew Dillon /*  ========================================================================  *
4724f73fc56SMatthew Dillon  *				Modify Commands				      *
4734f73fc56SMatthew Dillon  *  ========================================================================  */
4744f73fc56SMatthew Dillon 
4754f73fc56SMatthew Dillon /*
4764f73fc56SMatthew Dillon  * DCC deletes the character under the cursor.  If this character is a '\n' the
4774f73fc56SMatthew Dillon  * current line is joined with the next one.
4784f73fc56SMatthew Dillon  * If this character is the only character of the line, the current line will
4794f73fc56SMatthew Dillon  * be deleted.
4804f73fc56SMatthew Dillon  */
4818ecf459dSSascha Wildner void
DCC(int u __unused)4828ecf459dSSascha Wildner DCC(int u __unused)
4834f73fc56SMatthew Dillon {
4844f73fc56SMatthew Dillon   if (*cur_text == '\n')
4854f73fc56SMatthew Dillon   	delete(cur_line,cur_text, cur_line->next,cur_line->next->text);
4864f73fc56SMatthew Dillon   else
4874f73fc56SMatthew Dillon   	delete(cur_line, cur_text, cur_line, cur_text + 1);
4884f73fc56SMatthew Dillon }
4894f73fc56SMatthew Dillon 
4904f73fc56SMatthew Dillon /*
4914f73fc56SMatthew Dillon  * DPC deletes the character on the left side of the cursor.  If the cursor is
4924f73fc56SMatthew Dillon  * at the beginning of the line, the last character if the previous line is
4934f73fc56SMatthew Dillon  * deleted.
4944f73fc56SMatthew Dillon  */
4958ecf459dSSascha Wildner void
DPC(int u __unused)4968ecf459dSSascha Wildner DPC(int u __unused)
4974f73fc56SMatthew Dillon {
4984f73fc56SMatthew Dillon   if (x == 0 && cur_line->prev == header)
4994f73fc56SMatthew Dillon   	return;			/* Top of file */
5004f73fc56SMatthew Dillon 
5018ecf459dSSascha Wildner   LF(0);				/* Move one left */
5028ecf459dSSascha Wildner   DCC(0);				/* Delete character under cursor */
5034f73fc56SMatthew Dillon }
5044f73fc56SMatthew Dillon 
5054f73fc56SMatthew Dillon /*
5064f73fc56SMatthew Dillon  * DLN deletes all characters until the end of the line. If the current
5074f73fc56SMatthew Dillon  * character is a '\n', then delete that char.
5084f73fc56SMatthew Dillon  */
5098ecf459dSSascha Wildner void
DLN(int u __unused)5108ecf459dSSascha Wildner DLN(int u __unused)
5114f73fc56SMatthew Dillon {
5124f73fc56SMatthew Dillon   if (*cur_text == '\n')
5138ecf459dSSascha Wildner   	DCC(0);
5144f73fc56SMatthew Dillon   else
5154f73fc56SMatthew Dillon   	delete(cur_line, cur_text, cur_line, cur_text + length_of(cur_text) -1);
5164f73fc56SMatthew Dillon }
5174f73fc56SMatthew Dillon 
5184f73fc56SMatthew Dillon /*
5194f73fc56SMatthew Dillon  * DNW() deletes the next word (as described in MN())
5204f73fc56SMatthew Dillon  */
5218ecf459dSSascha Wildner void
DNW(int u __unused)5228ecf459dSSascha Wildner DNW(int u __unused)
5234f73fc56SMatthew Dillon {
5244f73fc56SMatthew Dillon   if (*cur_text == '\n')
5258ecf459dSSascha Wildner   	DCC(0);
5264f73fc56SMatthew Dillon   else
5274f73fc56SMatthew Dillon   	move_next_word(DELETE);
5284f73fc56SMatthew Dillon }
5294f73fc56SMatthew Dillon 
5304f73fc56SMatthew Dillon /*
5314f73fc56SMatthew Dillon  * DPW() deletes the next word (as described in MP())
5324f73fc56SMatthew Dillon  */
5338ecf459dSSascha Wildner void
DPW(int u __unused)5348ecf459dSSascha Wildner DPW(int u __unused)
5354f73fc56SMatthew Dillon {
5364f73fc56SMatthew Dillon   if (cur_text == cur_line->text)
5378ecf459dSSascha Wildner   	DPC(0);
5384f73fc56SMatthew Dillon   else
5394f73fc56SMatthew Dillon   	move_previous_word(DELETE);
5404f73fc56SMatthew Dillon }
5414f73fc56SMatthew Dillon 
5424f73fc56SMatthew Dillon /*
5434f73fc56SMatthew Dillon  * Insert character `character' at current location.
5444f73fc56SMatthew Dillon  */
5458ecf459dSSascha Wildner void
S(int character)5468ecf459dSSascha Wildner S(int character)
5474f73fc56SMatthew Dillon {
5484f73fc56SMatthew Dillon   static char buffer[2];
5494f73fc56SMatthew Dillon 
5504f73fc56SMatthew Dillon   buffer[0] = character;
5514f73fc56SMatthew Dillon /* Insert the character */
5524f73fc56SMatthew Dillon   if (insert(cur_line, cur_text, buffer) == ERRORS)
5534f73fc56SMatthew Dillon   	return;
5544f73fc56SMatthew Dillon 
5554f73fc56SMatthew Dillon /* Fix screen */
5564f73fc56SMatthew Dillon   if (character == '\n') {
5574f73fc56SMatthew Dillon   	set_cursor(0, y);
5584f73fc56SMatthew Dillon   	if (y == screenmax) {		/* Can't use display */
5594f73fc56SMatthew Dillon   		line_print(cur_line);
5608ecf459dSSascha Wildner   		forward_scroll();
5614f73fc56SMatthew Dillon   	}
5624f73fc56SMatthew Dillon   	else {
5634f73fc56SMatthew Dillon   		reset(top_line, y);	/* Reset pointers */
5644f73fc56SMatthew Dillon   		display(0, y, cur_line, last_y - y);
5654f73fc56SMatthew Dillon   	}
5664f73fc56SMatthew Dillon   	move_to(0, (y == screenmax) ? y : y + 1);
5674f73fc56SMatthew Dillon   }
5684f73fc56SMatthew Dillon   else if (x + 1 == XBREAK)/* If line must be shifted, just call move_to*/
5694f73fc56SMatthew Dillon   	move_to(x + 1, y);
5704f73fc56SMatthew Dillon   else {			 /* else display rest of line */
5714f73fc56SMatthew Dillon   	put_line(cur_line, x, FALSE);
5724f73fc56SMatthew Dillon   	move_to(x + 1, y);
5734f73fc56SMatthew Dillon   }
5744f73fc56SMatthew Dillon }
5754f73fc56SMatthew Dillon 
5764f73fc56SMatthew Dillon /*
5774f73fc56SMatthew Dillon  * CTL inserts a control-char at the current location. A message that this
5784f73fc56SMatthew Dillon  * function is called is displayed at the status line.
5794f73fc56SMatthew Dillon  */
5808ecf459dSSascha Wildner void
CTL(int u __unused)5818ecf459dSSascha Wildner CTL(int u __unused)
5824f73fc56SMatthew Dillon {
5838ecf459dSSascha Wildner   char ctrl;
5844f73fc56SMatthew Dillon 
5854f73fc56SMatthew Dillon   status_line("Enter control character.", NIL_PTR);
5864f73fc56SMatthew Dillon   if ((ctrl = getchar()) >= '\01' && ctrl <= '\037') {
5874f73fc56SMatthew Dillon   	S(ctrl);		/* Insert the char */
5884f73fc56SMatthew Dillon 	clear_status();
5894f73fc56SMatthew Dillon   }
5904f73fc56SMatthew Dillon   else
5914f73fc56SMatthew Dillon 	error ("Unknown control character", NIL_PTR);
5924f73fc56SMatthew Dillon }
5934f73fc56SMatthew Dillon 
5944f73fc56SMatthew Dillon /*
5954f73fc56SMatthew Dillon  * LIB insert a line at the current position and moves back to the end of
5964f73fc56SMatthew Dillon  * the previous line.
5974f73fc56SMatthew Dillon  */
5988ecf459dSSascha Wildner void
LIB(int u __unused)5998ecf459dSSascha Wildner LIB(int u __unused)
6004f73fc56SMatthew Dillon {
6014f73fc56SMatthew Dillon   S('\n');	  		/* Insert the line */
6028ecf459dSSascha Wildner   UP(0);			/* Move one line up */
6034f73fc56SMatthew Dillon   move_to(LINE_END, y);		/* Move to end of this line */
6044f73fc56SMatthew Dillon }
6054f73fc56SMatthew Dillon 
6064f73fc56SMatthew Dillon /*
6074f73fc56SMatthew Dillon  * Line_insert() inserts a new line with text pointed to by `string'.
6084f73fc56SMatthew Dillon  * It returns the address of the new line.
6094f73fc56SMatthew Dillon  */
6108ecf459dSSascha Wildner LINE *
line_insert(LINE * line,const char * string,int len)6118ecf459dSSascha Wildner line_insert(LINE *line, const char *string, int len)
6124f73fc56SMatthew Dillon {
6138ecf459dSSascha Wildner   LINE *new_line;
6144f73fc56SMatthew Dillon 
6154f73fc56SMatthew Dillon /* Allocate space for LINE structure and text */
6164f73fc56SMatthew Dillon   new_line = install_line(string, len);
6174f73fc56SMatthew Dillon 
6184f73fc56SMatthew Dillon /* Install the line into the double linked list */
6194f73fc56SMatthew Dillon   new_line->prev = line;
6204f73fc56SMatthew Dillon   new_line->next = line->next;
6214f73fc56SMatthew Dillon   line->next = new_line;
6224f73fc56SMatthew Dillon   new_line->next->prev = new_line;
6234f73fc56SMatthew Dillon 
6244f73fc56SMatthew Dillon /* Increment nlines */
6254f73fc56SMatthew Dillon   nlines++;
6264f73fc56SMatthew Dillon 
6274f73fc56SMatthew Dillon   return new_line;
6284f73fc56SMatthew Dillon }
6294f73fc56SMatthew Dillon 
6304f73fc56SMatthew Dillon /*
6314f73fc56SMatthew Dillon  * Insert() insert the string `string' at the given line and location.
6324f73fc56SMatthew Dillon  */
6338ecf459dSSascha Wildner int
insert(LINE * line,char * location,char * string)6348ecf459dSSascha Wildner insert(LINE *line, char *location, char *string)
6354f73fc56SMatthew Dillon {
6368ecf459dSSascha Wildner   char *bufp = text_buffer;	/* Buffer for building line */
6378ecf459dSSascha Wildner   char *textp = line->text;
6384f73fc56SMatthew Dillon 
6394f73fc56SMatthew Dillon   if (length_of(textp) + length_of(string) >= MAX_CHARS) {
6404f73fc56SMatthew Dillon   	error("Line too long", NIL_PTR);
6414f73fc56SMatthew Dillon   	return ERRORS;
6424f73fc56SMatthew Dillon   }
6434f73fc56SMatthew Dillon 
6444f73fc56SMatthew Dillon   modified = TRUE;			/* File has been modified */
6454f73fc56SMatthew Dillon 
6464f73fc56SMatthew Dillon /* Copy part of line until `location' has been reached */
6474f73fc56SMatthew Dillon   while (textp != location)
6484f73fc56SMatthew Dillon   	*bufp++ = *textp++;
6494f73fc56SMatthew Dillon 
6504f73fc56SMatthew Dillon /* Insert string at this location */
6514f73fc56SMatthew Dillon   while (*string != '\0')
6524f73fc56SMatthew Dillon   	*bufp++ = *string++;
6534f73fc56SMatthew Dillon   *bufp = '\0';
6544f73fc56SMatthew Dillon 
6554f73fc56SMatthew Dillon   if (*(string - 1) == '\n')		/* Insert a new line */
6561f0f7b35SSascha Wildner   	line_insert(line, location, length_of(location));
6574f73fc56SMatthew Dillon   else					/* Append last part of line */
6584f73fc56SMatthew Dillon   	copy_string(bufp, location);
6594f73fc56SMatthew Dillon 
6604f73fc56SMatthew Dillon /* Install the new text in this line */
6614f73fc56SMatthew Dillon   free_space(line->text);
6624f73fc56SMatthew Dillon   line->text = alloc(length_of(text_buffer) + 1);
6634f73fc56SMatthew Dillon   copy_string(line->text, text_buffer);
6644f73fc56SMatthew Dillon 
6654f73fc56SMatthew Dillon   return FINE;
6664f73fc56SMatthew Dillon }
6674f73fc56SMatthew Dillon 
6684f73fc56SMatthew Dillon /*
6694f73fc56SMatthew Dillon  * Line_delete() deletes the argument line out of the line list. The pointer to
6704f73fc56SMatthew Dillon  * the next line is returned.
6714f73fc56SMatthew Dillon  */
6728ecf459dSSascha Wildner LINE *
line_delete(LINE * line)6738ecf459dSSascha Wildner line_delete(LINE *line)
6744f73fc56SMatthew Dillon {
6758ecf459dSSascha Wildner   LINE *next_line = line->next;
6764f73fc56SMatthew Dillon 
6774f73fc56SMatthew Dillon /* Delete the line */
6784f73fc56SMatthew Dillon   line->prev->next = line->next;
6794f73fc56SMatthew Dillon   line->next->prev = line->prev;
6804f73fc56SMatthew Dillon 
6814f73fc56SMatthew Dillon /* Free allocated space */
6824f73fc56SMatthew Dillon   free_space(line->text);
6834f73fc56SMatthew Dillon   free_space((char*)line);
6844f73fc56SMatthew Dillon 
6854f73fc56SMatthew Dillon /* Decrement nlines */
6864f73fc56SMatthew Dillon   nlines--;
6874f73fc56SMatthew Dillon 
6884f73fc56SMatthew Dillon   return next_line;
6894f73fc56SMatthew Dillon }
6904f73fc56SMatthew Dillon 
6914f73fc56SMatthew Dillon /*
6924f73fc56SMatthew Dillon  * Delete() deletes all the characters (including newlines) between the
6934f73fc56SMatthew Dillon  * startposition and endposition and fixes the screen accordingly. It
6944f73fc56SMatthew Dillon  * returns the number of lines deleted.
6954f73fc56SMatthew Dillon  */
6968ecf459dSSascha Wildner void
delete(LINE * start_line,char * start_textp,LINE * end_line,char * end_textp)6978ecf459dSSascha Wildner delete(LINE *start_line, char *start_textp,
6988ecf459dSSascha Wildner        LINE *end_line, char *end_textp)
6994f73fc56SMatthew Dillon {
7008ecf459dSSascha Wildner   char *textp = start_line->text;
7018ecf459dSSascha Wildner   char *bufp = text_buffer;	/* Storage for new line->text */
7024f73fc56SMatthew Dillon   LINE *line, *stop;
7034f73fc56SMatthew Dillon   int line_cnt = 0;			/* Nr of lines deleted */
7044f73fc56SMatthew Dillon   int count = 0;
7054f73fc56SMatthew Dillon   int shift = 0;				/* Used in shift calculation */
7064f73fc56SMatthew Dillon   int nx = x;
7074f73fc56SMatthew Dillon 
7084f73fc56SMatthew Dillon   modified = TRUE;			/* File has been modified */
7094f73fc56SMatthew Dillon 
7104f73fc56SMatthew Dillon /* Set up new line. Copy first part of start line until start_position. */
7114f73fc56SMatthew Dillon   while (textp < start_textp) {
7124f73fc56SMatthew Dillon   	*bufp++ = *textp++;
7134f73fc56SMatthew Dillon   	count++;
7144f73fc56SMatthew Dillon   }
7154f73fc56SMatthew Dillon 
7164f73fc56SMatthew Dillon /* Check if line doesn't exceed MAX_CHARS */
7174f73fc56SMatthew Dillon   if (count + length_of(end_textp) >= MAX_CHARS) {
7184f73fc56SMatthew Dillon   	error("Line too long", NIL_PTR);
7194f73fc56SMatthew Dillon   	return;
7204f73fc56SMatthew Dillon   }
7214f73fc56SMatthew Dillon 
7224f73fc56SMatthew Dillon /* Copy last part of end_line if end_line is not tail */
7234f73fc56SMatthew Dillon   copy_string(bufp, (end_textp != NIL_PTR) ? end_textp : "\n");
7244f73fc56SMatthew Dillon 
7254f73fc56SMatthew Dillon /* Delete all lines between start and end_position (including end_line) */
7264f73fc56SMatthew Dillon   line = start_line->next;
7274f73fc56SMatthew Dillon   stop = end_line->next;
7284f73fc56SMatthew Dillon   while (line != stop && line != tail) {
7294f73fc56SMatthew Dillon   	line = line_delete(line);
7304f73fc56SMatthew Dillon   	line_cnt++;
7314f73fc56SMatthew Dillon   }
7324f73fc56SMatthew Dillon 
7334f73fc56SMatthew Dillon /* Check if last line of file should be deleted */
7344f73fc56SMatthew Dillon   if (end_textp == NIL_PTR && length_of(start_line->text) == 1 && nlines > 1) {
7354f73fc56SMatthew Dillon   	start_line = start_line->prev;
7368ecf459dSSascha Wildner   	line_delete(start_line->next);
7374f73fc56SMatthew Dillon   	line_cnt++;
7384f73fc56SMatthew Dillon   }
7394f73fc56SMatthew Dillon   else {	/* Install new text */
7404f73fc56SMatthew Dillon   	free_space(start_line->text);
7414f73fc56SMatthew Dillon   	start_line->text = alloc(length_of(text_buffer) + 1);
7424f73fc56SMatthew Dillon   	copy_string(start_line->text, text_buffer);
7434f73fc56SMatthew Dillon   }
7444f73fc56SMatthew Dillon 
7454f73fc56SMatthew Dillon /* Fix screen. First check if line is shifted. Perhaps we should shift it back*/
7464f73fc56SMatthew Dillon   if (get_shift(start_line->shift_count)) {
7474f73fc56SMatthew Dillon   	shift = (XBREAK - count_chars(start_line)) / SHIFT_SIZE;
7484f73fc56SMatthew Dillon   	if (shift > 0) {		/* Shift line `shift' back */
7494f73fc56SMatthew Dillon   		if (shift >= get_shift(start_line->shift_count))
7504f73fc56SMatthew Dillon   			start_line->shift_count = 0;
7514f73fc56SMatthew Dillon   		else
7524f73fc56SMatthew Dillon   			start_line->shift_count -= shift;
7534f73fc56SMatthew Dillon   		nx += shift * SHIFT_SIZE;/* Reset x value */
7544f73fc56SMatthew Dillon   	}
7554f73fc56SMatthew Dillon   }
7564f73fc56SMatthew Dillon 
7574f73fc56SMatthew Dillon   if (line_cnt == 0) {		    /* Check if only one line changed */
7584f73fc56SMatthew Dillon   	if (shift > 0) {	    /* Reprint whole line */
7594f73fc56SMatthew Dillon   		set_cursor(0, y);
7604f73fc56SMatthew Dillon   		line_print(start_line);
7614f73fc56SMatthew Dillon   	}
7624f73fc56SMatthew Dillon   	else {			    /* Just display last part of line */
7634f73fc56SMatthew Dillon   		set_cursor(x, y);
7644f73fc56SMatthew Dillon   		put_line(start_line, x, TRUE);
7654f73fc56SMatthew Dillon   	}
7664f73fc56SMatthew Dillon   	move_to(nx, y);	   /* Reset cur_text */
7674f73fc56SMatthew Dillon   	return;
7684f73fc56SMatthew Dillon   }
7694f73fc56SMatthew Dillon 
7704f73fc56SMatthew Dillon   shift = last_y;	   /* Save value */
7714f73fc56SMatthew Dillon   reset(top_line, y);
7724f73fc56SMatthew Dillon   display(0, y, start_line, shift - y);
7734f73fc56SMatthew Dillon   move_to((line_cnt == 1) ? nx : 0, y);
7744f73fc56SMatthew Dillon }
7754f73fc56SMatthew Dillon 
7764f73fc56SMatthew Dillon /*  ========================================================================  *
7774f73fc56SMatthew Dillon  *				Yank Commands				      *
7784f73fc56SMatthew Dillon  *  ========================================================================  */
7794f73fc56SMatthew Dillon 
7804f73fc56SMatthew Dillon LINE *mark_line;			/* For marking position. */
7814f73fc56SMatthew Dillon char *mark_text;
7824f73fc56SMatthew Dillon int lines_saved;			/* Nr of lines in buffer */
7834f73fc56SMatthew Dillon 
7844f73fc56SMatthew Dillon /*
7854f73fc56SMatthew Dillon  * PT() inserts the buffer at the current location.
7864f73fc56SMatthew Dillon  */
7878ecf459dSSascha Wildner void
PT(int u __unused)7888ecf459dSSascha Wildner PT(int u __unused)
7894f73fc56SMatthew Dillon {
7908ecf459dSSascha Wildner   int fd;		/* File descriptor for buffer */
7914f73fc56SMatthew Dillon 
7924f73fc56SMatthew Dillon   if ((fd = scratch_file(READ)) == ERRORS)
7934f73fc56SMatthew Dillon   	error("Buffer is empty.", NIL_PTR);
7944f73fc56SMatthew Dillon   else {
7954f73fc56SMatthew Dillon   	file_insert(fd, FALSE);/* Insert the buffer */
7961f0f7b35SSascha Wildner   	close(fd);
7974f73fc56SMatthew Dillon   }
7984f73fc56SMatthew Dillon }
7994f73fc56SMatthew Dillon 
8004f73fc56SMatthew Dillon /*
8014f73fc56SMatthew Dillon  * IF() prompt for a filename and inserts the file at the current location
8024f73fc56SMatthew Dillon  * in the file.
8034f73fc56SMatthew Dillon  */
8048ecf459dSSascha Wildner void
IF(int u __unused)8058ecf459dSSascha Wildner IF(int u __unused)
8064f73fc56SMatthew Dillon {
8078ecf459dSSascha Wildner   int fd;		/* File descriptor of file */
8084f73fc56SMatthew Dillon   char name[LINE_LEN];		/* Buffer for file name */
8094f73fc56SMatthew Dillon 
8104f73fc56SMatthew Dillon /* Get the file name */
8114f73fc56SMatthew Dillon   if (get_file("Get and insert file:", name) != FINE)
8124f73fc56SMatthew Dillon   	return;
8134f73fc56SMatthew Dillon 
8144f73fc56SMatthew Dillon   if ((fd = open(name, 0)) < 0)
8154f73fc56SMatthew Dillon   	error("Cannot open ", name);
8164f73fc56SMatthew Dillon   else {
8174f73fc56SMatthew Dillon   	file_insert(fd, TRUE);	/* Insert the file */
8181f0f7b35SSascha Wildner   	close(fd);
8194f73fc56SMatthew Dillon   }
8204f73fc56SMatthew Dillon }
8214f73fc56SMatthew Dillon 
8224f73fc56SMatthew Dillon /*
8234f73fc56SMatthew Dillon  * File_insert() inserts a an opened file (as given by filedescriptor fd)
8244f73fc56SMatthew Dillon  * at the current location.
8254f73fc56SMatthew Dillon  */
8268ecf459dSSascha Wildner void
file_insert(int fd,FLAG old_pos)8278ecf459dSSascha Wildner file_insert(int fd, FLAG old_pos)
8284f73fc56SMatthew Dillon {
8294f73fc56SMatthew Dillon   char line_buffer[MAX_CHARS];		/* Buffer for next line */
8308ecf459dSSascha Wildner   LINE *line = cur_line;
8318ecf459dSSascha Wildner   int line_count = nlines;	/* Nr of lines inserted */
8324f73fc56SMatthew Dillon   LINE *page = cur_line;
8334f73fc56SMatthew Dillon   int ret = ERRORS;
8344f73fc56SMatthew Dillon 
8354f73fc56SMatthew Dillon /* Get the first piece of text (might be ended with a '\n') from fd */
8364f73fc56SMatthew Dillon   if (get_line(fd, line_buffer) == ERRORS)
8374f73fc56SMatthew Dillon   	return;				/* Empty file */
8384f73fc56SMatthew Dillon 
8394f73fc56SMatthew Dillon /* Insert this text at the current location. */
8404f73fc56SMatthew Dillon   if (insert(line, cur_text, line_buffer) == ERRORS)
8414f73fc56SMatthew Dillon   	return;
8424f73fc56SMatthew Dillon 
8434f73fc56SMatthew Dillon /* Repeat getting lines (and inserting lines) until EOF is reached */
8444f73fc56SMatthew Dillon   while ((ret = get_line(fd, line_buffer)) != ERRORS && ret != NO_LINE)
8454f73fc56SMatthew Dillon   	line = line_insert(line, line_buffer, ret);
8464f73fc56SMatthew Dillon 
8474f73fc56SMatthew Dillon   if (ret == NO_LINE) {		/* Last line read not ended by a '\n' */
8484f73fc56SMatthew Dillon   	line = line->next;
8491f0f7b35SSascha Wildner   	insert(line, line->text, line_buffer);
8504f73fc56SMatthew Dillon   }
8514f73fc56SMatthew Dillon 
8524f73fc56SMatthew Dillon /* Calculate nr of lines added */
8534f73fc56SMatthew Dillon   line_count = nlines - line_count;
8544f73fc56SMatthew Dillon 
8554f73fc56SMatthew Dillon /* Fix the screen */
8564f73fc56SMatthew Dillon   if (line_count == 0) {		/* Only one line changed */
8574f73fc56SMatthew Dillon   	set_cursor(0, y);
8584f73fc56SMatthew Dillon   	line_print(line);
8594f73fc56SMatthew Dillon   	move_to((old_pos == TRUE) ? x : x + length_of(line_buffer), y);
8604f73fc56SMatthew Dillon   }
8614f73fc56SMatthew Dillon   else {				/* Several lines changed */
8624f73fc56SMatthew Dillon   	reset(top_line, y);	/* Reset pointers */
8634f73fc56SMatthew Dillon   	while (page != line && page != bot_line->next)
8644f73fc56SMatthew Dillon   		page = page->next;
8654f73fc56SMatthew Dillon   	if (page != bot_line->next || old_pos == TRUE)
8664f73fc56SMatthew Dillon   		display(0, y, cur_line, screenmax - y);
8674f73fc56SMatthew Dillon   	if (old_pos == TRUE)
8684f73fc56SMatthew Dillon   		move_to(x, y);
8694f73fc56SMatthew Dillon   	else if (ret == NO_LINE)
8704f73fc56SMatthew Dillon 		move_to(length_of(line_buffer), find_y(line));
8714f73fc56SMatthew Dillon 	else
8724f73fc56SMatthew Dillon 		move_to(0, find_y(line->next));
8734f73fc56SMatthew Dillon   }
8744f73fc56SMatthew Dillon 
8754f73fc56SMatthew Dillon /* If nr of added line >= REPORT, print the count */
8764f73fc56SMatthew Dillon   if (line_count >= REPORT)
8774f73fc56SMatthew Dillon   	status_line(num_out((long) line_count), " lines added.");
8784f73fc56SMatthew Dillon }
8794f73fc56SMatthew Dillon 
8804f73fc56SMatthew Dillon /*
8814f73fc56SMatthew Dillon  * WB() writes the buffer (yank_file) into another file, which
8824f73fc56SMatthew Dillon  * is prompted for.
8834f73fc56SMatthew Dillon  */
8848ecf459dSSascha Wildner void
WB(int u __unused)8858ecf459dSSascha Wildner WB(int u __unused)
8864f73fc56SMatthew Dillon {
8878ecf459dSSascha Wildner   int new_fd;		/* Filedescriptor to copy file */
8884f73fc56SMatthew Dillon   int yank_fd;			/* Filedescriptor to buffer */
8898ecf459dSSascha Wildner   int cnt;		/* Count check for read/write */
8904f73fc56SMatthew Dillon   int ret = 0;			/* Error check for write */
8914f73fc56SMatthew Dillon   char file[LINE_LEN];		/* Output file */
8924f73fc56SMatthew Dillon 
8934f73fc56SMatthew Dillon /* Checkout the buffer */
8944f73fc56SMatthew Dillon   if ((yank_fd = scratch_file(READ)) == ERRORS) {
8954f73fc56SMatthew Dillon   	error("Buffer is empty.", NIL_PTR);
8964f73fc56SMatthew Dillon   	return;
8974f73fc56SMatthew Dillon   }
8984f73fc56SMatthew Dillon 
8994f73fc56SMatthew Dillon /* Get file name */
9004f73fc56SMatthew Dillon   if (get_file("Write buffer to file:", file) != FINE)
9014f73fc56SMatthew Dillon   	return;
9024f73fc56SMatthew Dillon 
9034f73fc56SMatthew Dillon /* Creat the new file */
9044f73fc56SMatthew Dillon   if ((new_fd = creat(file, 0644)) < 0) {
9054f73fc56SMatthew Dillon   	error("Cannot create ", file);
9064f73fc56SMatthew Dillon   	return;
9074f73fc56SMatthew Dillon   }
9084f73fc56SMatthew Dillon 
9094f73fc56SMatthew Dillon   status_line("Writing ", file);
9104f73fc56SMatthew Dillon 
9114f73fc56SMatthew Dillon /* Copy buffer into file */
9124f73fc56SMatthew Dillon   while ((cnt = read(yank_fd, text_buffer, sizeof(text_buffer))) > 0)
9134f73fc56SMatthew Dillon   	if (write(new_fd, text_buffer, cnt) != cnt) {
9144f73fc56SMatthew Dillon   		bad_write(new_fd);
9154f73fc56SMatthew Dillon   		ret = ERRORS;
9164f73fc56SMatthew Dillon   		break;
9174f73fc56SMatthew Dillon   	}
9184f73fc56SMatthew Dillon 
9194f73fc56SMatthew Dillon /* Clean up open files and status_line */
9208ecf459dSSascha Wildner   close(new_fd);
9218ecf459dSSascha Wildner   close(yank_fd);
9224f73fc56SMatthew Dillon 
9234f73fc56SMatthew Dillon   if (ret != ERRORS)			/* Bad write */
9244f73fc56SMatthew Dillon   	file_status("Wrote", chars_saved, file, lines_saved, TRUE, FALSE);
9254f73fc56SMatthew Dillon }
9264f73fc56SMatthew Dillon 
9274f73fc56SMatthew Dillon /*
9284f73fc56SMatthew Dillon  * MA sets mark_line (mark_text) to the current line (text pointer).
9294f73fc56SMatthew Dillon  */
9308ecf459dSSascha Wildner void
MA(int u __unused)9318ecf459dSSascha Wildner MA(int u __unused)
9324f73fc56SMatthew Dillon {
9334f73fc56SMatthew Dillon   mark_line = cur_line;
9344f73fc56SMatthew Dillon   mark_text = cur_text;
9354f73fc56SMatthew Dillon   status_line("Mark set", NIL_PTR);
9364f73fc56SMatthew Dillon }
9374f73fc56SMatthew Dillon 
9384f73fc56SMatthew Dillon /*
9394f73fc56SMatthew Dillon  * YA() puts the text between the marked position and the current
9404f73fc56SMatthew Dillon  * in the buffer.
9414f73fc56SMatthew Dillon  */
9428ecf459dSSascha Wildner void
YA(int u __unused)9438ecf459dSSascha Wildner YA(int u __unused)
9444f73fc56SMatthew Dillon {
9454f73fc56SMatthew Dillon   set_up(NO_DELETE);
9464f73fc56SMatthew Dillon }
9474f73fc56SMatthew Dillon 
9484f73fc56SMatthew Dillon /*
9494f73fc56SMatthew Dillon  * DT() is essentially the same as YA(), but in DT() the text is deleted.
9504f73fc56SMatthew Dillon  */
9518ecf459dSSascha Wildner void
DT(int u __unused)9528ecf459dSSascha Wildner DT(int u __unused)
9534f73fc56SMatthew Dillon {
9544f73fc56SMatthew Dillon   set_up(DELETE);
9554f73fc56SMatthew Dillon }
9564f73fc56SMatthew Dillon 
9574f73fc56SMatthew Dillon /*
9584f73fc56SMatthew Dillon  * Set_up is an interface to the actual yank. It calls checkmark () to check
9594f73fc56SMatthew Dillon  * if the marked position is still valid. If it is, yank is called with the
9604f73fc56SMatthew Dillon  * arguments in the right order.
9618ecf459dSSascha Wildner  *
9628ecf459dSSascha Wildner  * parameter
9638ecf459dSSascha Wildner  * remove:	DELETE if text should be deleted
9644f73fc56SMatthew Dillon  */
9658ecf459dSSascha Wildner void
set_up(FLAG remove)9668ecf459dSSascha Wildner set_up(FLAG remove)
9674f73fc56SMatthew Dillon {
9684f73fc56SMatthew Dillon   switch (checkmark()) {
9694f73fc56SMatthew Dillon   	case NOT_VALID :
9704f73fc56SMatthew Dillon   		error("Mark not set.", NIL_PTR);
9714f73fc56SMatthew Dillon   		return;
9724f73fc56SMatthew Dillon   	case SMALLER :
9734f73fc56SMatthew Dillon   		yank(mark_line, mark_text, cur_line, cur_text, remove);
9744f73fc56SMatthew Dillon   		break;
9754f73fc56SMatthew Dillon   	case BIGGER :
9764f73fc56SMatthew Dillon   		yank(cur_line, cur_text, mark_line, mark_text, remove);
9774f73fc56SMatthew Dillon   		break;
9784f73fc56SMatthew Dillon   	case SAME :		/* Ignore stupid behaviour */
9794f73fc56SMatthew Dillon   		yank_status = EMPTY;
9804f73fc56SMatthew Dillon   		chars_saved = 0L;
9814f73fc56SMatthew Dillon   		status_line("0 characters saved in buffer.", NIL_PTR);
9824f73fc56SMatthew Dillon   		break;
9834f73fc56SMatthew Dillon   }
9844f73fc56SMatthew Dillon }
9854f73fc56SMatthew Dillon 
9864f73fc56SMatthew Dillon /*
9874f73fc56SMatthew Dillon  * Check_mark() checks if mark_line and mark_text are still valid pointers. If
9884f73fc56SMatthew Dillon  * they are it returns SMALLER if the marked position is before the current,
9894f73fc56SMatthew Dillon  * BIGGER if it isn't or SAME if somebody didn't get the point.
9904f73fc56SMatthew Dillon  * NOT_VALID is returned when mark_line and/or mark_text are no longer valid.
9914f73fc56SMatthew Dillon  * Legal() checks if mark_text is valid on the mark_line.
9924f73fc56SMatthew Dillon  */
9938ecf459dSSascha Wildner FLAG
checkmark(void)9948ecf459dSSascha Wildner checkmark(void)
9954f73fc56SMatthew Dillon {
9968ecf459dSSascha Wildner   LINE *line;
9974f73fc56SMatthew Dillon   FLAG cur_seen = FALSE;
9984f73fc56SMatthew Dillon 
9994f73fc56SMatthew Dillon /* Special case: check is mark_line and cur_line are the same. */
10004f73fc56SMatthew Dillon   if (mark_line == cur_line) {
10014f73fc56SMatthew Dillon   	if (mark_text == cur_text)	/* Even same place */
10024f73fc56SMatthew Dillon   		return SAME;
10034f73fc56SMatthew Dillon   	if (legal() == ERRORS)		/* mark_text out of range */
10044f73fc56SMatthew Dillon   		return NOT_VALID;
10054f73fc56SMatthew Dillon   	return (mark_text < cur_text) ? SMALLER : BIGGER;
10064f73fc56SMatthew Dillon   }
10074f73fc56SMatthew Dillon 
10084f73fc56SMatthew Dillon /* Start looking for mark_line in the line structure */
10094f73fc56SMatthew Dillon   for (line = header->next; line != tail; line = line->next) {
10104f73fc56SMatthew Dillon   	if (line == cur_line)
10114f73fc56SMatthew Dillon   		cur_seen = TRUE;
10124f73fc56SMatthew Dillon   	else if (line == mark_line)
10134f73fc56SMatthew Dillon   		break;
10144f73fc56SMatthew Dillon   }
10154f73fc56SMatthew Dillon 
10164f73fc56SMatthew Dillon /* If we found mark_line (line != tail) check for legality of mark_text */
10174f73fc56SMatthew Dillon   if (line == tail || legal() == ERRORS)
10184f73fc56SMatthew Dillon   	return NOT_VALID;
10194f73fc56SMatthew Dillon 
10204f73fc56SMatthew Dillon /* cur_seen is TRUE if cur_line is before mark_line */
10214f73fc56SMatthew Dillon   return (cur_seen == TRUE) ? BIGGER : SMALLER;
10224f73fc56SMatthew Dillon }
10234f73fc56SMatthew Dillon 
10244f73fc56SMatthew Dillon /*
10254f73fc56SMatthew Dillon  * Legal() checks if mark_text is still a valid pointer.
10264f73fc56SMatthew Dillon  */
10278ecf459dSSascha Wildner int
legal(void)10288ecf459dSSascha Wildner legal(void)
10294f73fc56SMatthew Dillon {
10308ecf459dSSascha Wildner   char *textp = mark_line->text;
10314f73fc56SMatthew Dillon 
10324f73fc56SMatthew Dillon /* Locate mark_text on mark_line */
10334f73fc56SMatthew Dillon   while (textp != mark_text && *textp++ != '\0')
10344f73fc56SMatthew Dillon   	;
10354f73fc56SMatthew Dillon   return (*textp == '\0') ? ERRORS : FINE;
10364f73fc56SMatthew Dillon }
10374f73fc56SMatthew Dillon 
10384f73fc56SMatthew Dillon /*
10394f73fc56SMatthew Dillon  * Yank puts all the text between start_position and end_position into
10404f73fc56SMatthew Dillon  * the buffer.
10414f73fc56SMatthew Dillon  * The caller must check that the arguments to yank() are valid. (E.g. in
10424f73fc56SMatthew Dillon  * the right order)
10438ecf459dSSascha Wildner  *
10448ecf459dSSascha Wildner  * parameter
10458ecf459dSSascha Wildner  * remove:	DELETE if text should be deleted
10464f73fc56SMatthew Dillon  */
10478ecf459dSSascha Wildner void
yank(LINE * start_line,char * start_textp,LINE * end_line,char * end_textp,FLAG remove)10488ecf459dSSascha Wildner yank(LINE *start_line, char *start_textp, LINE *end_line, char *end_textp,
10498ecf459dSSascha Wildner      FLAG remove)
10504f73fc56SMatthew Dillon {
10518ecf459dSSascha Wildner   LINE *line = start_line;
10528ecf459dSSascha Wildner   char *textp = start_textp;
10534f73fc56SMatthew Dillon   int fd;
10544f73fc56SMatthew Dillon 
10554f73fc56SMatthew Dillon /* Creat file to hold buffer */
10564f73fc56SMatthew Dillon   if ((fd = scratch_file(WRITE)) == ERRORS)
10574f73fc56SMatthew Dillon   	return;
10584f73fc56SMatthew Dillon 
10594f73fc56SMatthew Dillon   chars_saved = 0L;
10604f73fc56SMatthew Dillon   lines_saved = 0;
10614f73fc56SMatthew Dillon   status_line("Saving text.", NIL_PTR);
10624f73fc56SMatthew Dillon 
10634f73fc56SMatthew Dillon /* Keep writing chars until the end_location is reached. */
10644f73fc56SMatthew Dillon   while (textp != end_textp) {
10654f73fc56SMatthew Dillon   	if (write_char(fd, *textp) == ERRORS) {
10668ecf459dSSascha Wildner   		close(fd);
10674f73fc56SMatthew Dillon   		return;
10684f73fc56SMatthew Dillon   	}
10694f73fc56SMatthew Dillon   	if (*textp++ == '\n') {	/* Move to the next line */
10704f73fc56SMatthew Dillon   		line = line->next;
10714f73fc56SMatthew Dillon   		textp = line->text;
10724f73fc56SMatthew Dillon   		lines_saved++;
10734f73fc56SMatthew Dillon   	}
10744f73fc56SMatthew Dillon   	chars_saved++;
10754f73fc56SMatthew Dillon   }
10764f73fc56SMatthew Dillon 
10774f73fc56SMatthew Dillon /* Flush the I/O buffer and close file */
10784f73fc56SMatthew Dillon   if (flush_buffer(fd) == ERRORS) {
10798ecf459dSSascha Wildner   	close(fd);
10804f73fc56SMatthew Dillon   	return;
10814f73fc56SMatthew Dillon   }
10828ecf459dSSascha Wildner   close(fd);
10834f73fc56SMatthew Dillon   yank_status = VALID;
10844f73fc56SMatthew Dillon 
10854f73fc56SMatthew Dillon /*
10864f73fc56SMatthew Dillon  * Check if the text should be deleted as well. If it should, the following
10874f73fc56SMatthew Dillon  * hack is used to save a lot of code. First move back to the start_position.
10884f73fc56SMatthew Dillon  * (This might be the location we're on now!) and them delete the text.
10894f73fc56SMatthew Dillon  * It might be a bit confusing the first time somebody uses it.
10904f73fc56SMatthew Dillon  * Delete() will fix the screen.
10914f73fc56SMatthew Dillon  */
10924f73fc56SMatthew Dillon   if (remove == DELETE) {
10934f73fc56SMatthew Dillon   	move_to(find_x(start_line, start_textp), find_y(start_line));
10944f73fc56SMatthew Dillon   	delete(start_line, start_textp, end_line, end_textp);
10954f73fc56SMatthew Dillon   }
10964f73fc56SMatthew Dillon 
10974f73fc56SMatthew Dillon   status_line(num_out(chars_saved), " characters saved in buffer.");
10984f73fc56SMatthew Dillon }
10994f73fc56SMatthew Dillon 
11004f73fc56SMatthew Dillon /*
11014f73fc56SMatthew Dillon  * Scratch_file() creates a uniq file in /usr/tmp. If the file couldn't
11024f73fc56SMatthew Dillon  * be created other combinations of files are tried until a maximum
11034f73fc56SMatthew Dillon  * of MAXTRAILS times. After MAXTRAILS times, an error message is given
11044f73fc56SMatthew Dillon  * and ERRORS is returned.
11054f73fc56SMatthew Dillon  */
11064f73fc56SMatthew Dillon 
11074f73fc56SMatthew Dillon #define MAXTRAILS	26
11084f73fc56SMatthew Dillon 
11098ecf459dSSascha Wildner /*
11108ecf459dSSascha Wildner  * parameter
11118ecf459dSSascha Wildner  * mode:	Can be READ or WRITE permission
11128ecf459dSSascha Wildner  */
11138ecf459dSSascha Wildner int
scratch_file(FLAG mode)11148ecf459dSSascha Wildner scratch_file(FLAG mode)
11154f73fc56SMatthew Dillon {
11164f73fc56SMatthew Dillon   static int trials = 0;		/* Keep track of trails */
11178ecf459dSSascha Wildner   char *y_ptr, *n_ptr;
11188ecf459dSSascha Wildner   int fd = ERRORS;			/* Filedescriptor to buffer */
11194f73fc56SMatthew Dillon 
11204f73fc56SMatthew Dillon /* If yank_status == NOT_VALID, scratch_file is called for the first time */
11214f73fc56SMatthew Dillon   if (yank_status == NOT_VALID && mode == WRITE) { /* Create new file */
11224f73fc56SMatthew Dillon   	/* Generate file name. */
11234f73fc56SMatthew Dillon 	y_ptr = &yank_file[11];
11244f73fc56SMatthew Dillon 	n_ptr = num_out((long) getpid());
11254f73fc56SMatthew Dillon 	while ((*y_ptr = *n_ptr++) != '\0')
11264f73fc56SMatthew Dillon 		y_ptr++;
11274f73fc56SMatthew Dillon 	*y_ptr++ = 'a' + trials;
11284f73fc56SMatthew Dillon 	*y_ptr = '\0';
11294f73fc56SMatthew Dillon   	/* Check file existence */
11304f73fc56SMatthew Dillon   	if (access(yank_file, 0) == 0 || (fd = creat(yank_file, 0644)) < 0) {
11314f73fc56SMatthew Dillon   		if (trials++ >= MAXTRAILS) {
11324f73fc56SMatthew Dillon   			error("Unable to creat scratchfile.", NIL_PTR);
11334f73fc56SMatthew Dillon   			return ERRORS;
11344f73fc56SMatthew Dillon   		}
11354f73fc56SMatthew Dillon   		else
11364f73fc56SMatthew Dillon   			return scratch_file(mode);/* Have another go */
11374f73fc56SMatthew Dillon   	}
11384f73fc56SMatthew Dillon   }
11394f73fc56SMatthew Dillon   else if ((mode == READ && (fd = open(yank_file, 0)) < 0) ||
11404f73fc56SMatthew Dillon 			(mode == WRITE && (fd = creat(yank_file, 0644)) < 0)) {
11414f73fc56SMatthew Dillon   	yank_status = NOT_VALID;
11424f73fc56SMatthew Dillon   	return ERRORS;
11434f73fc56SMatthew Dillon   }
11444f73fc56SMatthew Dillon 
11454f73fc56SMatthew Dillon   clear_buffer();
11464f73fc56SMatthew Dillon   return fd;
11474f73fc56SMatthew Dillon }
11484f73fc56SMatthew Dillon 
11494f73fc56SMatthew Dillon /*  ========================================================================  *
11504f73fc56SMatthew Dillon  *				Search Routines				      *
11514f73fc56SMatthew Dillon  *  ========================================================================  */
11524f73fc56SMatthew Dillon 
11534f73fc56SMatthew Dillon /*
11544f73fc56SMatthew Dillon  * A regular expression consists of a sequence of:
11554f73fc56SMatthew Dillon  * 	1. A normal character matching that character.
11564f73fc56SMatthew Dillon  * 	2. A . matching any character.
11574f73fc56SMatthew Dillon  * 	3. A ^ matching the begin of a line.
11584f73fc56SMatthew Dillon  * 	4. A $ (as last character of the pattern) mathing the end of a line.
11594f73fc56SMatthew Dillon  * 	5. A \<character> matching <character>.
11604f73fc56SMatthew Dillon  * 	6. A number of characters enclosed in [] pairs matching any of these
11614f73fc56SMatthew Dillon  * 	   characters. A list of characters can be indicated by a '-'. So
11624f73fc56SMatthew Dillon  * 	   [a-z] matches any letter of the alphabet. If the first character
11634f73fc56SMatthew Dillon  * 	   after the '[' is a '^' then the set is negated (matching none of
11644f73fc56SMatthew Dillon  * 	   the characters).
11654f73fc56SMatthew Dillon  * 	   A ']', '^' or '-' can be escaped by putting a '\' in front of it.
11664f73fc56SMatthew Dillon  * 	7. If one of the expressions as described in 1-6 is followed by a
11674f73fc56SMatthew Dillon  * 	   '*' than that expressions matches a sequence of 0 or more of
11684f73fc56SMatthew Dillon  * 	   that expression.
11694f73fc56SMatthew Dillon  */
11704f73fc56SMatthew Dillon 
11714f73fc56SMatthew Dillon char typed_expression[LINE_LEN];	/* Holds previous expr. */
11724f73fc56SMatthew Dillon 
11734f73fc56SMatthew Dillon /*
11744f73fc56SMatthew Dillon  * SF searches forward for an expression.
11754f73fc56SMatthew Dillon  */
11768ecf459dSSascha Wildner void
SF(int u __unused)11778ecf459dSSascha Wildner SF(int u __unused)
11784f73fc56SMatthew Dillon {
11794f73fc56SMatthew Dillon   search("Search forward:", FORWARD);
11804f73fc56SMatthew Dillon }
11814f73fc56SMatthew Dillon 
11824f73fc56SMatthew Dillon /*
11834f73fc56SMatthew Dillon  * SF searches backwards for an expression.
11844f73fc56SMatthew Dillon  */
11858ecf459dSSascha Wildner void
SR(int u __unused)11868ecf459dSSascha Wildner SR(int u __unused)
11874f73fc56SMatthew Dillon {
11884f73fc56SMatthew Dillon   search("Search reverse:", REVERSE);
11894f73fc56SMatthew Dillon }
11904f73fc56SMatthew Dillon 
11914f73fc56SMatthew Dillon /*
11924f73fc56SMatthew Dillon  * Get_expression() prompts for an expression. If just a return is typed, the
11934f73fc56SMatthew Dillon  * old expression is used. If the expression changed, compile() is called and
11944f73fc56SMatthew Dillon  * the returning REGEX structure is returned. It returns NIL_REG upon error.
11954f73fc56SMatthew Dillon  * The save flag indicates whether the expression should be appended at the
11964f73fc56SMatthew Dillon  * message pointer.
11974f73fc56SMatthew Dillon  */
11988ecf459dSSascha Wildner REGEX *
get_expression(const char * message)11998ecf459dSSascha Wildner get_expression(const char *message)
12004f73fc56SMatthew Dillon {
12014f73fc56SMatthew Dillon   static REGEX program;			/* Program of expression */
12024f73fc56SMatthew Dillon   char exp_buf[LINE_LEN];			/* Buffer for new expr. */
12034f73fc56SMatthew Dillon 
12044f73fc56SMatthew Dillon   if (get_string(message, exp_buf, FALSE) == ERRORS)
12054f73fc56SMatthew Dillon   	return NIL_REG;
12064f73fc56SMatthew Dillon 
12074f73fc56SMatthew Dillon   if (exp_buf[0] == '\0' && typed_expression[0] == '\0') {
12084f73fc56SMatthew Dillon   	error("No previous expression.", NIL_PTR);
12094f73fc56SMatthew Dillon   	return NIL_REG;
12104f73fc56SMatthew Dillon   }
12114f73fc56SMatthew Dillon 
12124f73fc56SMatthew Dillon   if (exp_buf[0] != '\0') {		/* A new expr. is typed */
12134f73fc56SMatthew Dillon   	copy_string(typed_expression, exp_buf);/* Save expr. */
12144f73fc56SMatthew Dillon   	compile(exp_buf, &program);	/* Compile new expression */
12154f73fc56SMatthew Dillon   }
12164f73fc56SMatthew Dillon 
12174f73fc56SMatthew Dillon   if (program.status == REG_ERROR) {	/* Error during compiling */
12184f73fc56SMatthew Dillon   	error(program.result.err_mess, NIL_PTR);
12194f73fc56SMatthew Dillon   	return NIL_REG;
12204f73fc56SMatthew Dillon   }
12214f73fc56SMatthew Dillon   return &program;
12224f73fc56SMatthew Dillon }
12234f73fc56SMatthew Dillon 
12244f73fc56SMatthew Dillon /*
12254f73fc56SMatthew Dillon  * GR() a replaces all matches from the current position until the end
12264f73fc56SMatthew Dillon  * of the file.
12274f73fc56SMatthew Dillon  */
12288ecf459dSSascha Wildner void
GR(int u __unused)12298ecf459dSSascha Wildner GR(int u __unused)
12304f73fc56SMatthew Dillon {
12314f73fc56SMatthew Dillon   change("Global replace:", VALID);
12324f73fc56SMatthew Dillon }
12334f73fc56SMatthew Dillon 
12344f73fc56SMatthew Dillon /*
12354f73fc56SMatthew Dillon  * LR() replaces all matches on the current line.
12364f73fc56SMatthew Dillon  */
12378ecf459dSSascha Wildner void
LR(int u __unused)12388ecf459dSSascha Wildner LR(int u __unused)
12394f73fc56SMatthew Dillon {
12404f73fc56SMatthew Dillon   change("Line replace:", NOT_VALID);
12414f73fc56SMatthew Dillon }
12424f73fc56SMatthew Dillon 
12434f73fc56SMatthew Dillon /*
12444f73fc56SMatthew Dillon  * Change() prompts for an expression and a substitution pattern and changes
12454f73fc56SMatthew Dillon  * all matches of the expression into the substitution. change() start looking
12464f73fc56SMatthew Dillon  * for expressions at the current line and continues until the end of the file
12474f73fc56SMatthew Dillon  * if the FLAG file is VALID.
12488ecf459dSSascha Wildner  *
12498ecf459dSSascha Wildner  * parameter
12508ecf459dSSascha Wildner  * message:	Message to prompt for expression
12514f73fc56SMatthew Dillon  */
12528ecf459dSSascha Wildner void
change(const char * message,FLAG file)12538ecf459dSSascha Wildner change(const char *message, FLAG file)
12544f73fc56SMatthew Dillon {
12554f73fc56SMatthew Dillon   char mess_buf[LINE_LEN];	/* Buffer to hold message */
12564f73fc56SMatthew Dillon   char replacement[LINE_LEN];	/* Buffer to hold subst. pattern */
12574f73fc56SMatthew Dillon   REGEX *program;			/* Program resulting from compilation */
12588ecf459dSSascha Wildner   LINE *line = cur_line;
12598ecf459dSSascha Wildner   char *textp;
12604f73fc56SMatthew Dillon   long lines = 0L;		/* Nr of lines on which subs occurred */
12614f73fc56SMatthew Dillon   long subs = 0L;			/* Nr of subs made */
12624f73fc56SMatthew Dillon   int page = y;			/* Index to check if line is on screen*/
12634f73fc56SMatthew Dillon 
12644f73fc56SMatthew Dillon /* Save message and get expression */
12654f73fc56SMatthew Dillon   copy_string(mess_buf, message);
12664f73fc56SMatthew Dillon   if ((program = get_expression(mess_buf)) == NIL_REG)
12674f73fc56SMatthew Dillon   	return;
12684f73fc56SMatthew Dillon 
12694f73fc56SMatthew Dillon /* Get substitution pattern */
12704f73fc56SMatthew Dillon   build_string(mess_buf, "%s %s by:", mess_buf, typed_expression);
12714f73fc56SMatthew Dillon   if (get_string(mess_buf, replacement, FALSE) == ERRORS)
12724f73fc56SMatthew Dillon   	return;
12734f73fc56SMatthew Dillon 
12744f73fc56SMatthew Dillon   set_cursor(0, ymax);
12754f73fc56SMatthew Dillon   flush();
12764f73fc56SMatthew Dillon /* Substitute until end of file */
12774f73fc56SMatthew Dillon   do {
12784f73fc56SMatthew Dillon   	if (line_check(program, line->text, FORWARD)) {
12794f73fc56SMatthew Dillon   		lines++;
12804f73fc56SMatthew Dillon   		/* Repeat sub. on this line as long as we find a match*/
12814f73fc56SMatthew Dillon   		do {
12824f73fc56SMatthew Dillon   			subs++;	/* Increment subs */
12834f73fc56SMatthew Dillon   			if ((textp = substitute(line, program,replacement))
12844f73fc56SMatthew Dillon 								     == NIL_PTR)
12854f73fc56SMatthew Dillon   				return;	/* Line too long */
12864f73fc56SMatthew Dillon   		} while ((program->status & BEGIN_LINE) != BEGIN_LINE &&
12874f73fc56SMatthew Dillon 			 (program->status & END_LINE) != END_LINE &&
12884f73fc56SMatthew Dillon 					  line_check(program, textp, FORWARD));
12894f73fc56SMatthew Dillon   		/* Check to see if we can print the result */
12904f73fc56SMatthew Dillon   		if (page <= screenmax) {
12914f73fc56SMatthew Dillon   			set_cursor(0, page);
12924f73fc56SMatthew Dillon   			line_print(line);
12934f73fc56SMatthew Dillon   		}
12944f73fc56SMatthew Dillon   	}
12954f73fc56SMatthew Dillon   	if (page <= screenmax)
12964f73fc56SMatthew Dillon   		page++;
12974f73fc56SMatthew Dillon   	line = line->next;
12984f73fc56SMatthew Dillon   } while (line != tail && file == VALID && quit == FALSE);
12994f73fc56SMatthew Dillon 
13004f73fc56SMatthew Dillon   copy_string(mess_buf, (quit == TRUE) ? "(Aborted) " : "");
13014f73fc56SMatthew Dillon /* Fix the status line */
13024f73fc56SMatthew Dillon   if (subs == 0L && quit == FALSE)
13034f73fc56SMatthew Dillon   	error("Pattern not found.", NIL_PTR);
13044f73fc56SMatthew Dillon   else if (lines >= REPORT || quit == TRUE) {
13054f73fc56SMatthew Dillon   	build_string(mess_buf, "%s %D substitutions on %D lines.", mess_buf,
13064f73fc56SMatthew Dillon 								   subs, lines);
13074f73fc56SMatthew Dillon   	status_line(mess_buf, NIL_PTR);
13084f73fc56SMatthew Dillon   }
13094f73fc56SMatthew Dillon   else if (file == NOT_VALID && subs >= REPORT)
13104f73fc56SMatthew Dillon   	status_line(num_out(subs), " substitutions.");
13114f73fc56SMatthew Dillon   else
13124f73fc56SMatthew Dillon   	clear_status();
13134f73fc56SMatthew Dillon   move_to (x, y);
13144f73fc56SMatthew Dillon }
13154f73fc56SMatthew Dillon 
13164f73fc56SMatthew Dillon /*
13174f73fc56SMatthew Dillon  * Substitute() replaces the match on this line by the substitute pattern
13184f73fc56SMatthew Dillon  * as indicated by the program. Every '&' in the replacement is replaced by
13194f73fc56SMatthew Dillon  * the original match. A \ in the replacement escapes the next character.
13208ecf459dSSascha Wildner  *
13218ecf459dSSascha Wildner  * parameter
13228ecf459dSSascha Wildner  * replacement:	Contains replacement pattern
13234f73fc56SMatthew Dillon  */
13248ecf459dSSascha Wildner char *
substitute(LINE * line,REGEX * program,char * replacement)13258ecf459dSSascha Wildner substitute(LINE *line, REGEX *program, char *replacement)
13264f73fc56SMatthew Dillon {
13278ecf459dSSascha Wildner   char *textp = text_buffer;
13288ecf459dSSascha Wildner   char *subp = replacement;
13294f73fc56SMatthew Dillon   char *linep = line->text;
13304f73fc56SMatthew Dillon   char *amp;
13314f73fc56SMatthew Dillon 
13324f73fc56SMatthew Dillon   modified = TRUE;
13334f73fc56SMatthew Dillon 
13344f73fc56SMatthew Dillon /* Copy part of line until the beginning of the match */
13354f73fc56SMatthew Dillon   while (linep != program->start_ptr)
13364f73fc56SMatthew Dillon   	*textp++ = *linep++;
13374f73fc56SMatthew Dillon 
13384f73fc56SMatthew Dillon /*
13394f73fc56SMatthew Dillon  * Replace the match by the substitution pattern. Each occurrence of '&' is
13404f73fc56SMatthew Dillon  * replaced by the original match. A \ escapes the next character.
13414f73fc56SMatthew Dillon  */
13424f73fc56SMatthew Dillon   while (*subp != '\0' && textp < &text_buffer[MAX_CHARS]) {
13434f73fc56SMatthew Dillon   	if (*subp == '&') {		/* Replace the original match */
13444f73fc56SMatthew Dillon   		amp = program->start_ptr;
13454f73fc56SMatthew Dillon   		while (amp < program->end_ptr && textp<&text_buffer[MAX_CHARS])
13464f73fc56SMatthew Dillon   			*textp++ = *amp++;
13474f73fc56SMatthew Dillon   		subp++;
13484f73fc56SMatthew Dillon   	}
13494f73fc56SMatthew Dillon   	else {
13504f73fc56SMatthew Dillon   		if (*subp == '\\' && *(subp + 1) != '\0')
13514f73fc56SMatthew Dillon   			subp++;
13524f73fc56SMatthew Dillon   		*textp++ = *subp++;
13534f73fc56SMatthew Dillon   	}
13544f73fc56SMatthew Dillon   }
13554f73fc56SMatthew Dillon 
13564f73fc56SMatthew Dillon /* Check for line length not exceeding MAX_CHARS */
13574f73fc56SMatthew Dillon   if (length_of(text_buffer) + length_of(program->end_ptr) >= MAX_CHARS) {
13584f73fc56SMatthew Dillon   	error("Substitution result: line too big", NIL_PTR);
13594f73fc56SMatthew Dillon   	return NIL_PTR;
13604f73fc56SMatthew Dillon   }
13614f73fc56SMatthew Dillon 
13624f73fc56SMatthew Dillon /* Append last part of line to the new build line */
13634f73fc56SMatthew Dillon   copy_string(textp, program->end_ptr);
13644f73fc56SMatthew Dillon 
13654f73fc56SMatthew Dillon /* Free old line and install new one */
13664f73fc56SMatthew Dillon   free_space(line->text);
13674f73fc56SMatthew Dillon   line->text = alloc(length_of(text_buffer) + 1);
13684f73fc56SMatthew Dillon   copy_string(line->text, text_buffer);
13694f73fc56SMatthew Dillon 
13704f73fc56SMatthew Dillon   return(line->text + (textp - text_buffer));
13714f73fc56SMatthew Dillon }
13724f73fc56SMatthew Dillon 
13734f73fc56SMatthew Dillon /*
13744f73fc56SMatthew Dillon  * Search() calls get_expression to fetch the expression. If this went well,
13754f73fc56SMatthew Dillon  * the function match() is called which returns the line with the next match.
13764f73fc56SMatthew Dillon  * If this line is the NIL_LINE, it means that a match could not be found.
13774f73fc56SMatthew Dillon  * Find_x() and find_y() display the right page on the screen, and return
13784f73fc56SMatthew Dillon  * the right coordinates for x and y. These coordinates are passed to move_to()
13794f73fc56SMatthew Dillon  */
13808ecf459dSSascha Wildner void
search(const char * message,FLAG method)13818ecf459dSSascha Wildner search(const char *message, FLAG method)
13824f73fc56SMatthew Dillon {
13838ecf459dSSascha Wildner   REGEX *program;
13848ecf459dSSascha Wildner   LINE *match_line;
13854f73fc56SMatthew Dillon 
13864f73fc56SMatthew Dillon /* Get the expression */
13874f73fc56SMatthew Dillon   if ((program = get_expression(message)) == NIL_REG)
13884f73fc56SMatthew Dillon   	return;
13894f73fc56SMatthew Dillon 
13904f73fc56SMatthew Dillon   set_cursor(0, ymax);
13914f73fc56SMatthew Dillon   flush();
13924f73fc56SMatthew Dillon /* Find the match */
13934f73fc56SMatthew Dillon   if ((match_line = match(program, cur_text, method)) == NIL_LINE) {
13944f73fc56SMatthew Dillon   	if (quit == TRUE)
13954f73fc56SMatthew Dillon   		status_line("Aborted", NIL_PTR);
13964f73fc56SMatthew Dillon   	else
13974f73fc56SMatthew Dillon   		status_line("Pattern not found.", NIL_PTR);
13984f73fc56SMatthew Dillon   	return;
13994f73fc56SMatthew Dillon   }
14004f73fc56SMatthew Dillon 
14014f73fc56SMatthew Dillon   move(0, program->start_ptr, find_y(match_line));
14024f73fc56SMatthew Dillon   clear_status();
14034f73fc56SMatthew Dillon }
14044f73fc56SMatthew Dillon 
14054f73fc56SMatthew Dillon /*
14064f73fc56SMatthew Dillon  * find_y() checks if the matched line is on the current page.  If it is, it
14074f73fc56SMatthew Dillon  * returns the new y coordinate, else it displays the correct page with the
14084f73fc56SMatthew Dillon  * matched line in the middle and returns the new y value;
14094f73fc56SMatthew Dillon  */
14108ecf459dSSascha Wildner int
find_y(LINE * match_line)14118ecf459dSSascha Wildner find_y(LINE *match_line)
14124f73fc56SMatthew Dillon {
14138ecf459dSSascha Wildner   LINE *line;
14148ecf459dSSascha Wildner   int count = 0;
14154f73fc56SMatthew Dillon 
14164f73fc56SMatthew Dillon /* Check if match_line is on the same page as currently displayed. */
14174f73fc56SMatthew Dillon   for (line = top_line; line != match_line && line != bot_line->next;
14184f73fc56SMatthew Dillon   						      line = line->next)
14194f73fc56SMatthew Dillon   	count++;
14204f73fc56SMatthew Dillon   if (line != bot_line->next)
14214f73fc56SMatthew Dillon   	return count;
14224f73fc56SMatthew Dillon 
14234f73fc56SMatthew Dillon /* Display new page, with match_line in center. */
14244f73fc56SMatthew Dillon   if ((line = proceed(match_line, -(screenmax >> 1))) == header) {
14254f73fc56SMatthew Dillon   /* Can't display in the middle. Make first line of file top_line */
14264f73fc56SMatthew Dillon   	count = 0;
14274f73fc56SMatthew Dillon   	for (line = header->next; line != match_line; line = line->next)
14284f73fc56SMatthew Dillon   		count++;
14294f73fc56SMatthew Dillon   	line = header->next;
14304f73fc56SMatthew Dillon   }
14314f73fc56SMatthew Dillon   else	/* New page is displayed. Set cursor to middle of page */
14324f73fc56SMatthew Dillon   	count = screenmax >> 1;
14334f73fc56SMatthew Dillon 
14344f73fc56SMatthew Dillon /* Reset pointers and redraw the screen */
14354f73fc56SMatthew Dillon   reset(line, 0);
14368ecf459dSSascha Wildner   RD(0);
14374f73fc56SMatthew Dillon 
14384f73fc56SMatthew Dillon   return count;
14394f73fc56SMatthew Dillon }
14404f73fc56SMatthew Dillon 
14414f73fc56SMatthew Dillon /* Opcodes for characters */
14424f73fc56SMatthew Dillon #define	NORMAL		0x0200
14434f73fc56SMatthew Dillon #define DOT		0x0400
14444f73fc56SMatthew Dillon #define EOLN		0x0800
14454f73fc56SMatthew Dillon #define STAR		0x1000
14464f73fc56SMatthew Dillon #define BRACKET		0x2000
14474f73fc56SMatthew Dillon #define NEGATE		0x0100
14484f73fc56SMatthew Dillon #define DONE		0x4000
14494f73fc56SMatthew Dillon 
14504f73fc56SMatthew Dillon /* Mask for opcodes and characters */
14514f73fc56SMatthew Dillon #define LOW_BYTE	0x00FF
14524f73fc56SMatthew Dillon #define HIGH_BYTE	0xFF00
14534f73fc56SMatthew Dillon 
14544f73fc56SMatthew Dillon /* Previous is the contents of the previous address (ptr) points to */
14554f73fc56SMatthew Dillon #define previous(ptr)		(*((ptr) - 1))
14564f73fc56SMatthew Dillon 
14574f73fc56SMatthew Dillon /* Buffer to store outcome of compilation */
14584f73fc56SMatthew Dillon int exp_buffer[BLOCK_SIZE];
14594f73fc56SMatthew Dillon 
14604f73fc56SMatthew Dillon /* Errors often used */
14618ecf459dSSascha Wildner static const char *too_long = "Regular expression too long";
14624f73fc56SMatthew Dillon 
14634f73fc56SMatthew Dillon /*
14644f73fc56SMatthew Dillon  * Reg_error() is called by compile() is something went wrong. It set the
14654f73fc56SMatthew Dillon  * status of the structure to error, and assigns the error field of the union.
14664f73fc56SMatthew Dillon  */
14674f73fc56SMatthew Dillon #define reg_error(str)	program->status = REG_ERROR, \
14684f73fc56SMatthew Dillon   					program->result.err_mess = (str)
14694f73fc56SMatthew Dillon /*
14704f73fc56SMatthew Dillon  * Finished() is called when everything went right during compilation. It
14714f73fc56SMatthew Dillon  * allocates space for the expression, and copies the expression buffer into
14724f73fc56SMatthew Dillon  * this field.
14734f73fc56SMatthew Dillon  */
14748ecf459dSSascha Wildner void
finished(REGEX * program,int * last_exp)14758ecf459dSSascha Wildner finished(REGEX *program, int *last_exp)
14764f73fc56SMatthew Dillon {
14778ecf459dSSascha Wildner   int length = (last_exp - exp_buffer) * sizeof(int);
14784f73fc56SMatthew Dillon 
14794f73fc56SMatthew Dillon /* Allocate space */
14804f73fc56SMatthew Dillon   program->result.expression = (int *) alloc(length);
14814f73fc56SMatthew Dillon /* Copy expression. (expression consists of ints!) */
14824f73fc56SMatthew Dillon   bcopy(exp_buffer, program->result.expression, length);
14834f73fc56SMatthew Dillon }
14844f73fc56SMatthew Dillon 
14854f73fc56SMatthew Dillon /*
14864f73fc56SMatthew Dillon  * Compile compiles the pattern into a more comprehensible form and returns a
14874f73fc56SMatthew Dillon  * REGEX structure. If something went wrong, the status field of the structure
14884f73fc56SMatthew Dillon  * is set to REG_ERROR and an error message is set into the err_mess field of
14894f73fc56SMatthew Dillon  * the union. If all went well the expression is saved and the expression
14904f73fc56SMatthew Dillon  * pointer is set to the saved (and compiled) expression.
14918ecf459dSSascha Wildner  *
14928ecf459dSSascha Wildner  * parameter
14938ecf459dSSascha Wildner  * pattern:	Pointer to pattern
14944f73fc56SMatthew Dillon  */
14958ecf459dSSascha Wildner void
compile(char * pattern,REGEX * program)14968ecf459dSSascha Wildner compile(char *pattern, REGEX *program)
14974f73fc56SMatthew Dillon {
14988ecf459dSSascha Wildner   int *expression = exp_buffer;
14994f73fc56SMatthew Dillon   int *prev_char;			/* Pointer to previous compiled atom */
15008ecf459dSSascha Wildner   int *acct_field = NULL;		/* Pointer to last BRACKET start */
15014f73fc56SMatthew Dillon   FLAG negate;			/* Negate flag for BRACKET */
15024f73fc56SMatthew Dillon   char low_char;			/* Index for chars in BRACKET */
15034f73fc56SMatthew Dillon   char c;
15044f73fc56SMatthew Dillon 
15054f73fc56SMatthew Dillon /* Check for begin of line */
15064f73fc56SMatthew Dillon   if (*pattern == '^') {
15074f73fc56SMatthew Dillon   	program->status = BEGIN_LINE;
15084f73fc56SMatthew Dillon   	pattern++;
15094f73fc56SMatthew Dillon   }
15104f73fc56SMatthew Dillon   else {
15114f73fc56SMatthew Dillon   	program->status = 0;
15124f73fc56SMatthew Dillon /* If the first character is a '*' we have to assign it here. */
15134f73fc56SMatthew Dillon   	if (*pattern == '*') {
15144f73fc56SMatthew Dillon   		*expression++ = '*' + NORMAL;
15154f73fc56SMatthew Dillon   		pattern++;
15164f73fc56SMatthew Dillon   	}
15174f73fc56SMatthew Dillon   }
15184f73fc56SMatthew Dillon 
15194f73fc56SMatthew Dillon   for (; ;) {
15204f73fc56SMatthew Dillon   	switch (c = *pattern++) {
15214f73fc56SMatthew Dillon   	case '.' :
15224f73fc56SMatthew Dillon   		*expression++ = DOT;
15234f73fc56SMatthew Dillon   		break;
15244f73fc56SMatthew Dillon   	case '$' :
15254f73fc56SMatthew Dillon   		/*
15264f73fc56SMatthew Dillon   		 * Only means EOLN if it is the last char of the pattern
15274f73fc56SMatthew Dillon   		 */
15284f73fc56SMatthew Dillon   		if (*pattern == '\0') {
15294f73fc56SMatthew Dillon   			*expression++ = EOLN | DONE;
15304f73fc56SMatthew Dillon   			program->status |= END_LINE;
15314f73fc56SMatthew Dillon   			finished(program, expression);
15324f73fc56SMatthew Dillon   			return;
15334f73fc56SMatthew Dillon   		}
15344f73fc56SMatthew Dillon   		else
15354f73fc56SMatthew Dillon   			*expression++ = NORMAL + '$';
15364f73fc56SMatthew Dillon   		break;
15374f73fc56SMatthew Dillon   	case '\0' :
15384f73fc56SMatthew Dillon   		*expression++ = DONE;
15394f73fc56SMatthew Dillon   		finished(program, expression);
15404f73fc56SMatthew Dillon   		return;
15414f73fc56SMatthew Dillon   	case '\\' :
15424f73fc56SMatthew Dillon   		/* If last char, it must! mean a normal '\' */
15434f73fc56SMatthew Dillon   		if (*pattern == '\0')
15444f73fc56SMatthew Dillon   			*expression++ = NORMAL + '\\';
15454f73fc56SMatthew Dillon   		else
15464f73fc56SMatthew Dillon   			*expression++ = NORMAL + *pattern++;
15474f73fc56SMatthew Dillon   		break;
15484f73fc56SMatthew Dillon   	case '*' :
15494f73fc56SMatthew Dillon   		/*
15504f73fc56SMatthew Dillon   		 * If the previous expression was a [] find out the
15514f73fc56SMatthew Dillon   		 * begin of the list, and adjust the opcode.
15524f73fc56SMatthew Dillon   		 */
15534f73fc56SMatthew Dillon   		prev_char = expression - 1;
15544f73fc56SMatthew Dillon   		if (*prev_char & BRACKET)
15554f73fc56SMatthew Dillon   			*(expression - (*acct_field & LOW_BYTE))|= STAR;
15564f73fc56SMatthew Dillon   		else
15574f73fc56SMatthew Dillon   			*prev_char |= STAR;
15584f73fc56SMatthew Dillon   		break;
15594f73fc56SMatthew Dillon   	case '[' :
15604f73fc56SMatthew Dillon   		/*
15614f73fc56SMatthew Dillon   		 * First field in expression gives information about
15624f73fc56SMatthew Dillon   		 * the list.
15634f73fc56SMatthew Dillon   		 * The opcode consists of BRACKET and if necessary
15644f73fc56SMatthew Dillon   		 * NEGATE to indicate that the list should be negated
15654f73fc56SMatthew Dillon   		 * and/or STAR to indicate a number of sequence of this
15664f73fc56SMatthew Dillon   		 * list.
15674f73fc56SMatthew Dillon   		 * The lower byte contains the length of the list.
15684f73fc56SMatthew Dillon   		 */
15694f73fc56SMatthew Dillon   		acct_field = expression++;
15704f73fc56SMatthew Dillon   		if (*pattern == '^') {	/* List must be negated */
15714f73fc56SMatthew Dillon   			pattern++;
15724f73fc56SMatthew Dillon   			negate = TRUE;
15734f73fc56SMatthew Dillon   		}
15744f73fc56SMatthew Dillon   		else
15754f73fc56SMatthew Dillon   			negate = FALSE;
15764f73fc56SMatthew Dillon   		while (*pattern != ']') {
15774f73fc56SMatthew Dillon   			if (*pattern == '\0') {
15784f73fc56SMatthew Dillon   				reg_error("Missing ]");
15794f73fc56SMatthew Dillon   				return;
15804f73fc56SMatthew Dillon   			}
15814f73fc56SMatthew Dillon   			if (*pattern == '\\')
15824f73fc56SMatthew Dillon   				pattern++;
15834f73fc56SMatthew Dillon   			*expression++ = *pattern++;
15844f73fc56SMatthew Dillon   			if (*pattern == '-') {
15854f73fc56SMatthew Dillon   						/* Make list of chars */
15864f73fc56SMatthew Dillon   				low_char = previous(pattern);
15874f73fc56SMatthew Dillon   				pattern++;	/* Skip '-' */
15884f73fc56SMatthew Dillon   				if (low_char++ > *pattern) {
15894f73fc56SMatthew Dillon   					reg_error("Bad range in [a-z]");
15904f73fc56SMatthew Dillon   					return;
15914f73fc56SMatthew Dillon   				}
15924f73fc56SMatthew Dillon   				/* Build list */
15934f73fc56SMatthew Dillon   				while (low_char <= *pattern)
15944f73fc56SMatthew Dillon   					*expression++ = low_char++;
15954f73fc56SMatthew Dillon   				pattern++;
15964f73fc56SMatthew Dillon   			}
15974f73fc56SMatthew Dillon   			if (expression >= &exp_buffer[BLOCK_SIZE]) {
15984f73fc56SMatthew Dillon   				reg_error(too_long);
15994f73fc56SMatthew Dillon   				return;
16004f73fc56SMatthew Dillon   			}
16014f73fc56SMatthew Dillon   		}
16024f73fc56SMatthew Dillon   		pattern++;			/* Skip ']' */
16034f73fc56SMatthew Dillon   		/* Assign length of list in acct field */
16044f73fc56SMatthew Dillon   		if ((*acct_field = (expression - acct_field)) == 1) {
16054f73fc56SMatthew Dillon   			reg_error("Empty []");
16064f73fc56SMatthew Dillon   			return;
16074f73fc56SMatthew Dillon   		}
16084f73fc56SMatthew Dillon   		/* Assign negate and bracket field */
16094f73fc56SMatthew Dillon   		*acct_field |= BRACKET;
16104f73fc56SMatthew Dillon   		if (negate == TRUE)
16114f73fc56SMatthew Dillon   			*acct_field |= NEGATE;
16124f73fc56SMatthew Dillon   		/*
16134f73fc56SMatthew Dillon   		 * Add BRACKET to opcode of last char in field because
16144f73fc56SMatthew Dillon   		 * a '*' may be following the list.
16154f73fc56SMatthew Dillon   		 */
16164f73fc56SMatthew Dillon   		previous(expression) |= BRACKET;
16174f73fc56SMatthew Dillon   		break;
16184f73fc56SMatthew Dillon   	default :
16194f73fc56SMatthew Dillon   		*expression++ = c + NORMAL;
16204f73fc56SMatthew Dillon   	}
16214f73fc56SMatthew Dillon   	if (expression == &exp_buffer[BLOCK_SIZE]) {
16224f73fc56SMatthew Dillon   		reg_error(too_long);
16234f73fc56SMatthew Dillon   		return;
16244f73fc56SMatthew Dillon   	}
16254f73fc56SMatthew Dillon   }
16264f73fc56SMatthew Dillon   /* NOTREACHED */
16274f73fc56SMatthew Dillon }
16284f73fc56SMatthew Dillon 
16294f73fc56SMatthew Dillon /*
16304f73fc56SMatthew Dillon  * Match gets as argument the program, pointer to place in current line to
16314f73fc56SMatthew Dillon  * start from and the method to search for (either FORWARD or REVERSE).
16324f73fc56SMatthew Dillon  * Match() will look through the whole file until a match is found.
16334f73fc56SMatthew Dillon  * NIL_LINE is returned if no match could be found.
16344f73fc56SMatthew Dillon  */
16358ecf459dSSascha Wildner LINE *
match(REGEX * program,char * string,FLAG method)16368ecf459dSSascha Wildner match(REGEX *program, char *string, FLAG method)
16374f73fc56SMatthew Dillon {
16388ecf459dSSascha Wildner   LINE *line = cur_line;
16394f73fc56SMatthew Dillon   char old_char;				/* For saving chars */
16404f73fc56SMatthew Dillon 
16414f73fc56SMatthew Dillon /* Corrupted program */
16424f73fc56SMatthew Dillon   if (program->status == REG_ERROR)
16434f73fc56SMatthew Dillon   	return NIL_LINE;
16444f73fc56SMatthew Dillon 
16454f73fc56SMatthew Dillon /* Check part of text first */
16464f73fc56SMatthew Dillon   if (!(program->status & BEGIN_LINE)) {
16474f73fc56SMatthew Dillon   	if (method == FORWARD) {
16484f73fc56SMatthew Dillon   		if (line_check(program, string + 1, method) == MATCH)
16494f73fc56SMatthew Dillon   			return cur_line;	/* Match found */
16504f73fc56SMatthew Dillon   	}
16514f73fc56SMatthew Dillon   	else if (!(program->status & END_LINE)) {
16524f73fc56SMatthew Dillon   		old_char = *string;	/* Save char and */
16534f73fc56SMatthew Dillon   		*string = '\n';		/* Assign '\n' for line_check */
16544f73fc56SMatthew Dillon   		if (line_check(program, line->text, method) == MATCH) {
16554f73fc56SMatthew Dillon   			*string = old_char; /* Restore char */
16564f73fc56SMatthew Dillon   			return cur_line;    /* Found match */
16574f73fc56SMatthew Dillon   		}
16584f73fc56SMatthew Dillon   		*string = old_char;	/* No match, but restore char */
16594f73fc56SMatthew Dillon   	}
16604f73fc56SMatthew Dillon   }
16614f73fc56SMatthew Dillon 
16624f73fc56SMatthew Dillon /* No match in last (or first) part of line. Check out rest of file */
16634f73fc56SMatthew Dillon   do {
16644f73fc56SMatthew Dillon   	line = (method == FORWARD) ? line->next : line->prev;
16654f73fc56SMatthew Dillon   	if (line->text == NIL_PTR)	/* Header/tail */
16664f73fc56SMatthew Dillon   		continue;
16674f73fc56SMatthew Dillon   	if (line_check(program, line->text, method) == MATCH)
16684f73fc56SMatthew Dillon   		return line;
16694f73fc56SMatthew Dillon   } while (line != cur_line && quit == FALSE);
16704f73fc56SMatthew Dillon 
16714f73fc56SMatthew Dillon /* No match found. */
16724f73fc56SMatthew Dillon   return NIL_LINE;
16734f73fc56SMatthew Dillon }
16744f73fc56SMatthew Dillon 
16754f73fc56SMatthew Dillon /*
16764f73fc56SMatthew Dillon  * Line_check() checks the line (or rather string) for a match. Method
16774f73fc56SMatthew Dillon  * indicates FORWARD or REVERSE search. It scans through the whole string
16784f73fc56SMatthew Dillon  * until a match is found, or the end of the string is reached.
16794f73fc56SMatthew Dillon  */
16808ecf459dSSascha Wildner int
line_check(REGEX * program,char * string,FLAG method)16818ecf459dSSascha Wildner line_check(REGEX *program, char *string, FLAG method)
16824f73fc56SMatthew Dillon {
16838ecf459dSSascha Wildner   char *textp = string;
16844f73fc56SMatthew Dillon 
16854f73fc56SMatthew Dillon /* Assign start_ptr field. We might find a match right away! */
16864f73fc56SMatthew Dillon   program->start_ptr = textp;
16874f73fc56SMatthew Dillon 
16884f73fc56SMatthew Dillon /* If the match must be anchored, just check the string. */
16894f73fc56SMatthew Dillon   if (program->status & BEGIN_LINE)
16904f73fc56SMatthew Dillon   	return check_string(program, string, NIL_INT);
16914f73fc56SMatthew Dillon 
16924f73fc56SMatthew Dillon   if (method == REVERSE) {
16934f73fc56SMatthew Dillon   	/* First move to the end of the string */
16944f73fc56SMatthew Dillon   	for (textp = string; *textp != '\n'; textp++)
16954f73fc56SMatthew Dillon   		;
16964f73fc56SMatthew Dillon   	/* Start checking string until the begin of the string is met */
16974f73fc56SMatthew Dillon   	while (textp >= string) {
16984f73fc56SMatthew Dillon   		program->start_ptr = textp;
16994f73fc56SMatthew Dillon   		if (check_string(program, textp--, NIL_INT))
17004f73fc56SMatthew Dillon   			return MATCH;
17014f73fc56SMatthew Dillon   	}
17024f73fc56SMatthew Dillon   }
17034f73fc56SMatthew Dillon   else {
17044f73fc56SMatthew Dillon   	/* Move through the string until the end of is found */
17054f73fc56SMatthew Dillon 	while (quit == FALSE && *textp != '\0') {
17064f73fc56SMatthew Dillon   		program->start_ptr = textp;
17074f73fc56SMatthew Dillon   		if (check_string(program, textp, NIL_INT))
17084f73fc56SMatthew Dillon   			return MATCH;
17094f73fc56SMatthew Dillon 		if (*textp == '\n')
17104f73fc56SMatthew Dillon 			break;
17114f73fc56SMatthew Dillon 		textp++;
17124f73fc56SMatthew Dillon   	}
17134f73fc56SMatthew Dillon   }
17144f73fc56SMatthew Dillon 
17154f73fc56SMatthew Dillon   return NO_MATCH;
17164f73fc56SMatthew Dillon }
17174f73fc56SMatthew Dillon 
17184f73fc56SMatthew Dillon /*
17194f73fc56SMatthew Dillon  * Check() checks of a match can be found in the given string. Whenever a STAR
17204f73fc56SMatthew Dillon  * is found during matching, then the begin position of the string is marked
17214f73fc56SMatthew Dillon  * and the maximum number of matches is performed. Then the function star()
17224f73fc56SMatthew Dillon  * is called which starts to finish the match from this position of the string
17234f73fc56SMatthew Dillon  * (and expression). Check() return MATCH for a match, NO_MATCH is the string
17244f73fc56SMatthew Dillon  * couldn't be matched or REG_ERROR for an illegal opcode in expression.
17254f73fc56SMatthew Dillon  */
17268ecf459dSSascha Wildner int
check_string(REGEX * program,char * string,int * expression)17278ecf459dSSascha Wildner check_string(REGEX *program, char *string, int *expression)
17284f73fc56SMatthew Dillon {
17298ecf459dSSascha Wildner   int opcode;		/* Holds opcode of next expr. atom */
17304f73fc56SMatthew Dillon   char c;				/* Char that must be matched */
17318ecf459dSSascha Wildner   char *mark = NULL;		/* For marking position */
17324f73fc56SMatthew Dillon   int star_fl;			/* A star has been born */
17334f73fc56SMatthew Dillon 
17344f73fc56SMatthew Dillon   if (expression == NIL_INT)
17354f73fc56SMatthew Dillon   	expression = program->result.expression;
17364f73fc56SMatthew Dillon 
17374f73fc56SMatthew Dillon /* Loop until end of string or end of expression */
17384f73fc56SMatthew Dillon   while (quit == FALSE && !(*expression & DONE) &&
17394f73fc56SMatthew Dillon 					   *string != '\0' && *string != '\n') {
17404f73fc56SMatthew Dillon   	c = *expression & LOW_BYTE;	  /* Extract match char */
17414f73fc56SMatthew Dillon   	opcode = *expression & HIGH_BYTE; /* Extract opcode */
17428ecf459dSSascha Wildner   	if ((star_fl = (opcode & STAR)) != 0) {  /* Check star occurrence */
17434f73fc56SMatthew Dillon   		opcode &= ~STAR;	  /* Strip opcode */
17444f73fc56SMatthew Dillon   		mark = string;		  /* Mark current position */
17454f73fc56SMatthew Dillon   	}
17464f73fc56SMatthew Dillon   	expression++;		/* Increment expr. */
17474f73fc56SMatthew Dillon   	switch (opcode) {
17484f73fc56SMatthew Dillon   	case NORMAL :
17494f73fc56SMatthew Dillon   		if (star_fl)
17504f73fc56SMatthew Dillon   			while (*string++ == c)	/* Skip all matches */
17514f73fc56SMatthew Dillon   				;
17524f73fc56SMatthew Dillon   		else if (*string++ != c)
17534f73fc56SMatthew Dillon   			return NO_MATCH;
17544f73fc56SMatthew Dillon   		break;
17554f73fc56SMatthew Dillon   	case DOT :
17564f73fc56SMatthew Dillon   		string++;
17574f73fc56SMatthew Dillon   		if (star_fl)			/* Skip to eoln */
17584f73fc56SMatthew Dillon   			while (*string != '\0' && *string++ != '\n')
17594f73fc56SMatthew Dillon   				;
17604f73fc56SMatthew Dillon   		break;
17614f73fc56SMatthew Dillon   	case NEGATE | BRACKET:
17624f73fc56SMatthew Dillon   	case BRACKET :
17634f73fc56SMatthew Dillon   		if (star_fl)
17644f73fc56SMatthew Dillon   			while (in_list(expression, *string++, c, opcode)
17654f73fc56SMatthew Dillon 								       == MATCH)
17664f73fc56SMatthew Dillon   				;
17674f73fc56SMatthew Dillon   		else if (in_list(expression, *string++, c, opcode) == NO_MATCH)
17684f73fc56SMatthew Dillon   			return NO_MATCH;
17694f73fc56SMatthew Dillon   		expression += c - 1;	/* Add length of list */
17704f73fc56SMatthew Dillon   		break;
17714f73fc56SMatthew Dillon   	default :
17724f73fc56SMatthew Dillon   		panic("Corrupted program in check_string()");
17734f73fc56SMatthew Dillon   	}
17744f73fc56SMatthew Dillon   	if (star_fl)
17754f73fc56SMatthew Dillon   		return star(program, mark, string, expression);
17764f73fc56SMatthew Dillon   }
17774f73fc56SMatthew Dillon   if (*expression & DONE) {
17784f73fc56SMatthew Dillon   	program->end_ptr = string;	/* Match ends here */
17794f73fc56SMatthew Dillon   	/*
17804f73fc56SMatthew Dillon   	 * We might have found a match. The last thing to do is check
17814f73fc56SMatthew Dillon   	 * whether a '$' was given at the end of the expression, or
17824f73fc56SMatthew Dillon   	 * the match was found on a null string. (E.g. [a-z]* always
17834f73fc56SMatthew Dillon   	 * matches) unless a ^ or $ was included in the pattern.
17844f73fc56SMatthew Dillon   	 */
17854f73fc56SMatthew Dillon   	if ((*expression & EOLN) && *string != '\n' && *string != '\0')
17864f73fc56SMatthew Dillon   		return NO_MATCH;
17874f73fc56SMatthew Dillon 	if (string == program->start_ptr && !(program->status & BEGIN_LINE)
17884f73fc56SMatthew Dillon 					 && !(*expression & EOLN))
17894f73fc56SMatthew Dillon   		return NO_MATCH;
17904f73fc56SMatthew Dillon   	return MATCH;
17914f73fc56SMatthew Dillon   }
17924f73fc56SMatthew Dillon   return NO_MATCH;
17934f73fc56SMatthew Dillon }
17944f73fc56SMatthew Dillon 
17954f73fc56SMatthew Dillon /*
17964f73fc56SMatthew Dillon  * Star() calls check_string() to find out the longest match possible.
17974f73fc56SMatthew Dillon  * It searches backwards until the (in check_string()) marked position
17984f73fc56SMatthew Dillon  * is reached, or a match is found.
17994f73fc56SMatthew Dillon  */
18008ecf459dSSascha Wildner int
star(REGEX * program,char * end_position,char * string,int * expression)18018ecf459dSSascha Wildner star(REGEX *program, char *end_position, char *string, int *expression)
18024f73fc56SMatthew Dillon {
18034f73fc56SMatthew Dillon   do {
18044f73fc56SMatthew Dillon   	string--;
18054f73fc56SMatthew Dillon   	if (check_string(program, string, expression))
18064f73fc56SMatthew Dillon   		return MATCH;
18074f73fc56SMatthew Dillon   } while (string != end_position);
18084f73fc56SMatthew Dillon 
18094f73fc56SMatthew Dillon   return NO_MATCH;
18104f73fc56SMatthew Dillon }
18114f73fc56SMatthew Dillon 
18124f73fc56SMatthew Dillon /*
18134f73fc56SMatthew Dillon  * In_list() checks if the given character is in the list of []. If it is
18144f73fc56SMatthew Dillon  * it returns MATCH. if it isn't it returns NO_MATCH. These returns values
18154f73fc56SMatthew Dillon  * are reversed when the NEGATE field in the opcode is present.
18164f73fc56SMatthew Dillon  */
18178ecf459dSSascha Wildner int
in_list(int * list,char c,int list_length,int opcode)18188ecf459dSSascha Wildner in_list(int *list, char c, int list_length, int opcode)
18194f73fc56SMatthew Dillon {
18204f73fc56SMatthew Dillon   if (c == '\0' || c == '\n')	/* End of string, never matches */
18214f73fc56SMatthew Dillon   	return NO_MATCH;
18224f73fc56SMatthew Dillon   while (list_length-- > 1) {	/* > 1, don't check acct_field */
18234f73fc56SMatthew Dillon   	if ((*list & LOW_BYTE) == c)
18244f73fc56SMatthew Dillon   		return (opcode & NEGATE) ? NO_MATCH : MATCH;
18254f73fc56SMatthew Dillon   	list++;
18264f73fc56SMatthew Dillon   }
18274f73fc56SMatthew Dillon   return (opcode & NEGATE) ? MATCH : NO_MATCH;
18284f73fc56SMatthew Dillon }
18294f73fc56SMatthew Dillon 
18304f73fc56SMatthew Dillon /*
18314f73fc56SMatthew Dillon  * Dummy_line() adds an empty line at the end of the file. This is sometimes
18324f73fc56SMatthew Dillon  * useful in combination with the EF and DN command in combination with the
18334f73fc56SMatthew Dillon  * Yank command set.
18344f73fc56SMatthew Dillon  */
18358ecf459dSSascha Wildner void
dummy_line(void)18368ecf459dSSascha Wildner dummy_line(void)
18374f73fc56SMatthew Dillon {
18388ecf459dSSascha Wildner 	line_insert(tail->prev, "\n", 1);
18394f73fc56SMatthew Dillon 	tail->prev->shift_count = DUMMY;
18404f73fc56SMatthew Dillon 	if (last_y != screenmax) {
18414f73fc56SMatthew Dillon 		last_y++;
18424f73fc56SMatthew Dillon 		bot_line = bot_line->next;
18434f73fc56SMatthew Dillon 	}
18444f73fc56SMatthew Dillon }
1845