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.2 (Berkeley) 07/25/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 "less.h" 35 36 extern int squeeze; 37 extern int sigs; 38 extern char *line; 39 40 /* 41 * Get the next line. 42 * A "current" position is passed and a "new" position is returned. 43 * The current position is the position of the first character of 44 * a line. The new position is the position of the first character 45 * of the NEXT line. The line obtained is the line starting at curr_pos. 46 */ 47 public POSITION 48 forw_line(curr_pos) 49 POSITION curr_pos; 50 { 51 POSITION new_pos; 52 register int c; 53 54 if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) 55 return (NULL_POSITION); 56 57 c = ch_forw_get(); 58 if (c == EOI) 59 return (NULL_POSITION); 60 61 prewind(); 62 for (;;) 63 { 64 if (sigs) 65 return (NULL_POSITION); 66 if (c == '\n' || c == EOI) 67 { 68 /* 69 * End of the line. 70 */ 71 new_pos = ch_tell(); 72 break; 73 } 74 75 /* 76 * Append the char to the line and get the next char. 77 */ 78 if (pappend(c)) 79 { 80 /* 81 * The char won't fit in the line; the line 82 * is too long to print in the screen width. 83 * End the line here. 84 */ 85 new_pos = ch_tell() - 1; 86 break; 87 } 88 c = ch_forw_get(); 89 } 90 (void) pappend('\0'); 91 92 if (squeeze && *line == '\0') 93 { 94 /* 95 * This line is blank. 96 * Skip down to the last contiguous blank line 97 * and pretend it is the one which we are returning. 98 */ 99 while ((c = ch_forw_get()) == '\n') 100 if (sigs) 101 return (NULL_POSITION); 102 if (c != EOI) 103 (void) ch_back_get(); 104 new_pos = ch_tell(); 105 } 106 107 return (new_pos); 108 } 109 110 /* 111 * Get the previous line. 112 * A "current" position is passed and a "new" position is returned. 113 * The current position is the position of the first character of 114 * a line. The new position is the position of the first character 115 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 116 */ 117 public POSITION 118 back_line(curr_pos) 119 POSITION curr_pos; 120 { 121 POSITION new_pos, begin_new_pos; 122 int c; 123 124 if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 || 125 ch_seek(curr_pos-1)) 126 return (NULL_POSITION); 127 128 if (squeeze) 129 { 130 /* 131 * Find out if the "current" line was blank. 132 */ 133 (void) ch_forw_get(); /* Skip the newline */ 134 c = ch_forw_get(); /* First char of "current" line */ 135 (void) ch_back_get(); /* Restore our position */ 136 (void) ch_back_get(); 137 138 if (c == '\n') 139 { 140 /* 141 * The "current" line was blank. 142 * Skip over any preceeding blank lines, 143 * since we skipped them in forw_line(). 144 */ 145 while ((c = ch_back_get()) == '\n') 146 if (sigs) 147 return (NULL_POSITION); 148 if (c == EOI) 149 return (NULL_POSITION); 150 (void) ch_forw_get(); 151 } 152 } 153 154 /* 155 * Scan backwards until we hit the beginning of the line. 156 */ 157 for (;;) 158 { 159 if (sigs) 160 return (NULL_POSITION); 161 c = ch_back_get(); 162 if (c == '\n') 163 { 164 /* 165 * This is the newline ending the previous line. 166 * We have hit the beginning of the line. 167 */ 168 new_pos = ch_tell() + 1; 169 break; 170 } 171 if (c == EOI) 172 { 173 /* 174 * We have hit the beginning of the file. 175 * This must be the first line in the file. 176 * This must, of course, be the beginning of the line. 177 */ 178 new_pos = ch_tell(); 179 break; 180 } 181 } 182 183 /* 184 * Now scan forwards from the beginning of this line. 185 * We keep discarding "printable lines" (based on screen width) 186 * until we reach the curr_pos. 187 * 188 * {{ This algorithm is pretty inefficient if the lines 189 * are much longer than the screen width, 190 * but I don't know of any better way. }} 191 */ 192 if (ch_seek(new_pos)) 193 return (NULL_POSITION); 194 loop: 195 begin_new_pos = new_pos; 196 prewind(); 197 198 do 199 { 200 c = ch_forw_get(); 201 if (c == EOI || sigs) 202 return (NULL_POSITION); 203 new_pos++; 204 if (c == '\n') 205 break; 206 if (pappend(c)) 207 { 208 /* 209 * Got a full printable line, but we haven't 210 * reached our curr_pos yet. Discard the line 211 * and start a new one. 212 */ 213 (void) pappend('\0'); 214 (void) ch_back_get(); 215 new_pos--; 216 goto loop; 217 } 218 } while (new_pos < curr_pos); 219 220 (void) pappend('\0'); 221 222 return (begin_new_pos); 223 } 224