Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / nvi / vi / getc.c
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
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
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
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
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
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
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 }