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