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
13static 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 */
45int
46cs_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 */
73int
74cs_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 */
125int
126cs_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 */
147int
148cs_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 */
169int
170cs_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 */
220int
221cs_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