1 /* 2 * Copyright (c) 1988 Mark Nudleman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 06/01/90"; 11 #endif /* not lint */ 12 13 /* 14 * High level routines dealing with getting lines of input 15 * from the file being viewed. 16 * 17 * When we speak of "lines" here, we mean PRINTABLE lines; 18 * lines processed with respect to the screen width. 19 * We use the term "raw line" to refer to lines simply 20 * delimited by newlines; not processed with respect to screen width. 21 */ 22 23 #include <sys/types.h> 24 #include <less.h> 25 26 extern int squeeze; 27 extern int sigs; 28 extern char *line; 29 30 off_t ch_tell(); 31 32 /* 33 * Get the next line. 34 * A "current" position is passed and a "new" position is returned. 35 * The current position is the position of the first character of 36 * a line. The new position is the position of the first character 37 * of the NEXT line. The line obtained is the line starting at curr_pos. 38 */ 39 off_t 40 forw_line(curr_pos) 41 off_t curr_pos; 42 { 43 off_t new_pos; 44 register int c; 45 46 if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) 47 return (NULL_POSITION); 48 49 c = ch_forw_get(); 50 if (c == EOI) 51 return (NULL_POSITION); 52 53 prewind(); 54 for (;;) 55 { 56 if (sigs) 57 return (NULL_POSITION); 58 if (c == '\n' || c == EOI) 59 { 60 /* 61 * End of the line. 62 */ 63 new_pos = ch_tell(); 64 break; 65 } 66 67 /* 68 * Append the char to the line and get the next char. 69 */ 70 if (pappend(c)) 71 { 72 /* 73 * The char won't fit in the line; the line 74 * is too long to print in the screen width. 75 * End the line here. 76 */ 77 new_pos = ch_tell() - 1; 78 break; 79 } 80 c = ch_forw_get(); 81 } 82 (void) pappend('\0'); 83 84 if (squeeze && *line == '\0') 85 { 86 /* 87 * This line is blank. 88 * Skip down to the last contiguous blank line 89 * and pretend it is the one which we are returning. 90 */ 91 while ((c = ch_forw_get()) == '\n') 92 if (sigs) 93 return (NULL_POSITION); 94 if (c != EOI) 95 (void) ch_back_get(); 96 new_pos = ch_tell(); 97 } 98 99 return (new_pos); 100 } 101 102 /* 103 * Get the previous line. 104 * A "current" position is passed and a "new" position is returned. 105 * The current position is the position of the first character of 106 * a line. The new position is the position of the first character 107 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 108 */ 109 off_t 110 back_line(curr_pos) 111 off_t curr_pos; 112 { 113 off_t new_pos, begin_new_pos; 114 int c; 115 116 if (curr_pos == NULL_POSITION || curr_pos <= (off_t)0 || 117 ch_seek(curr_pos-1)) 118 return (NULL_POSITION); 119 120 if (squeeze) 121 { 122 /* 123 * Find out if the "current" line was blank. 124 */ 125 (void) ch_forw_get(); /* Skip the newline */ 126 c = ch_forw_get(); /* First char of "current" line */ 127 (void) ch_back_get(); /* Restore our position */ 128 (void) ch_back_get(); 129 130 if (c == '\n') 131 { 132 /* 133 * The "current" line was blank. 134 * Skip over any preceeding blank lines, 135 * since we skipped them in forw_line(). 136 */ 137 while ((c = ch_back_get()) == '\n') 138 if (sigs) 139 return (NULL_POSITION); 140 if (c == EOI) 141 return (NULL_POSITION); 142 (void) ch_forw_get(); 143 } 144 } 145 146 /* 147 * Scan backwards until we hit the beginning of the line. 148 */ 149 for (;;) 150 { 151 if (sigs) 152 return (NULL_POSITION); 153 c = ch_back_get(); 154 if (c == '\n') 155 { 156 /* 157 * This is the newline ending the previous line. 158 * We have hit the beginning of the line. 159 */ 160 new_pos = ch_tell() + 1; 161 break; 162 } 163 if (c == EOI) 164 { 165 /* 166 * We have hit the beginning of the file. 167 * This must be the first line in the file. 168 * This must, of course, be the beginning of the line. 169 */ 170 new_pos = ch_tell(); 171 break; 172 } 173 } 174 175 /* 176 * Now scan forwards from the beginning of this line. 177 * We keep discarding "printable lines" (based on screen width) 178 * until we reach the curr_pos. 179 * 180 * {{ This algorithm is pretty inefficient if the lines 181 * are much longer than the screen width, 182 * but I don't know of any better way. }} 183 */ 184 if (ch_seek(new_pos)) 185 return (NULL_POSITION); 186 loop: 187 begin_new_pos = new_pos; 188 prewind(); 189 190 do 191 { 192 c = ch_forw_get(); 193 if (c == EOI || sigs) 194 return (NULL_POSITION); 195 new_pos++; 196 if (c == '\n') 197 break; 198 if (pappend(c)) 199 { 200 /* 201 * Got a full printable line, but we haven't 202 * reached our curr_pos yet. Discard the line 203 * and start a new one. 204 */ 205 (void) pappend('\0'); 206 (void) ch_back_get(); 207 new_pos--; 208 goto loop; 209 } 210 } while (new_pos < curr_pos); 211 212 (void) pappend('\0'); 213 214 return (begin_new_pos); 215 } 216