xref: /freebsd/contrib/nvi/vi/getc.c (revision f3c5273d315a64826d2149ac453ff8c4583ddbe8)
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[] = "$Id: getc.c,v 10.13 2011/12/27 00:49:31 zy Exp $";
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(SCR *, VCS *);
44  */
45 int
46 cs_init(SCR *sp, VCS *csp)
47 {
48 	int isempty;
49 
50 	if (db_eget(sp, csp->cs_lno, &csp->cs_bp, &csp->cs_len, &isempty)) {
51 		if (isempty)
52 			msgq(sp, M_BERR, "177|Empty file");
53 		return (1);
54 	}
55 	if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
56 		csp->cs_cno = 0;
57 		csp->cs_flags = CS_EMP;
58 	} else {
59 		csp->cs_flags = 0;
60 		csp->cs_ch = csp->cs_bp[csp->cs_cno];
61 	}
62 	return (0);
63 }
64 
65 /*
66  * cs_next --
67  *	Retrieve the next character.
68  *
69  * PUBLIC: int cs_next(SCR *, VCS *);
70  */
71 int
72 cs_next(SCR *sp, VCS *csp)
73 {
74 	CHAR_T *p;
75 
76 	switch (csp->cs_flags) {
77 	case CS_EMP:				/* EMP; get next line. */
78 	case CS_EOL:				/* EOL; get next line. */
79 		if (db_get(sp, ++csp->cs_lno, 0, &p, &csp->cs_len)) {
80 			--csp->cs_lno;
81 			csp->cs_flags = CS_EOF;
82 		} else {
83 			csp->cs_bp = p;
84 			if (csp->cs_len == 0 ||
85 			    v_isempty(csp->cs_bp, csp->cs_len)) {
86 				csp->cs_cno = 0;
87 				csp->cs_flags = CS_EMP;
88 			} else {
89 				csp->cs_flags = 0;
90 				csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
91 			}
92 		}
93 		break;
94 	case 0:
95 		if (csp->cs_cno == csp->cs_len - 1)
96 			csp->cs_flags = CS_EOL;
97 		else
98 			csp->cs_ch = csp->cs_bp[++csp->cs_cno];
99 		break;
100 	case CS_EOF:				/* EOF. */
101 		break;
102 	default:
103 		abort();
104 		/* NOTREACHED */
105 	}
106 	return (0);
107 }
108 
109 /*
110  * cs_fspace --
111  *	If on a space, eat forward until something other than a
112  *	whitespace character.
113  *
114  * XXX
115  * Semantics of checking the current character were coded for the fword()
116  * function -- once the other word routines are converted, they may have
117  * to change.
118  *
119  * PUBLIC: int cs_fspace(SCR *, VCS *);
120  */
121 int
122 cs_fspace(SCR *sp, VCS *csp)
123 {
124 	if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch))
125 		return (0);
126 	for (;;) {
127 		if (cs_next(sp, csp))
128 			return (1);
129 		if (csp->cs_flags != 0 || !ISBLANK(csp->cs_ch))
130 			break;
131 	}
132 	return (0);
133 }
134 
135 /*
136  * cs_fblank --
137  *	Eat forward to the next non-whitespace character.
138  *
139  * PUBLIC: int cs_fblank(SCR *, VCS *);
140  */
141 int
142 cs_fblank(SCR *sp, VCS *csp)
143 {
144 	for (;;) {
145 		if (cs_next(sp, csp))
146 			return (1);
147 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
148 		    (csp->cs_flags == 0 && ISBLANK(csp->cs_ch)))
149 			continue;
150 		break;
151 	}
152 	return (0);
153 }
154 
155 /*
156  * cs_prev --
157  *	Retrieve the previous character.
158  *
159  * PUBLIC: int cs_prev(SCR *, VCS *);
160  */
161 int
162 cs_prev(SCR *sp, VCS *csp)
163 {
164 	switch (csp->cs_flags) {
165 	case CS_EMP:				/* EMP; get previous line. */
166 	case CS_EOL:				/* EOL; get previous line. */
167 		if (csp->cs_lno == 1) {		/* SOF. */
168 			csp->cs_flags = CS_SOF;
169 			break;
170 		}
171 		if (db_get(sp,			/* The line should exist. */
172 		    --csp->cs_lno, DBG_FATAL, &csp->cs_bp, &csp->cs_len)) {
173 			++csp->cs_lno;
174 			return (1);
175 		}
176 		if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
177 			csp->cs_cno = 0;
178 			csp->cs_flags = CS_EMP;
179 		} else {
180 			csp->cs_flags = 0;
181 			csp->cs_cno = csp->cs_len - 1;
182 			csp->cs_ch = csp->cs_bp[csp->cs_cno];
183 		}
184 		break;
185 	case CS_EOF:				/* EOF: get previous char. */
186 	case 0:
187 		if (csp->cs_cno == 0)
188 			if (csp->cs_lno == 1)
189 				csp->cs_flags = CS_SOF;
190 			else
191 				csp->cs_flags = CS_EOL;
192 		else
193 			csp->cs_ch = csp->cs_bp[--csp->cs_cno];
194 		break;
195 	case CS_SOF:				/* SOF. */
196 		break;
197 	default:
198 		abort();
199 		/* NOTREACHED */
200 	}
201 	return (0);
202 }
203 
204 /*
205  * cs_bblank --
206  *	Eat backward to the next non-whitespace character.
207  *
208  * PUBLIC: int cs_bblank(SCR *, VCS *);
209  */
210 int
211 cs_bblank(SCR *sp, VCS *csp)
212 {
213 	for (;;) {
214 		if (cs_prev(sp, csp))
215 			return (1);
216 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
217 		    (csp->cs_flags == 0 && ISBLANK(csp->cs_ch)))
218 			continue;
219 		break;
220 	}
221 	return (0);
222 }
223