xref: /openbsd-src/usr.bin/vi/vi/getc.c (revision a0b15055027e40896769bb61ce100804e66327ea)
1 /*	$OpenBSD: getc.c,v 1.10 2016/01/06 22:28:52 millert Exp $	*/
2 
3 /*-
4  * Copyright (c) 1992, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1992, 1993, 1994, 1995, 1996
7  *	Keith Bostic.  All rights reserved.
8  *
9  * See the LICENSE file for redistribution information.
10  */
11 
12 #include "config.h"
13 
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
17 
18 #include <bitstring.h>
19 #include <ctype.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "../common/common.h"
25 #include "vi.h"
26 
27 /*
28  * Character stream routines --
29  *	These routines return the file a character at a time.  There are two
30  *	special cases.  First, the end of a line, end of a file, start of a
31  *	file and empty lines are returned as special cases, and no character
32  *	is returned.  Second, empty lines include lines that have only white
33  *	space in them, because the vi search functions don't care about white
34  *	space, and this makes it easier for them to be consistent.
35  */
36 
37 /*
38  * cs_init --
39  *	Initialize character stream routines.
40  *
41  * PUBLIC: int cs_init(SCR *, VCS *);
42  */
43 int
cs_init(SCR * sp,VCS * csp)44 cs_init(SCR *sp, VCS *csp)
45 {
46 	int isempty;
47 
48 	if (db_eget(sp, csp->cs_lno, (char **) &csp->cs_bp, &csp->cs_len,
49 	    &isempty)) {
50 		if (isempty)
51 			msgq(sp, M_BERR, "Empty file");
52 		return (1);
53 	}
54 	if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) {
55 		csp->cs_cno = 0;
56 		csp->cs_flags = CS_EMP;
57 	} else {
58 		csp->cs_flags = 0;
59 		csp->cs_ch = csp->cs_bp[csp->cs_cno];
60 	}
61 	return (0);
62 }
63 
64 /*
65  * cs_next --
66  *	Retrieve the next character.
67  *
68  * PUBLIC: int cs_next(SCR *, VCS *);
69  */
70 int
cs_next(SCR * sp,VCS * csp)71 cs_next(SCR *sp, VCS *csp)
72 {
73 	char *p;
74 
75 	switch (csp->cs_flags) {
76 	case CS_EMP:				/* EMP; get next line. */
77 	case CS_EOL:				/* EOL; get next line. */
78 		if (db_get(sp, ++csp->cs_lno, 0, &p, &csp->cs_len)) {
79 			--csp->cs_lno;
80 			csp->cs_flags = CS_EOF;
81 		} else {
82 			csp->cs_bp = p;
83 			if (csp->cs_len == 0 ||
84 			    v_isempty(csp->cs_bp, csp->cs_len)) {
85 				csp->cs_cno = 0;
86 				csp->cs_flags = CS_EMP;
87 			} else {
88 				csp->cs_flags = 0;
89 				csp->cs_ch = csp->cs_bp[csp->cs_cno = 0];
90 			}
91 		}
92 		break;
93 	case 0:
94 		if (csp->cs_cno == csp->cs_len - 1)
95 			csp->cs_flags = CS_EOL;
96 		else
97 			csp->cs_ch = csp->cs_bp[++csp->cs_cno];
98 		break;
99 	case CS_EOF:				/* EOF. */
100 		break;
101 	default:
102 		abort();
103 		/* NOTREACHED */
104 	}
105 	return (0);
106 }
107 
108 /*
109  * cs_fspace --
110  *	If on a space, eat forward until something other than a
111  *	whitespace character.
112  *
113  * XXX
114  * Semantics of checking the current character were coded for the fword()
115  * function -- once the other word routines are converted, they may have
116  * to change.
117  *
118  * PUBLIC: int cs_fspace(SCR *, VCS *);
119  */
120 int
cs_fspace(SCR * sp,VCS * csp)121 cs_fspace(SCR *sp, VCS *csp)
122 {
123 	if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
124 		return (0);
125 	for (;;) {
126 		if (cs_next(sp, csp))
127 			return (1);
128 		if (csp->cs_flags != 0 || !isblank(csp->cs_ch))
129 			break;
130 	}
131 	return (0);
132 }
133 
134 /*
135  * cs_fblank --
136  *	Eat forward to the next non-whitespace character.
137  *
138  * PUBLIC: int cs_fblank(SCR *, VCS *);
139  */
140 int
cs_fblank(SCR * sp,VCS * csp)141 cs_fblank(SCR *sp, VCS *csp)
142 {
143 	for (;;) {
144 		if (cs_next(sp, csp))
145 			return (1);
146 		if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP ||
147 		    (csp->cs_flags == 0 && isblank(csp->cs_ch)))
148 			continue;
149 		break;
150 	}
151 	return (0);
152 }
153 
154 /*
155  * cs_prev --
156  *	Retrieve the previous character.
157  *
158  * PUBLIC: int cs_prev(SCR *, VCS *);
159  */
160 int
cs_prev(SCR * sp,VCS * csp)161 cs_prev(SCR *sp, VCS *csp)
162 {
163 	switch (csp->cs_flags) {
164 	case CS_EMP:				/* EMP; get previous line. */
165 	case CS_EOL:				/* EOL; get previous line. */
166 		if (csp->cs_lno == 1) {		/* SOF. */
167 			csp->cs_flags = CS_SOF;
168 			break;
169 		}
170 		if (db_get(sp,			/* The line should exist. */
171 		    --csp->cs_lno, DBG_FATAL, (char **) &csp->cs_bp,
172 		    &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
cs_bblank(SCR * sp,VCS * csp)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