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[] = "$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 */
45int
46cs_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 */
71int
72cs_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 */
121int
122cs_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 */
141int
142cs_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 */
161int
162cs_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 */
210int
211cs_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