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
cs_init(sp,csp)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
cs_next(sp,csp)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
cs_fspace(sp,csp)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
cs_fblank(sp,csp)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
cs_prev(sp,csp)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
cs_bblank(sp,csp)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