1 /* $NetBSD: getc.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */ 2 /*- 3 * Copyright (c) 1992, 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 1992, 1993, 1994, 1995, 1996 6 * Keith Bostic. All rights reserved. 7 * 8 * See the LICENSE file for redistribution information. 9 */ 10 11 #include "config.h" 12 13 #include <sys/cdefs.h> 14 #if 0 15 #ifndef lint 16 static const char sccsid[] = "Id: getc.c,v 10.12 2001/06/25 15:19:30 skimo Exp (Berkeley) Date: 2001/06/25 15:19:30 "; 17 #endif /* not lint */ 18 #else 19 __RCSID("$NetBSD: getc.c,v 1.3 2014/01/26 21:43:45 christos Exp $"); 20 #endif 21 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/time.h> 25 26 #include <bitstring.h> 27 #include <ctype.h> 28 #include <limits.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 32 #include "../common/common.h" 33 #include "vi.h" 34 35 /* 36 * Character stream routines -- 37 * These routines return the file a character at a time. There are two 38 * special cases. First, the end of a line, end of a file, start of a 39 * file and empty lines are returned as special cases, and no character 40 * is returned. Second, empty lines include lines that have only white 41 * space in them, because the vi search functions don't care about white 42 * space, and this makes it easier for them to be consistent. 43 */ 44 45 /* 46 * cs_init -- 47 * Initialize character stream routines. 48 * 49 * PUBLIC: int cs_init __P((SCR *, VCS *)); 50 */ 51 int 52 cs_init(SCR *sp, VCS *csp) 53 { 54 int isempty; 55 56 if (db_eget(sp, csp->cs_lno, &csp->cs_bp, &csp->cs_len, &isempty)) { 57 if (isempty) 58 msgq(sp, M_BERR, "177|Empty file"); 59 return (1); 60 } 61 if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { 62 csp->cs_cno = 0; 63 csp->cs_flags = CS_EMP; 64 } else { 65 csp->cs_flags = 0; 66 csp->cs_ch = csp->cs_bp[csp->cs_cno]; 67 } 68 return (0); 69 } 70 71 /* 72 * cs_next -- 73 * Retrieve the next character. 74 * 75 * PUBLIC: int cs_next __P((SCR *, VCS *)); 76 */ 77 int 78 cs_next(SCR *sp, VCS *csp) 79 { 80 CHAR_T *p; 81 82 switch (csp->cs_flags) { 83 case CS_EMP: /* EMP; get next line. */ 84 case CS_EOL: /* EOL; get next line. */ 85 if (db_get(sp, ++csp->cs_lno, 0, &p, &csp->cs_len)) { 86 --csp->cs_lno; 87 csp->cs_flags = CS_EOF; 88 } else { 89 csp->cs_bp = p; 90 if (csp->cs_len == 0 || 91 v_isempty(csp->cs_bp, csp->cs_len)) { 92 csp->cs_cno = 0; 93 csp->cs_flags = CS_EMP; 94 } else { 95 csp->cs_flags = 0; 96 csp->cs_ch = csp->cs_bp[csp->cs_cno = 0]; 97 } 98 } 99 break; 100 case 0: 101 if (csp->cs_cno == csp->cs_len - 1) 102 csp->cs_flags = CS_EOL; 103 else 104 csp->cs_ch = csp->cs_bp[++csp->cs_cno]; 105 break; 106 case CS_EOF: /* EOF. */ 107 break; 108 default: 109 abort(); 110 /* NOTREACHED */ 111 } 112 return (0); 113 } 114 115 /* 116 * cs_fspace -- 117 * If on a space, eat forward until something other than a 118 * whitespace character. 119 * 120 * XXX 121 * Semantics of checking the current character were coded for the fword() 122 * function -- once the other word routines are converted, they may have 123 * to change. 124 * 125 * PUBLIC: int cs_fspace __P((SCR *, VCS *)); 126 */ 127 int 128 cs_fspace(SCR *sp, VCS *csp) 129 { 130 if (csp->cs_flags != 0 || !ISBLANK2(csp->cs_ch)) 131 return (0); 132 for (;;) { 133 if (cs_next(sp, csp)) 134 return (1); 135 if (csp->cs_flags != 0 || !ISBLANK2(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(SCR *sp, VCS *csp) 149 { 150 for (;;) { 151 if (cs_next(sp, csp)) 152 return (1); 153 if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || 154 (csp->cs_flags == 0 && ISBLANK2(csp->cs_ch))) 155 continue; 156 break; 157 } 158 return (0); 159 } 160 161 /* 162 * cs_prev -- 163 * Retrieve the previous character. 164 * 165 * PUBLIC: int cs_prev __P((SCR *, VCS *)); 166 */ 167 int 168 cs_prev(SCR *sp, VCS *csp) 169 { 170 switch (csp->cs_flags) { 171 case CS_EMP: /* EMP; get previous line. */ 172 case CS_EOL: /* EOL; get previous line. */ 173 if (csp->cs_lno == 1) { /* SOF. */ 174 csp->cs_flags = CS_SOF; 175 break; 176 } 177 if (db_get(sp, /* The line should exist. */ 178 --csp->cs_lno, DBG_FATAL, &csp->cs_bp, &csp->cs_len)) { 179 ++csp->cs_lno; 180 return (1); 181 } 182 if (csp->cs_len == 0 || v_isempty(csp->cs_bp, csp->cs_len)) { 183 csp->cs_cno = 0; 184 csp->cs_flags = CS_EMP; 185 } else { 186 csp->cs_flags = 0; 187 csp->cs_cno = csp->cs_len - 1; 188 csp->cs_ch = csp->cs_bp[csp->cs_cno]; 189 } 190 break; 191 case CS_EOF: /* EOF: get previous char. */ 192 case 0: 193 if (csp->cs_cno == 0) 194 if (csp->cs_lno == 1) 195 csp->cs_flags = CS_SOF; 196 else 197 csp->cs_flags = CS_EOL; 198 else 199 csp->cs_ch = csp->cs_bp[--csp->cs_cno]; 200 break; 201 case CS_SOF: /* SOF. */ 202 break; 203 default: 204 abort(); 205 /* NOTREACHED */ 206 } 207 return (0); 208 } 209 210 /* 211 * cs_bblank -- 212 * Eat backward to the next non-whitespace character. 213 * 214 * PUBLIC: int cs_bblank __P((SCR *, VCS *)); 215 */ 216 int 217 cs_bblank(SCR *sp, VCS *csp) 218 { 219 for (;;) { 220 if (cs_prev(sp, csp)) 221 return (1); 222 if (csp->cs_flags == CS_EOL || csp->cs_flags == CS_EMP || 223 (csp->cs_flags == 0 && ISBLANK2(csp->cs_ch))) 224 continue; 225 break; 226 } 227 return (0); 228 } 229