[9] | 1 | /* Copyright (c) 1985 Ceriel J.H. Jacobs */
|
---|
| 2 |
|
---|
| 3 | # ifndef lint
|
---|
| 4 | static char rcsid[] = "$Header: /cvsup/minix/src/commands/yap/getline.c,v 1.1.1.1 2005/04/21 14:55:39 beng Exp $";
|
---|
| 5 | # endif
|
---|
| 6 |
|
---|
| 7 | # define _GETLINE_
|
---|
| 8 |
|
---|
| 9 | # include <errno.h>
|
---|
| 10 | # include "in_all.h"
|
---|
| 11 | # include "getline.h"
|
---|
| 12 | # include "options.h"
|
---|
| 13 | # include "process.h"
|
---|
| 14 | # include "term.h"
|
---|
| 15 | # include "main.h"
|
---|
| 16 | # include "display.h"
|
---|
| 17 | # include "output.h"
|
---|
| 18 | # include "assert.h"
|
---|
| 19 |
|
---|
| 20 | extern int errno;
|
---|
| 21 |
|
---|
| 22 | # define BLOCKSIZE 2048 /* size of blocks */
|
---|
| 23 | # define CHUNK 50 /* # of blockheaders allocated at a time */
|
---|
| 24 |
|
---|
| 25 | /*
|
---|
| 26 | * The blockheaders of the blocks that are in core are kept in a linked list.
|
---|
| 27 | * The last added block is indicated by b_head,
|
---|
| 28 | * the tail of the list is indicated by b_tail.
|
---|
| 29 | * The links go from b_tail to b_head.
|
---|
| 30 | * The blockheaders are all in an array, in the order of the line numbers.
|
---|
| 31 | * Also, the blockheaders must always be in core, so they have to be rather
|
---|
| 32 | * small. On systems with a small address space, yap can run out of core,
|
---|
| 33 | * and panic. However, this should only happen with very large files (>> 1M).
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | struct block {
|
---|
| 37 | int b_flags; /* Contains the following flags: */
|
---|
| 38 | # define DUMPED 01 /* block dumped on temporary file */
|
---|
| 39 | # define PARTLY 02 /* block not filled completely (eof) */
|
---|
| 40 | int b_next; /* ptr in linked list */
|
---|
| 41 | long b_end; /* line number of last line in block */
|
---|
| 42 | char * b_info; /* the block */
|
---|
| 43 | int * b_offs; /* line offsets within the block */
|
---|
| 44 | long b_foff; /* offset of block in file */
|
---|
| 45 | };
|
---|
| 46 |
|
---|
| 47 | static struct block * blocklist, /* beginning of the list of blocks */
|
---|
| 48 | * maxblocklist, /* first free entry in the list */
|
---|
| 49 | * topblocklist; /* end of allocated core for the list */
|
---|
| 50 | static int b_head,
|
---|
| 51 | b_tail;
|
---|
| 52 | static int tfdes, ifdes; /* File descriptors for temporary's */
|
---|
| 53 | static long lastreadline; /* lineno of last line read */
|
---|
| 54 | static int ENDseen;
|
---|
| 55 |
|
---|
| 56 | STATIC VOID readblock();
|
---|
| 57 | STATIC VOID nextblock();
|
---|
| 58 | STATIC char *re_alloc();
|
---|
| 59 |
|
---|
| 60 | STATIC struct block *
|
---|
| 61 | new_block()
|
---|
| 62 | {
|
---|
| 63 | register struct block *pblock = maxblocklist - 1;
|
---|
| 64 |
|
---|
| 65 | if (!maxblocklist || !(pblock->b_flags & PARTLY)) {
|
---|
| 66 | /*
|
---|
| 67 | * There is no last block, or it was filled completely,
|
---|
| 68 | * so allocate a new blockheader.
|
---|
| 69 | */
|
---|
| 70 | register int siz;
|
---|
| 71 |
|
---|
| 72 | pblock = blocklist;
|
---|
| 73 | if (maxblocklist == topblocklist) {
|
---|
| 74 | /*
|
---|
| 75 | * No blockheaders left. Allocate new ones
|
---|
| 76 | */
|
---|
| 77 | siz = topblocklist - pblock;
|
---|
| 78 | blocklist = pblock = (struct block *)
|
---|
| 79 | re_alloc((char *) pblock,
|
---|
| 80 | (unsigned) (siz * sizeof(*pblock)),
|
---|
| 81 | (unsigned) ((siz + CHUNK) * sizeof(*pblock)));
|
---|
| 82 | pblock += siz;
|
---|
| 83 | topblocklist = pblock + CHUNK;
|
---|
| 84 | maxblocklist = pblock;
|
---|
| 85 | for (; pblock < topblocklist; pblock++) {
|
---|
| 86 | pblock->b_end = 0;
|
---|
| 87 | pblock->b_info = 0;
|
---|
| 88 | pblock->b_flags = 0;
|
---|
| 89 | }
|
---|
| 90 | if (!siz) {
|
---|
| 91 | /*
|
---|
| 92 | * Create dummy header cell.
|
---|
| 93 | */
|
---|
| 94 | maxblocklist++;
|
---|
| 95 | }
|
---|
| 96 | }
|
---|
| 97 | pblock = maxblocklist++;
|
---|
| 98 | }
|
---|
| 99 | nextblock(pblock);
|
---|
| 100 | return pblock;
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 | /*
|
---|
| 104 | * Return the block in which line 'n' of the current file can be found.
|
---|
| 105 | * If "disable_interrupt" = 0, the call may be interrupted, in which
|
---|
| 106 | * case it returns 0.
|
---|
| 107 | */
|
---|
| 108 |
|
---|
| 109 | STATIC struct block *
|
---|
| 110 | getblock(n, disable_interrupt) register long n; {
|
---|
| 111 | register struct block * pblock;
|
---|
| 112 |
|
---|
| 113 | if (stdf < 0) {
|
---|
| 114 | /*
|
---|
| 115 | * Not file descriptor, so return end of file
|
---|
| 116 | */
|
---|
| 117 | return 0;
|
---|
| 118 | }
|
---|
| 119 | pblock = maxblocklist - 1;
|
---|
| 120 | if (n < lastreadline ||
|
---|
| 121 | (n == lastreadline && !(pblock->b_flags & PARTLY))) {
|
---|
| 122 | /*
|
---|
| 123 | * The line asked for has been read already.
|
---|
| 124 | * Perform binary search in the blocklist to find the block
|
---|
| 125 | * where it's in.
|
---|
| 126 | */
|
---|
| 127 | register struct block *min, *mid;
|
---|
| 128 |
|
---|
| 129 | min = blocklist + 1;
|
---|
| 130 | do {
|
---|
| 131 | mid = min + (pblock - min) / 2;
|
---|
| 132 | if (n > mid->b_end) {
|
---|
| 133 | min = mid + 1;
|
---|
| 134 | }
|
---|
| 135 | else pblock = mid;
|
---|
| 136 | } while (min < pblock);
|
---|
| 137 | /* Found, pblock is now a reference to the block wanted */
|
---|
| 138 | if (!pblock->b_info) readblock(pblock);
|
---|
| 139 | return pblock;
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | /*
|
---|
| 143 | * The line was'nt read yet, so read blocks until found
|
---|
| 144 | */
|
---|
| 145 | for (;;) {
|
---|
| 146 | if (interrupt && !disable_interrupt) return 0;
|
---|
| 147 | pblock = new_block();
|
---|
| 148 | if (pblock->b_end >= n) {
|
---|
| 149 | return pblock;
|
---|
| 150 | }
|
---|
| 151 | if (pblock->b_flags & PARTLY) {
|
---|
| 152 | /*
|
---|
| 153 | * We did not find it, and the last block could not be
|
---|
| 154 | * read completely, so return 0;
|
---|
| 155 | */
|
---|
| 156 | return 0;
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 | /* NOTREACHED */
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | char *
|
---|
| 163 | getline(n, disable_interrupt) long n; {
|
---|
| 164 | register struct block *pblock;
|
---|
| 165 |
|
---|
| 166 | if (!(pblock = getblock(n, disable_interrupt))) {
|
---|
| 167 | return (char *) 0;
|
---|
| 168 | }
|
---|
| 169 | return pblock->b_info + pblock->b_offs[n - ((pblock-1)->b_end + 1)];
|
---|
| 170 | }
|
---|
| 171 |
|
---|
| 172 | /*
|
---|
| 173 | * Find the last line of the input, and return its number
|
---|
| 174 | */
|
---|
| 175 |
|
---|
| 176 | long
|
---|
| 177 | to_lastline() {
|
---|
| 178 |
|
---|
| 179 | for (;;) {
|
---|
| 180 | if (!getline(lastreadline + 1, 0)) {
|
---|
| 181 | /*
|
---|
| 182 | * "lastreadline" always contains the linenumber of
|
---|
| 183 | * the last line read. So, if the call to getline
|
---|
| 184 | * succeeds, "lastreadline" is affected
|
---|
| 185 | */
|
---|
| 186 | if (interrupt) return -1L;
|
---|
| 187 | return lastreadline;
|
---|
| 188 | }
|
---|
| 189 | }
|
---|
| 190 | /* NOTREACHED */
|
---|
| 191 | }
|
---|
| 192 |
|
---|
| 193 | #if MAXNBLOCKS
|
---|
| 194 | int nblocks; /* Count number of large blocks */
|
---|
| 195 | #endif
|
---|
| 196 |
|
---|
| 197 | /*
|
---|
| 198 | * Allocate some memory. If unavailable, free some and try again.
|
---|
| 199 | * If all fails, panic.
|
---|
| 200 | */
|
---|
| 201 |
|
---|
| 202 | char *
|
---|
| 203 | alloc(size, isblock) unsigned size; {
|
---|
| 204 |
|
---|
| 205 | register char *pmem;
|
---|
| 206 | register struct block *pblock, *bllist;
|
---|
| 207 | char *malloc();
|
---|
| 208 | long lseek();
|
---|
| 209 | register long i;
|
---|
| 210 |
|
---|
| 211 | bllist = blocklist;
|
---|
| 212 | while (
|
---|
| 213 | #if MAXNBLOCKS
|
---|
| 214 | (isblock && nblocks >= MAXNBLOCKS) ||
|
---|
| 215 | #endif
|
---|
| 216 | !(pmem = malloc(size)) /* No space */
|
---|
| 217 | ) {
|
---|
| 218 | if (b_tail == 0) {
|
---|
| 219 | /*
|
---|
| 220 | * Also, no blocks in core. Pity
|
---|
| 221 | */
|
---|
| 222 | panic("No core");
|
---|
| 223 | }
|
---|
| 224 | #if MAXNBLOCKS
|
---|
| 225 | nblocks--;
|
---|
| 226 | #endif
|
---|
| 227 | pblock = bllist + b_tail;
|
---|
| 228 | b_tail = pblock->b_next;
|
---|
| 229 | if (!nopipe && !(pblock->b_flags & DUMPED)) {
|
---|
| 230 | /*
|
---|
| 231 | * Dump the block on a temporary file
|
---|
| 232 | */
|
---|
| 233 | if (!tfdes) {
|
---|
| 234 | /*
|
---|
| 235 | * create and open temporary files
|
---|
| 236 | */
|
---|
| 237 | tfdes = opentemp(0);
|
---|
| 238 | ifdes = opentemp(1);
|
---|
| 239 | }
|
---|
| 240 | pblock->b_flags |= DUMPED;
|
---|
| 241 | /*
|
---|
| 242 | * Find out where to dump the block, and dump it
|
---|
| 243 | */
|
---|
| 244 | i = (pblock-1)->b_end * sizeof(int);
|
---|
| 245 | (VOID) lseek(tfdes,
|
---|
| 246 | ((long) BLOCKSIZE * (pblock - bllist)), 0);
|
---|
| 247 | if (write(tfdes, pblock->b_info, BLOCKSIZE)
|
---|
| 248 | != BLOCKSIZE) {
|
---|
| 249 | panic("write failed");
|
---|
| 250 | }
|
---|
| 251 | /*
|
---|
| 252 | * Also dump the offsets of the lines in the block
|
---|
| 253 | */
|
---|
| 254 | (VOID) lseek(ifdes, i, 0);
|
---|
| 255 | i = pblock->b_end * sizeof(int) - i;
|
---|
| 256 | if (write(ifdes, (char *) pblock->b_offs, (int) i)
|
---|
| 257 | != (int) i) {
|
---|
| 258 | panic("Write failed");
|
---|
| 259 | }
|
---|
| 260 | }
|
---|
| 261 | /*
|
---|
| 262 | * Now that the block is dumped, the space taken by it can
|
---|
| 263 | * be freed
|
---|
| 264 | */
|
---|
| 265 | free((char *) pblock->b_offs);
|
---|
| 266 | free(pblock->b_info);
|
---|
| 267 | pblock->b_info = (char *) 0;
|
---|
| 268 | }
|
---|
| 269 | #if MAXNBLOCKS
|
---|
| 270 | if (isblock) nblocks++;
|
---|
| 271 | #endif
|
---|
| 272 | return pmem;
|
---|
| 273 | }
|
---|
| 274 |
|
---|
| 275 | /*
|
---|
| 276 | * Re-allocate the memorychunk pointed to by ptr, to let it
|
---|
| 277 | * grow or shrink.
|
---|
| 278 | * realloc of the standard C library is useless, as it is destructive
|
---|
| 279 | * if the malloc fails.
|
---|
| 280 | */
|
---|
| 281 |
|
---|
| 282 | STATIC char *
|
---|
| 283 | re_alloc(ptr,oldsize, newsize)
|
---|
| 284 | char *ptr; unsigned oldsize; unsigned newsize; {
|
---|
| 285 | register char *pmem;
|
---|
| 286 | register char *c1, *c2;
|
---|
| 287 |
|
---|
| 288 | /*
|
---|
| 289 | * We could be smarter here, by checking if newsize < oldsize, and in
|
---|
| 290 | * that case using realloc, but this depends on realloc using the
|
---|
| 291 | * same block if the block shrinks. The question is, wether all
|
---|
| 292 | * reallocs in the world do this.
|
---|
| 293 | */
|
---|
| 294 | pmem = alloc(newsize, 0);
|
---|
| 295 | if (oldsize) {
|
---|
| 296 | /*
|
---|
| 297 | * This test makes re_alloc also work if there was no old block
|
---|
| 298 | */
|
---|
| 299 | c1 = pmem;
|
---|
| 300 | c2 = ptr;
|
---|
| 301 | if (newsize > oldsize) {
|
---|
| 302 | newsize = oldsize;
|
---|
| 303 | }
|
---|
| 304 | while (newsize--) {
|
---|
| 305 | *c1++ = *c2++;
|
---|
| 306 | }
|
---|
| 307 | free(ptr);
|
---|
| 308 | }
|
---|
| 309 | return pmem;
|
---|
| 310 | }
|
---|
| 311 |
|
---|
| 312 | /*
|
---|
| 313 | * Append a block to the linked list of blockheaders of blocks that are
|
---|
| 314 | * in core.
|
---|
| 315 | */
|
---|
| 316 |
|
---|
| 317 | STATIC VOID
|
---|
| 318 | addtolist(pblock) register struct block *pblock; {
|
---|
| 319 | register struct block *bllist = blocklist;
|
---|
| 320 |
|
---|
| 321 | pblock->b_next = 0;
|
---|
| 322 | (bllist + b_head)->b_next = pblock - bllist;
|
---|
| 323 | b_head = pblock - bllist;
|
---|
| 324 | if (!b_tail) {
|
---|
| 325 | /*
|
---|
| 326 | * The list was empty, initialize
|
---|
| 327 | */
|
---|
| 328 | b_tail = b_head;
|
---|
| 329 | }
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | static char *saved;
|
---|
| 333 | static long filldegree;
|
---|
| 334 |
|
---|
| 335 | /*
|
---|
| 336 | * Try to read the block indicated by pblock
|
---|
| 337 | */
|
---|
| 338 |
|
---|
| 339 | STATIC VOID
|
---|
| 340 | nextblock(pblock) register struct block *pblock; {
|
---|
| 341 | register char *c, /* Run through pblock->b_info */
|
---|
| 342 | *c1; /* indicate end of pblock->b_info */
|
---|
| 343 | register int *poff; /* pointer in line-offset list */
|
---|
| 344 | register int cnt; /* # of characters read */
|
---|
| 345 | register unsigned siz; /* Size of allocated line-offset list */
|
---|
| 346 | static unsigned savedsiz; /* saved "siz" */
|
---|
| 347 | static int *savedpoff; /* saved "poff" */
|
---|
| 348 | static char *savedc1; /* saved "c1" */
|
---|
| 349 |
|
---|
| 350 | if (pblock->b_flags & PARTLY) {
|
---|
| 351 | /*
|
---|
| 352 | * The block was already partly filled. Initialize locals
|
---|
| 353 | * accordingly
|
---|
| 354 | */
|
---|
| 355 | poff = savedpoff;
|
---|
| 356 | siz = savedsiz;
|
---|
| 357 | pblock->b_flags = 0;
|
---|
| 358 | c1 = savedc1;
|
---|
| 359 | if (c1 == pblock->b_info || *(c1 - 1)) {
|
---|
| 360 | /*
|
---|
| 361 | * We had incremented "lastreadline" temporarily,
|
---|
| 362 | * because the last line could not be completely read
|
---|
| 363 | * last time we tried. Undo this increment
|
---|
| 364 | */
|
---|
| 365 | poff--;
|
---|
| 366 | --lastreadline;
|
---|
| 367 | }
|
---|
| 368 | }
|
---|
| 369 | else {
|
---|
| 370 | if (nopipe) pblock->b_foff = lseek(stdf, 0L, 1);
|
---|
| 371 | if (saved) {
|
---|
| 372 | /*
|
---|
| 373 | * There were leftovers from the previous block
|
---|
| 374 | */
|
---|
| 375 | pblock->b_info = saved;
|
---|
| 376 | if (nopipe) pblock->b_foff -= savedc1 - saved;
|
---|
| 377 | c1 = savedc1;
|
---|
| 378 | saved = 0;
|
---|
| 379 | }
|
---|
| 380 | else { /* Allocate new block */
|
---|
| 381 | pblock->b_info = c1 = alloc(BLOCKSIZE + 1, 1);
|
---|
| 382 | }
|
---|
| 383 | /*
|
---|
| 384 | * Allocate some space for line-offsets
|
---|
| 385 | */
|
---|
| 386 | pblock->b_offs = poff = (int *)
|
---|
| 387 | alloc((unsigned) (100 * sizeof(int)), 0);
|
---|
| 388 | siz = 99;
|
---|
| 389 | *poff++ = 0;
|
---|
| 390 | }
|
---|
| 391 | c = c1;
|
---|
| 392 | for (;;) {
|
---|
| 393 | /*
|
---|
| 394 | * Read loop
|
---|
| 395 | */
|
---|
| 396 | cnt = read(stdf, c1, BLOCKSIZE - (c1 - pblock->b_info));
|
---|
| 397 | if (cnt < 0) {
|
---|
| 398 | /*
|
---|
| 399 | * Interrupted read
|
---|
| 400 | */
|
---|
| 401 | if (errno == EINTR) continue;
|
---|
| 402 | error("Could not read input file");
|
---|
| 403 | cnt = 0;
|
---|
| 404 | }
|
---|
| 405 | c1 += cnt;
|
---|
| 406 | if (c1 != pblock->b_info + BLOCKSIZE) {
|
---|
| 407 | ENDseen = 1;
|
---|
| 408 | pblock->b_flags |= PARTLY;
|
---|
| 409 | }
|
---|
| 410 | break;
|
---|
| 411 | }
|
---|
| 412 | assert(c <= c1);
|
---|
| 413 | while (c < c1) {
|
---|
| 414 | /*
|
---|
| 415 | * Now process the block
|
---|
| 416 | */
|
---|
| 417 | *c &= 0177; /* Most significant bit ignored */
|
---|
| 418 | if (*c == '\n') {
|
---|
| 419 | /*
|
---|
| 420 | * Newlines are replaced by '\0', so that "getline"
|
---|
| 421 | * can deliver one line at a time
|
---|
| 422 | */
|
---|
| 423 | *c = 0;
|
---|
| 424 | lastreadline++;
|
---|
| 425 | /*
|
---|
| 426 | * Remember the line-offset
|
---|
| 427 | */
|
---|
| 428 | if (poff == pblock->b_offs + siz) {
|
---|
| 429 | /*
|
---|
| 430 | * No space for it, allocate some more
|
---|
| 431 | */
|
---|
| 432 | pblock->b_offs = (int *)
|
---|
| 433 | re_alloc((char *) pblock->b_offs,
|
---|
| 434 | (siz+1) * sizeof(int),
|
---|
| 435 | (siz + 51) * sizeof(int));
|
---|
| 436 | poff = pblock->b_offs + siz;
|
---|
| 437 | siz += 50;
|
---|
| 438 | }
|
---|
| 439 | *poff++ = c - pblock->b_info + 1;
|
---|
| 440 | }
|
---|
| 441 | else if (*c == '\0') {
|
---|
| 442 | /*
|
---|
| 443 | * 0-bytes are replaced by 0200, because newlines are
|
---|
| 444 | * replaced by 0, and 0200 & 0177 gives again 0 ...
|
---|
| 445 | */
|
---|
| 446 | *c = 0200;
|
---|
| 447 | }
|
---|
| 448 | c++;
|
---|
| 449 | }
|
---|
| 450 | assert(c==c1);
|
---|
| 451 | *c = 0;
|
---|
| 452 | if (c != pblock->b_info && *(c-1) != 0) {
|
---|
| 453 | /*
|
---|
| 454 | * The last line read does not end with a newline, so add one
|
---|
| 455 | */
|
---|
| 456 | lastreadline++;
|
---|
| 457 | *poff++ = c - pblock->b_info + 1;
|
---|
| 458 | if (!(pblock->b_flags & PARTLY) && *(poff - 2) != 0) {
|
---|
| 459 | /*
|
---|
| 460 | * Save the started line; it will be in the next block.
|
---|
| 461 | * Remove the newline we added just now.
|
---|
| 462 | */
|
---|
| 463 | saved = c1 = alloc(BLOCKSIZE + 1, 1);
|
---|
| 464 | c = pblock->b_info + *(--poff - 1);
|
---|
| 465 | while (*c) *c1++ = *c++;
|
---|
| 466 | c = pblock->b_info + *(poff - 1);
|
---|
| 467 | savedc1 = c1;
|
---|
| 468 | --lastreadline;
|
---|
| 469 | }
|
---|
| 470 | }
|
---|
| 471 | pblock->b_end = lastreadline;
|
---|
| 472 | if (pblock->b_flags & PARTLY) {
|
---|
| 473 | /*
|
---|
| 474 | * Take care, that we can call "nextblock" again, to fill in
|
---|
| 475 | * the rest of this block
|
---|
| 476 | */
|
---|
| 477 | savedsiz = siz;
|
---|
| 478 | savedpoff = poff;
|
---|
| 479 | savedc1 = c;
|
---|
| 480 | if (c == pblock->b_info) {
|
---|
| 481 | lastreadline++;
|
---|
| 482 | pblock->b_end = 0;
|
---|
| 483 | }
|
---|
| 484 | }
|
---|
| 485 | else {
|
---|
| 486 | /*
|
---|
| 487 | * Not completely read blocks are not in the linked list,
|
---|
| 488 | * so can never be "swapped out".
|
---|
| 489 | */
|
---|
| 490 | addtolist(pblock);
|
---|
| 491 | cnt = pblock - blocklist;
|
---|
| 492 | filldegree = ((c-pblock->b_info) + (cnt-1) * filldegree) / cnt;
|
---|
| 493 | }
|
---|
| 494 | assert(pblock->b_end - (pblock-1)->b_end <= poff - pblock->b_offs);
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | /*
|
---|
| 498 | * Allocate core for the block, and read it back from
|
---|
| 499 | * the temporary file.
|
---|
| 500 | */
|
---|
| 501 |
|
---|
| 502 | STATIC VOID
|
---|
| 503 | readblock(pblock) register struct block *pblock; {
|
---|
| 504 |
|
---|
| 505 | register int size;
|
---|
| 506 | register long i;
|
---|
| 507 |
|
---|
| 508 | /*
|
---|
| 509 | * Find out where the block is, and read it
|
---|
| 510 | */
|
---|
| 511 | pblock->b_info = alloc(BLOCKSIZE + 1, 1);
|
---|
| 512 | i = (pblock - 1)->b_end * sizeof(int);
|
---|
| 513 | size = (int) (pblock->b_end * sizeof(int) - i);
|
---|
| 514 | pblock->b_offs = (int *) alloc((unsigned) size, 0);
|
---|
| 515 | if (nopipe) {
|
---|
| 516 | register char *c;
|
---|
| 517 | register int line_index;
|
---|
| 518 | int cnt;
|
---|
| 519 | long l = lseek(stdf, 0L, 1);
|
---|
| 520 |
|
---|
| 521 | (VOID) lseek(stdf, pblock->b_foff, 0);
|
---|
| 522 | cnt = read(stdf, pblock->b_info, BLOCKSIZE);
|
---|
| 523 | (VOID) lseek(stdf, l, 0);
|
---|
| 524 | c = pblock->b_info;
|
---|
| 525 | pblock->b_offs[0] = 0;
|
---|
| 526 | line_index = 1;
|
---|
| 527 | size /= sizeof(int);
|
---|
| 528 | while (c < pblock->b_info + cnt) {
|
---|
| 529 | *c &= 0177;
|
---|
| 530 | if (*c == '\n') {
|
---|
| 531 | *c = '\0';
|
---|
| 532 | if (line_index < size)
|
---|
| 533 | pblock->b_offs[line_index++] =
|
---|
| 534 | (c - pblock->b_info) + 1;
|
---|
| 535 | }
|
---|
| 536 | else if (*c == '\0') *c = 0200;
|
---|
| 537 | c++;
|
---|
| 538 | }
|
---|
| 539 | *c = '\0';
|
---|
| 540 | }
|
---|
| 541 | else {
|
---|
| 542 | (VOID) lseek(tfdes, (long) ((long) BLOCKSIZE * (pblock - blocklist)),0);
|
---|
| 543 | if (read(tfdes, pblock->b_info,BLOCKSIZE) != BLOCKSIZE) {
|
---|
| 544 | panic("read error");
|
---|
| 545 | }
|
---|
| 546 | /*
|
---|
| 547 | * Find out where the line-offset list is, and read it
|
---|
| 548 | */
|
---|
| 549 | (VOID) lseek(ifdes, i, 0);
|
---|
| 550 | if (read(ifdes, (char *) pblock->b_offs, size) != size) {
|
---|
| 551 | panic("read error");
|
---|
| 552 | }
|
---|
| 553 | pblock->b_info[BLOCKSIZE] = '\0';
|
---|
| 554 | }
|
---|
| 555 | /*
|
---|
| 556 | * Add this block to the list of incore blocks
|
---|
| 557 | */
|
---|
| 558 | addtolist(pblock);
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 | /*
|
---|
| 562 | * Called after processing a file.
|
---|
| 563 | * Free all core.
|
---|
| 564 | */
|
---|
| 565 |
|
---|
| 566 | VOID
|
---|
| 567 | do_clean() {
|
---|
| 568 |
|
---|
| 569 | register struct block *pblock;
|
---|
| 570 | register char *p;
|
---|
| 571 |
|
---|
| 572 | for (pblock = blocklist; pblock < maxblocklist; pblock++) {
|
---|
| 573 | if (p = pblock->b_info) {
|
---|
| 574 | free(p);
|
---|
| 575 | free((char *) pblock->b_offs);
|
---|
| 576 | }
|
---|
| 577 | }
|
---|
| 578 | if (p = (char *) blocklist) {
|
---|
| 579 | free(p);
|
---|
| 580 | }
|
---|
| 581 | blocklist = 0;
|
---|
| 582 | maxblocklist = 0;
|
---|
| 583 | topblocklist = 0;
|
---|
| 584 | lastreadline = 0;
|
---|
| 585 | filldegree = 0;
|
---|
| 586 | ENDseen = 0;
|
---|
| 587 | if (p = saved) free(p);
|
---|
| 588 | saved = 0;
|
---|
| 589 | b_head = 0;
|
---|
| 590 | b_tail = 0;
|
---|
| 591 | # if MAXNBLOCKS
|
---|
| 592 | nblocks = 0;
|
---|
| 593 | # endif
|
---|
| 594 | }
|
---|
| 595 |
|
---|
| 596 | /*
|
---|
| 597 | * Close a file with file-descriptor "file", if it indeed is one
|
---|
| 598 | */
|
---|
| 599 |
|
---|
| 600 | STATIC VOID
|
---|
| 601 | cls(file) {
|
---|
| 602 | if (file) (VOID) close(file);
|
---|
| 603 | }
|
---|
| 604 |
|
---|
| 605 | /*
|
---|
| 606 | * Close all files
|
---|
| 607 | */
|
---|
| 608 |
|
---|
| 609 | VOID
|
---|
| 610 | cls_files() {
|
---|
| 611 |
|
---|
| 612 | cls(tfdes);
|
---|
| 613 | cls(ifdes);
|
---|
| 614 | cls(stdf);
|
---|
| 615 | }
|
---|
| 616 |
|
---|
| 617 | /*
|
---|
| 618 | * Get a character. If possible, do some workahead.
|
---|
| 619 | */
|
---|
| 620 |
|
---|
| 621 | int
|
---|
| 622 | getch() {
|
---|
| 623 | # if USG_OPEN
|
---|
| 624 | # include <fcntl.h>
|
---|
| 625 | # include <sys/stat.h>
|
---|
| 626 |
|
---|
| 627 | register int i,j;
|
---|
| 628 | struct stat buf;
|
---|
| 629 | # else
|
---|
| 630 | # ifdef FIONREAD
|
---|
| 631 | # include <sys/stat.h>
|
---|
| 632 |
|
---|
| 633 | struct stat buf;
|
---|
| 634 | long i;
|
---|
| 635 | # endif
|
---|
| 636 | # endif
|
---|
| 637 |
|
---|
| 638 | char c;
|
---|
| 639 | int retval;
|
---|
| 640 |
|
---|
| 641 | flush();
|
---|
| 642 | if (startcomm) {
|
---|
| 643 | /*
|
---|
| 644 | * Command line option command
|
---|
| 645 | */
|
---|
| 646 | if (*startcomm) return *startcomm++;
|
---|
| 647 | return '\n';
|
---|
| 648 | }
|
---|
| 649 | # if USG_OPEN
|
---|
| 650 | if (stdf >= 0) {
|
---|
| 651 | /*
|
---|
| 652 | * Make reads from the terminal non-blocking, so that
|
---|
| 653 | * we can see if the user typed something
|
---|
| 654 | */
|
---|
| 655 | i = fcntl(0,F_GETFL,0);
|
---|
| 656 | if (i != -1 && fcntl(0, F_SETFL, i|O_NDELAY) != -1) {
|
---|
| 657 | j = 0;
|
---|
| 658 | while (! ENDseen &&
|
---|
| 659 | ((j = read(0,&c,1)) == 0
|
---|
| 660 | #ifdef EWOULDBLOCK
|
---|
| 661 | || (j < 0 && errno == EWOULDBLOCK)
|
---|
| 662 | #endif
|
---|
| 663 | )
|
---|
| 664 | &&
|
---|
| 665 | (nopipe ||
|
---|
| 666 | (fstat(stdf,&buf) >= 0 && buf.st_size > 0))) {
|
---|
| 667 | /*
|
---|
| 668 | * Do some read ahead, after making sure there
|
---|
| 669 | * is input and the user did not type a command
|
---|
| 670 | */
|
---|
| 671 | new_block();
|
---|
| 672 | }
|
---|
| 673 | (VOID) fcntl(0,F_SETFL,i);
|
---|
| 674 | if (j < 0) {
|
---|
| 675 | /*
|
---|
| 676 | * Could this have happened?
|
---|
| 677 | * I'm not sure, because the read is
|
---|
| 678 | * nonblocking. Can it be interrupted then?
|
---|
| 679 | */
|
---|
| 680 | return -1;
|
---|
| 681 | }
|
---|
| 682 | if (j > 0) return c;
|
---|
| 683 | }
|
---|
| 684 | }
|
---|
| 685 | # else
|
---|
| 686 | # ifdef FIONREAD
|
---|
| 687 | if (stdf >= 0) {
|
---|
| 688 | /*
|
---|
| 689 | * See if there are any characters waiting in the terminal input
|
---|
| 690 | * queue. If there are not, read ahead.
|
---|
| 691 | */
|
---|
| 692 | while (! ENDseen &&
|
---|
| 693 | ( ioctl(0, FIONREAD, (char *) &i) >= 0 && i == 0) &&
|
---|
| 694 | ( nopipe || fstat(stdf,&buf) >= 0 && buf.st_size > 0)) {
|
---|
| 695 | /*
|
---|
| 696 | * While the user does'nt type anything, and there is
|
---|
| 697 | * input to be processed, work ahead
|
---|
| 698 | */
|
---|
| 699 | if (interrupt) return -1;
|
---|
| 700 | new_block();
|
---|
| 701 | }
|
---|
| 702 | }
|
---|
| 703 | # endif
|
---|
| 704 | # endif
|
---|
| 705 | if (read(0,&c,1) <= 0) retval = -1; else retval = c & 0177;
|
---|
| 706 | return retval;
|
---|
| 707 | }
|
---|
| 708 |
|
---|
| 709 | /*
|
---|
| 710 | * Get the position of line "ln" in the file.
|
---|
| 711 | */
|
---|
| 712 |
|
---|
| 713 | long
|
---|
| 714 | getpos(ln) long ln; {
|
---|
| 715 | register struct block *pblock;
|
---|
| 716 | register long i;
|
---|
| 717 |
|
---|
| 718 | pblock = getblock(ln,1);
|
---|
| 719 | assert(pblock != 0);
|
---|
| 720 | i = filldegree * (pblock - blocklist);
|
---|
| 721 | return i - (filldegree - pblock->b_offs[ln - (pblock-1)->b_end]);
|
---|
| 722 | }
|
---|