xref: /freebsd/contrib/nvi/vi/getc.c (revision aa0a1e58)
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #ifndef lint
13 static const char sccsid[] = "@(#)getc.c	10.10 (Berkeley) 3/6/96";
14 #endif /* not lint */
15 
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19 
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include "../common/common.h"
27 #include "vi.h"
28 
29 /*
30  * Character stream routines --
31  *	These routines return the file a character at a time.  There are two
32  *	special cases.  First, the end of a line, end of a file, start of a
33  *	file and empty lines are returned as special cases, and no character
34  *	is returned.  Second, empty lines include lines that have only white
35  *	space in them, because the vi search functions don't care about white
36  *	space, and this makes it easier for them to be consistent.
37  */
38 
39 /*
40  * cs_init --
41  *	Initialize character stream routines.
42  *
43  * PUBLIC: int cs_init __P((SCR *, VCS *));
44  */
45 int
46 cs_init(sp, csp)
47 	SCR *sp;
48 	VCS *csp;
49 {
50 	int isempty;
51 
52 	if (db_eget(sp, csp->cs_lno, &csp->cs_bp, &csp->cs_len, &isempty)) {
53 		if (isempty)
54 			msgq(sp, M_BERR, "177|Empty file");
55 		return (1);
56 	}
57 	if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
58 		csp->cs_cno = 0;
59 		csp->cs_flags = CS_EMP;
60 	} else {
61 		csp->cs_flags = 0;
62 		csp->cs_ch = csp->cs_bp[csp->cs_cno];
63 	}
64 	return (0);
65 }
66 
67 /*
68  * cs_next --
69  *	Retrieve the next character.
70  *
71  * PUBLIC: int cs_next __P((SCR *, VCS *));
72  */
73 int
74 cs_next(sp, csp)
75 	SCR *sp;
76 	VCS *csp;
77 {
78 	char *p;
79 
80 	switch (csp->cs_flags) {
81 	case CS_EMP:				/* EMP; get next line. */
82 	case CS_EOL:				/* EOL; get next line. */
83 		if (db_get(sp, ++csp->cs_lno, 0, &p, &csp->cs_len)) {
84 			--csp->cs_lno;
85 			csp->cs_flags = CS_EOF;
86 		} else {
87 			csp->cs_bp = p;
88 			if (csp->cs_len == 0 ||
89 			    v_isempty(csp->cs_bp, csp->cs_len)) {
90 				csp->cs_cno = 0;
91 				csp->cs_flags = CS_EMP;
92 			} else {
93 				csp->cs_flags = 0;
94 				csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
95 			}
96 		}
97 		break;
98 	case 0:
99 		if (csp->cs_cno == csp->cs_len - 1)
100 			csp->cs_flags = CS_EOL;
101 		else
102 			csp->cs_ch = csp->cs_bp[++csp->cs_cno];
103 		break;
104 	case CS_EOF:				/* EOF. */
105 		break;
106 	default:
107 		abort();
108 		/* NOTREACHED */
109 	}
110 	return (0);
111 }
112 
113 /*
114  * cs_fspace --
115  *	If on a space, eat forward until something other than a
116  *	whitespace character.
117  *
118  * XXX
119  * Semantics of checking the current character were coded for the fword()
120  * function -- once the other word routines are converted, they may have
121  * to change.
122  *
123  * PUBLIC: int cs_fspace __P((SCR *, VCS *));
124  */
125 int
126 cs_fspace(sp, csp)
127 	SCR *sp;
128 	VCS *csp;
129 {
130 	if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
131 		return (0);
132 	for (;;) {
133 		if (cs_next(sp, csp))
134 			return (1);
135 		if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
136 			break;
137 	}
138 	return (0);
139 }
140 
141 /*
142  * cs_fblank --
143  *	Eat forward to the next non-whitespace character.
144  *
145  * PUBLIC: int cs_fblank __P((SCR *, VCS *));
146  */
147 int
148 cs_fblank(sp, csp)
149 	SCR *sp;
150 	VCS *csp;
151 {
152 	for (;;) {
153 		if (cs_next(sp, csp))
154 			return (1);
155 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
156 		    csp->cs_flags == 0 && isblank(csp->cs_ch))
157 			continue;
158 		break;
159 	}
160 	return (0);
161 }
162 
163 /*
164  * cs_prev --
165  *	Retrieve the previous character.
166  *
167  * PUBLIC: int cs_prev __P((SCR *, VCS *));
168  */
169 int
170 cs_prev(sp, csp)
171 	SCR *sp;
172 	VCS *csp;
173 {
174 	switch (csp->cs_flags) {
175 	case CS_EMP:				/* EMP; get previous line. */
176 	case CS_EOL:				/* EOL; get previous line. */
177 		if (csp->cs_lno == 1) {		/* SOF. */
178 			csp->cs_flags = CS_SOF;
179 			break;
180 		}
181 		if (db_get(sp,			/* The line should exist. */
182 		    --csp->cs_lno, DBG_FATAL, &csp->cs_bp, &csp->cs_len)) {
183 			++csp->cs_lno;
184 			return (1);
185 		}
186 		if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
187 			csp->cs_cno = 0;
188 			csp->cs_flags = CS_EMP;
189 		} else {
190 			csp->cs_flags = 0;
191 			csp->cs_cno = csp->cs_len - 1;
192 			csp->cs_ch = csp->cs_bp[csp->cs_cno];
193 		}
194 		break;
195 	case CS_EOF:				/* EOF: get previous char. */
196 	case 0:
197 		if (csp->cs_cno == 0)
198 			if (csp->cs_lno == 1)
199 				csp->cs_flags = CS_SOF;
200 			else
201 				csp->cs_flags = CS_EOL;
202 		else
203 			csp->cs_ch = csp->cs_bp[--csp->cs_cno];
204 		break;
205 	case CS_SOF:				/* SOF. */
206 		break;
207 	default:
208 		abort();
209 		/* NOTREACHED */
210 	}
211 	return (0);
212 }
213 
214 /*
215  * cs_bblank --
216  *	Eat backward to the next non-whitespace character.
217  *
218  * PUBLIC: int cs_bblank __P((SCR *, VCS *));
219  */
220 int
221 cs_bblank(sp, csp)
222 	SCR *sp;
223 	VCS *csp;
224 {
225 	for (;;) {
226 		if (cs_prev(sp, csp))
227 			return (1);
228 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
229 		    csp->cs_flags == 0 && isblank(csp->cs_ch))
230 			continue;
231 		break;
232 	}
233 	return (0);
234 }
235