sources-request@mirror.UUCP (11/06/86)
Submitted by: seismo!rick (Rick Adams) Mod.sources: Volume 7, Issue 52 Archive-name: 2.11news/Part12 # To extract, sh this file # # news 2.11 source part 2 of 9 # if test ! -d src then mkdir src fi echo x - src/compress.c 1>&2 sed 's/.//' >src/compress.c <<'*-*-END-of-src/compress.c-*-*' -#ifdef SCCSID -static char *SccsId = "@(#)compress.c 1.12 10/29/86"; -#endif SCCSID -static char rcs_ident[] = "Based on compress.c,v 4.0 85/07/30 12:50:00 joe Release"; - -/* - * Compress - data compression program - */ -#define min(a,b) ((a>b) ? b : a) - -/* - * machine variants which require cc -Dmachine: pdp11, z8000, pcxt - */ - -/* - * Set USERMEM to the maximum amount of physical user memory available - * in bytes. USERMEM is used to determine the maximum BITS that can be used - * for compression. - * - * SACREDMEM is the amount of physical memory saved for others; compress - * will hog the rest. - */ -#ifndef SACREDMEM -#define SACREDMEM 0 -#endif - -#ifndef USERMEM -# define USERMEM 450000 /* default user memory */ -#endif - -#ifdef interdata /* (Perkin-Elmer) */ -#define SIGNED_COMPARE_SLOW /* signed compare is slower than unsigned */ -#endif - -#ifdef pdp11 -# define BITS 12 /* max bits/code for 16-bit machine */ -# define NO_UCHAR /* also if "unsigned char" functions as signed char */ -# undef USERMEM -#endif /* pdp11 */ /* don't forget to compile with -i */ - -#ifdef z8000 -# define BITS 12 -# undef vax /* weird preprocessor */ -# undef USERMEM -#endif /* z8000 */ - -#ifdef pcxt -# define BITS 12 -# undef USERMEM -#endif /* pcxt */ - -#ifdef USERMEM -# if USERMEM >= (433484+SACREDMEM) -# define PBITS 16 -# else -# if USERMEM >= (229600+SACREDMEM) -# define PBITS 15 -# else -# if USERMEM >= (127536+SACREDMEM) -# define PBITS 14 -# else -# if USERMEM >= (73464+SACREDMEM) -# define PBITS 13 -# else -# define PBITS 12 -# endif -# endif -# endif -# endif -# undef USERMEM -#endif /* USERMEM */ - -#ifdef PBITS /* Preferred BITS for this memory size */ -# ifndef BITS -# define BITS PBITS -# endif BITS -#endif /* PBITS */ - -#if BITS == 16 -# define HSIZE 69001 /* 95% occupancy */ -#endif -#if BITS == 15 -# define HSIZE 35023 /* 94% occupancy */ -#endif -#if BITS == 14 -# define HSIZE 18013 /* 91% occupancy */ -#endif -#if BITS == 13 -# define HSIZE 9001 /* 91% occupancy */ -#endif -#if BITS <= 12 -# define HSIZE 5003 /* 80% occupancy */ -#endif - -#ifdef M_XENIX /* Stupid compiler can't handle arrays with */ -# if BITS == 16 /* more than 65535 bytes - so we fake it */ -# define XENIX_16 -# else -# if BITS > 13 /* Code only handles BITS = 12, 13, or 16 */ -# define BITS 13 -# endif -# endif -#endif - -/* - * a code_int must be able to hold 2**BITS values of type int, and also -1 - */ -#if BITS > 15 -typedef long int code_int; -#else -typedef int code_int; -#endif - -#ifdef SIGNED_COMPARE_SLOW -typedef unsigned long int count_int; -typedef unsigned short int count_short; -#else -typedef long int count_int; -#endif - -#ifdef NO_UCHAR - typedef char char_type; -#else - typedef unsigned char char_type; -#endif /* UCHAR */ -char_type magic_header[] = { "\037\235" }; /* 1F 9D */ - -/* Defines for third byte of header */ -#define BIT_MASK 0x1f -#define BLOCK_MASK 0x80 -/* Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is - a fourth header byte (for expansion). -*/ -#define INIT_BITS 9 /* initial number of bits/code */ - -/* - * compress.c - File compression ala IEEE Computer, June 1984. - * - * Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) - * Jim McKie (decvax!mcvax!jim) - * Steve Davies (decvax!vax135!petsd!peora!srd) - * Ken Turkowski (decvax!decwrl!turtlevax!ken) - * James A. Woods (decvax!ihnp4!ames!jaw) - * Joe Orost (decvax!vax135!petsd!joe) - * - */ - -#include <stdio.h> -#include <ctype.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> - -#define ARGVAL() (*++(*argv) || (--argc && *++argv)) - -int n_bits; /* number of bits/code */ -int maxbits = BITS; /* user settable max # bits/code */ -code_int maxcode; /* maximum code, given n_bits */ -code_int maxmaxcode = 1L << BITS; /* should NEVER generate this code */ -#ifdef COMPATIBLE /* But wrong! */ -# define MAXCODE(n_bits) (1 << (n_bits) - 1) -#else -# define MAXCODE(n_bits) ((1 << (n_bits)) - 1) -#endif /* COMPATIBLE */ - -#ifdef XENIX_16 -count_int htab0[8192]; -count_int htab1[8192]; -count_int htab2[8192]; -count_int htab3[8192]; -count_int htab4[8192]; -count_int htab5[8192]; -count_int htab6[8192]; -count_int htab7[8192]; -count_int htab8[HSIZE-65536]; -count_int * htab[9] = { - htab0, htab1, htab2, htab3, htab4, htab5, htab6, htab7, htab8 }; - -#define htabof(i) (htab[(i) >> 13][(i) & 0x1fff]) -unsigned short code0tab[16384]; -unsigned short code1tab[16384]; -unsigned short code2tab[16384]; -unsigned short code3tab[16384]; -unsigned short code4tab[16384]; -unsigned short * codetab[5] = { - code0tab, code1tab, code2tab, code3tab, code4tab }; - -#define codetabof(i) (codetab[(i) >> 14][(i) & 0x3fff]) - -#else /* Normal machine */ -# ifdef sel -/* support gould base register problems */ -/*NOBASE*/ -count_int htab [HSIZE]; -unsigned short codetab [HSIZE]; -/*NOBASE*/ -# else /* !gould */ -count_int htab [HSIZE]; -unsigned short codetab [HSIZE]; -# endif /* !gould */ -#define htabof(i) htab[i] -#define codetabof(i) codetab[i] -#endif /* !XENIX_16 */ -code_int hsize = HSIZE; /* for dynamic table sizing */ -count_int fsize; - -/* - * To save much memory, we overlay the table used by compress() with those - * used by decompress(). The tab_prefix table is the same size and type - * as the codetab. The tab_suffix table needs 2**BITS characters. We - * get this from the beginning of htab. The output stack uses the rest - * of htab, and contains characters. There is plenty of room for any - * possible stack (stack used to be 8000 characters). - */ - -#define tab_prefixof(i) codetabof(i) -#ifdef XENIX_16 -# define tab_suffixof(i) ((char_type *)htab[(i)>>15])[(i) & 0x7fff] -# define de_stack ((char_type *)(htab2)) -#else /* Normal machine */ -# define tab_suffixof(i) ((char_type *)(htab))[i] -# define de_stack ((char_type *)&tab_suffixof(1<<BITS)) -#endif /* XENIX_16 */ - -code_int free_ent = 0; /* first unused entry */ -int exit_stat = 0; - -code_int getcode(); - -Usage() { -#ifdef DEBUG -fprintf(stderr,"Usage: compress [-dDVfc] [-b maxbits] [file ...]\n"); -} -int debug = 0; -#else -fprintf(stderr,"Usage: compress [-dfvcV] [-b maxbits] [file ...]\n"); -} -#endif /* DEBUG */ -int nomagic = 0; /* Use a 3-byte magic number header, unless old file */ -int zcat_flg = 0; /* Write output on stdout, suppress messages */ -int quiet = 1; /* don't tell me about compression */ - -/* - * block compression parameters -- after all codes are used up, - * and compression rate changes, start over. - */ -int block_compress = BLOCK_MASK; -int clear_flg = 0; -long int ratio = 0; -#define CHECK_GAP 10000 /* ratio check interval */ -count_int checkpoint = CHECK_GAP; -/* - * the next two codes should not be changed lightly, as they must not - * lie within the contiguous general code space. - */ -#define FIRST 257 /* first free entry */ -#define CLEAR 256 /* table clear output code */ - -int force = 0; -char ofname [100]; -#ifdef DEBUG -int verbose = 0; -#endif /* DEBUG */ -int (*bgnd_flag)(); - -int do_decomp = 0; - -/***************************************************************** - * TAG( main ) - * - * Algorithm from "A Technique for High Performance Data Compression", - * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19. - * - * Usage: compress [-dfvc] [-b bits] [file ...] - * Inputs: - * -d: If given, decompression is done instead. - * - * -c: Write output on stdout, don't remove original. - * - * -b: Parameter limits the max number of bits/code. - * - * -f: Forces output file to be generated, even if one already - * exists, and even if no space is saved by compressing. - * If -f is not used, the user will be prompted if stdin is - * a tty, otherwise, the output file will not be overwritten. - * - * -v: Write compression statistics - * - * file ...: Files to be compressed. If none specified, stdin - * is used. - * Outputs: - * file.Z: Compressed form of file with same mode, owner, and utimes - * or stdout (if stdin used as input) - * - * Assumptions: - * When filenames are given, replaces with the compressed version - * (.Z suffix) only if the file decreases in size. - * Algorithm: - * Modified Lempel-Ziv method (LZW). Basically finds common - * substrings and replaces them with a variable size code. This is - * deterministic, and can be done on the fly. Thus, the decompression - * procedure needs no input table, but tracks the way the table was built. - */ - -main( argc, argv ) -register int argc; char **argv; -{ - int overwrite = 0; /* Do not overwrite unless given -f flag */ - char tempname[100]; - char **filelist, **fileptr; - char *cp, *rindex(), *malloc(); - struct stat statbuf; - extern onintr(), oops(); - - - if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) { - signal ( SIGINT, onintr ); - signal ( SIGSEGV, oops ); - } - -#ifdef COMPATIBLE - nomagic = 1; /* Original didn't have a magic number */ -#endif /* COMPATIBLE */ - - filelist = fileptr = (char **)(malloc(argc * sizeof(*argv))); - *filelist = NULL; - - if((cp = rindex(argv[0], '/')) != 0) { - cp++; - } else { - cp = argv[0]; - } - if(strcmp(cp, "uncompress") == 0) { - do_decomp = 1; - } else if(strcmp(cp, "zcat") == 0) { - do_decomp = 1; - zcat_flg = 1; - } - -#ifdef BSD4_2 - /* 4.2BSD dependent - take it out if not */ - setlinebuf( stderr ); -#endif /* BSD4_2 */ - - /* Argument Processing - * All flags are optional. - * -D => debug - * -V => print Version; debug verbose - * -d => do_decomp - * -v => unquiet - * -f => force overwrite of output file - * -n => no header: useful to uncompress old files - * -b maxbits => maxbits. If -b is specified, then maxbits MUST be - * given also. - * -c => cat all output to stdout - * -C => generate output compatible with compress 2.0. - * if a string is left, must be an input filename. - */ - for (argc--, argv++; argc > 0; argc--, argv++) { - if (**argv == '-') { /* A flag argument */ - while (*++(*argv)) { /* Process all flags in this arg */ - switch (**argv) { -#ifdef DEBUG - case 'D': - debug = 1; - break; - case 'V': - verbose = 1; - version(); - break; -#else - case 'V': - version(); - break; -#endif /* DEBUG */ - case 'v': - quiet = 0; - break; - case 'd': - do_decomp = 1; - break; - case 'f': - case 'F': - overwrite = 1; - force = 1; - break; - case 'n': - nomagic = 1; - break; - case 'C': - block_compress = 0; - break; - case 'b': - if (!ARGVAL()) { - fprintf(stderr, "Missing maxbits\n"); - Usage(); - exit(1); - } - maxbits = atoi(*argv); - goto nextarg; - case 'c': - zcat_flg = 1; - break; - case 'q': - quiet = 1; - break; - default: - fprintf(stderr, "Unknown flag: '%c'; ", **argv); - Usage(); - exit(1); - } - } - } - else { /* Input file name */ - *fileptr++ = *argv; /* Build input file list */ - *fileptr = NULL; - /* process nextarg; */ - } - nextarg: continue; - } - - if(maxbits < INIT_BITS) maxbits = INIT_BITS; - if (maxbits > BITS) maxbits = BITS; - maxmaxcode = 1L << maxbits; - - if (*filelist != NULL) { - for (fileptr = filelist; *fileptr; fileptr++) { - exit_stat = 0; - if (do_decomp != 0) { /* DECOMPRESSION */ - /* Check for .Z suffix */ - if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") != 0) { - /* No .Z: tack one on */ - strcpy(tempname, *fileptr); - strcat(tempname, ".Z"); - *fileptr = tempname; - } - /* Open input file */ - if ((freopen(*fileptr, "r", stdin)) == NULL) { - perror(*fileptr); continue; - } - /* Check the magic number */ - if (nomagic == 0) { - if ((getchar() != (magic_header[0] & 0xFF)) - || (getchar() != (magic_header[1] & 0xFF))) { - fprintf(stderr, "%s: not in compressed format\n", - *fileptr); - continue; - } - maxbits = getchar(); /* set -b from file */ - block_compress = maxbits & BLOCK_MASK; - maxbits &= BIT_MASK; - maxmaxcode = 1L << maxbits; - if(maxbits > BITS) { - fprintf(stderr, - "%s: compressed with %d bits, can only handle %d bits\n", - *fileptr, maxbits, BITS); - continue; - } - } - /* Generate output filename */ - strcpy(ofname, *fileptr); - ofname[strlen(*fileptr) - 2] = '\0'; /* Strip off .Z */ - } else { /* COMPRESSION */ - if (strcmp(*fileptr + strlen(*fileptr) - 2, ".Z") == 0) { - fprintf(stderr, "%s: already has .Z suffix -- no change\n", - *fileptr); - continue; - } - /* Open input file */ - if ((freopen(*fileptr, "r", stdin)) == NULL) { - perror(*fileptr); continue; - } - stat ( *fileptr, &statbuf ); - fsize = (long) statbuf.st_size; - /* - * tune hash table size for small files -- ad hoc, - * but the sizes match earlier #defines, which - * serve as upper bounds on the number of output codes. - */ - hsize = HSIZE; - if ( fsize < (1 << 12) ) - hsize = min ( 5003, HSIZE ); - else if ( fsize < (1 << 13) ) - hsize = min ( 9001, HSIZE ); - else if ( fsize < (1 << 14) ) - hsize = min ( 18013, HSIZE ); - else if ( fsize < (1 << 15) ) - hsize = min ( 35023, HSIZE ); - else if ( fsize < 47000 ) - hsize = min ( 50021, HSIZE ); - - /* Generate output filename */ - strcpy(ofname, *fileptr); -#ifndef BSD4_2 /* Short filenames */ - if ((cp=rindex(ofname,'/')) != NULL) cp++; - else cp = ofname; - if (strlen(cp) > 12) { - fprintf(stderr,"%s: filename too long to tack on .Z\n",cp); - continue; - } -#endif /* BSD4_2 Long filenames allowed */ - strcat(ofname, ".Z"); - } - /* Check for overwrite of existing file */ - if (overwrite == 0 && zcat_flg == 0) { - if (stat(ofname, &statbuf) == 0) { - char response[2]; - response[0] = 'n'; - fprintf(stderr, "%s already exists;", ofname); - if (foreground()) { - fprintf(stderr, " do you wish to overwrite %s (y or n)? ", - ofname); - fflush(stderr); - read(2, response, 2); - while (response[1] != '\n') { - if (read(2, response+1, 1) < 0) { /* Ack! */ - perror("stderr"); break; - } - } - } - if (response[0] != 'y') { - fprintf(stderr, "\tnot overwritten\n"); - continue; - } - } - } - if(zcat_flg == 0) { /* Open output file */ - if (freopen(ofname, "w", stdout) == NULL) { - perror(ofname); - continue; - } - if(!quiet) - fprintf(stderr, "%s: ", *fileptr); - } - - /* Actually do the compression/decompression */ - if (do_decomp == 0) compress(); -#ifndef DEBUG - else decompress(); -#else - else if (debug == 0) decompress(); - else printcodes(); - if (verbose) dump_tab(); -#endif /* DEBUG */ - if(zcat_flg == 0) { - copystat(*fileptr, ofname); /* Copy stats */ - if((exit_stat == 1) || (!quiet)) - putc('\n', stderr); - } - } - } else { /* Standard input */ - if (do_decomp == 0) { - compress(); -#ifdef DEBUG - if(verbose) dump_tab(); -#endif /* DEBUG */ - if(!quiet) - putc('\n', stderr); - } else { - /* Check the magic number */ - if (nomagic == 0) { - if ((getchar()!=(magic_header[0] & 0xFF)) - || (getchar()!=(magic_header[1] & 0xFF))) { - fprintf(stderr, "stdin: not in compressed format\n"); - exit(1); - } - maxbits = getchar(); /* set -b from file */ - block_compress = maxbits & BLOCK_MASK; - maxbits &= BIT_MASK; - maxmaxcode = 1L << maxbits; - fsize = 100000; /* assume stdin large for USERMEM */ - if(maxbits > BITS) { - fprintf(stderr, - "stdin: compressed with %d bits, can only handle %d bits\n", - maxbits, BITS); - exit(1); - } - } -#ifndef DEBUG - decompress(); -#else - if (debug == 0) decompress(); - else printcodes(); - if (verbose) dump_tab(); -#endif /* DEBUG */ - } - } - exit(exit_stat); -} - -static int offset; -long int in_count = 1; /* length of input */ -long int bytes_out; /* length of compressed output */ -long int out_count = 0; /* # of codes output (for debugging) */ - -/* - * compress stdin to stdout - * - * Algorithm: use open addressing double hashing (no chaining) on the - * prefix code / next character combination. We do a variant of Knuth's - * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime - * secondary probe. Here, the modular division first probe is gives way - * to a faster exclusive-or manipulation. Also do block compression with - * an adaptive reset, whereby the code table is cleared when the compression - * ratio decreases, but after the table fills. The variable-length output - * codes are re-sized at this point, and a special CLEAR code is generated - * for the decompressor. Late addition: construct the table according to - * file size for noticeable speed improvement on small files. Please direct - * questions about this implementation to ames!jaw. - */ - -compress() { - register long fcode; - register code_int i = 0; - register int c; - register code_int ent; -#ifdef XENIX_16 - register code_int disp; -#else /* Normal machine */ - register int disp; -#endif - register code_int hsize_reg; - register int hshift; - -#ifndef COMPATIBLE - if (nomagic == 0) { - putchar(magic_header[0]); putchar(magic_header[1]); - putchar((char)(maxbits | block_compress)); - if(ferror(stdout)) - writeerr(); - } -#endif /* COMPATIBLE */ - - offset = 0; - bytes_out = 3; /* includes 3-byte header mojo */ - out_count = 0; - clear_flg = 0; - ratio = 0; - in_count = 1; - checkpoint = CHECK_GAP; - maxcode = MAXCODE(n_bits = INIT_BITS); - free_ent = ((block_compress) ? FIRST : 256 ); - - ent = getchar (); - - hshift = 0; - for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L ) - hshift++; - hshift = 8 - hshift; /* set hash code range bound */ - - hsize_reg = hsize; - cl_hash( (count_int) hsize_reg); /* clear hash table */ - -#ifdef SIGNED_COMPARE_SLOW - while ( (c = getchar()) != (unsigned) EOF ) { -#else - while ( (c = getchar()) != EOF ) { -#endif - in_count++; - fcode = (long) (((long) c << maxbits) + ent); - i = (((long)c << hshift) ^ ent); /* xor hashing */ - - if ( htabof (i) == fcode ) { - ent = codetabof (i); - continue; - } else if ( (long)htabof (i) < 0 ) /* empty slot */ - goto nomatch; - disp = hsize_reg - i; /* secondary hash (after G. Knott) */ - if ( i == 0 ) - disp = 1; -probe: - if ( (i -= disp) < 0 ) - i += hsize_reg; - - if ( htabof (i) == fcode ) { - ent = codetabof (i); - continue; - } - if ( (long)htabof (i) > 0 ) - goto probe; -nomatch: - output ( (code_int) ent ); - out_count++; - ent = c; -#ifdef SIGNED_COMPARE_SLOW - if ( (unsigned) free_ent < (unsigned) maxmaxcode) { -#else - if ( free_ent < maxmaxcode ) { -#endif - codetabof (i) = free_ent++; /* code -> hashtable */ - htabof (i) = fcode; - } - else if ( (count_int)in_count >= checkpoint && block_compress ) - cl_block (); - } - /* - * Put out the final code. - */ - output( (code_int)ent ); - out_count++; - output( (code_int)-1 ); - - /* - * Print out stats on stderr - */ - if(zcat_flg == 0 && !quiet) { -#ifdef DEBUG - fprintf( stderr, - "%ld chars in, %ld codes (%ld bytes) out, compression factor: ", - in_count, out_count, bytes_out ); - prratio( stderr, in_count, bytes_out ); - fprintf( stderr, "\n"); - fprintf( stderr, "\tCompression as in compact: " ); - prratio( stderr, in_count-bytes_out, in_count ); - fprintf( stderr, "\n"); - fprintf( stderr, "\tLargest code (of last block) was %d (%d bits)\n", - free_ent - 1, n_bits ); -#else /* !DEBUG */ - fprintf( stderr, "Compression: " ); - prratio( stderr, in_count-bytes_out, in_count ); -#endif /* DEBUG */ - } - if(bytes_out > in_count) /* exit(2) if no savings */ - exit_stat = 2; - return; -} - -/***************************************************************** - * TAG( output ) - * - * Output the given code. - * Inputs: - * code: A n_bits-bit integer. If == -1, then EOF. This assumes - * that n_bits =< (long)wordsize - 1. - * Outputs: - * Outputs code to the file. - * Assumptions: - * Chars are 8 bits long. - * Algorithm: - * Maintain a BITS character long buffer (so that 8 codes will - * fit in it exactly). Use the VAX insv instruction to insert each - * code in turn. When the buffer fills up empty it and start over. - */ - -static char buf[BITS]; - -#ifndef vax -char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; -char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; -#endif /* vax */ - -output( code ) -code_int code; -{ -#ifdef DEBUG - static int col = 0; -#endif /* DEBUG */ - - /* - * On the VAX, it is important to have the register declarations - * in exactly the order given, or the asm will break. - */ - register int r_off = offset, bits= n_bits; - register char * bp = buf; - -#ifdef DEBUG - if ( verbose ) - fprintf( stderr, "%5d%c", code, - (col+=6) >= 74 ? (col = 0, '\n') : ' ' ); -#endif /* DEBUG */ - if ( code >= 0 ) { -#ifdef vax - /* VAX DEPENDENT!! Implementation on other machines is below. - * - * Translation: Insert BITS bits from the argument starting at - * offset bits from the beginning of buf. - */ - 0; /* Work around for pcc -O bug with asm and if stmt */ - asm( "insv 4(ap),r11,r10,(r9)" ); -#else /* not a vax */ -/* - * byte/bit numbering on the VAX is simulated by the following code - */ - /* - * Get to the first byte. - */ - bp += (r_off >> 3); - r_off &= 7; - /* - * Since code is always >= 8 bits, only need to mask the first - * hunk on the left. - */ - *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off]; - bp++; - bits -= (8 - r_off); - code >>= 8 - r_off; - /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ - if ( bits >= 8 ) { - *bp++ = code; - code >>= 8; - bits -= 8; - } - /* Last bits. */ - if(bits) - *bp = code; -#endif /* vax */ - offset += n_bits; - if ( offset == (n_bits << 3) ) { - bp = buf; - bits = n_bits; - bytes_out += bits; - do - putchar(*bp++); - while(--bits); - offset = 0; - } - - /* - * If the next entry is going to be too big for the code size, - * then increase it, if possible. - */ - if ( free_ent > maxcode || (clear_flg > 0)) - { - /* - * Write the whole buffer, because the input side won't - * discover the size increase until after it has read it. - */ - if ( offset > 0 ) { - if( fwrite( buf, 1, n_bits, stdout ) != n_bits) - writeerr(); - bytes_out += n_bits; - } - offset = 0; - - if ( clear_flg ) { - maxcode = MAXCODE (n_bits = INIT_BITS); - clear_flg = 0; - } - else { - n_bits++; - if ( n_bits == maxbits ) - maxcode = maxmaxcode; - else - maxcode = MAXCODE(n_bits); - } -#ifdef DEBUG - if ( debug ) { - fprintf( stderr, "\nChange to %d bits\n", n_bits ); - col = 0; - } -#endif /* DEBUG */ - } - } else { - /* - * At EOF, write the rest of the buffer. - */ - if ( offset > 0 ) - fwrite( buf, 1, (offset + 7) / 8, stdout ); - bytes_out += (offset + 7) / 8; - offset = 0; - fflush( stdout ); -#ifdef DEBUG - if ( verbose ) - fprintf( stderr, "\n" ); -#endif /* DEBUG */ - if( ferror( stdout ) ) - writeerr(); - } -} - -/* - * Decompress stdin to stdout. This routine adapts to the codes in the - * file building the "string" table on-the-fly; requiring no table to - * be stored in the compressed file. The tables used herein are shared - * with those of the compress() routine. See the definitions above. - */ - -decompress() { - register char_type *stackp; - register int finchar; - register code_int code, oldcode, incode; - - /* - * As above, initialize the first 256 entries in the table. - */ - maxcode = MAXCODE(n_bits = INIT_BITS); - for ( code = 255; code >= 0; code-- ) { - tab_prefixof(code) = 0; - tab_suffixof(code) = (char_type)code; - } - free_ent = ((block_compress) ? FIRST : 256 ); - - finchar = oldcode = getcode(); - if(oldcode == -1) /* EOF already? */ - return; /* Get out of here */ - putchar( (char)finchar ); /* first code must be 8 bits = char */ - if(ferror(stdout)) /* Crash if can't write */ - writeerr(); - stackp = de_stack; - - while ( (code = getcode()) > -1 ) { - - if ( (code == CLEAR) && block_compress ) { - for ( code = 255; code >= 0; code-- ) - tab_prefixof(code) = 0; - clear_flg = 1; - free_ent = FIRST - 1; - if ( (code = getcode ()) == -1 ) /* O, untimely death! */ - break; - } - incode = code; - /* - * Special case for KwKwK string. - */ - if ( code >= free_ent ) { - *stackp++ = finchar; - code = oldcode; - } - - /* - * Generate output characters in reverse order - */ -#ifdef SIGNED_COMPARE_SLOW - while ( ((unsigned long)code) >= ((unsigned long)256) ) { -#else - while ( code >= 256 ) { -#endif - *stackp++ = tab_suffixof(code); - code = tab_prefixof(code); - } - *stackp++ = finchar = tab_suffixof(code); - - /* - * And put them out in forward order - */ - do - putchar ( *--stackp ); - while ( stackp > de_stack ); - - /* - * Generate the new entry. - */ - if ( (code=free_ent) < maxmaxcode ) { - tab_prefixof(code) = (unsigned short)oldcode; - tab_suffixof(code) = finchar; - free_ent = code+1; - } - /* - * Remember previous code. - */ - oldcode = incode; - } - fflush( stdout ); - if(ferror(stdout)) - writeerr(); -} - -/***************************************************************** - * TAG( getcode ) - * - * Read one code from the standard input. If EOF, return -1. - * Inputs: - * stdin - * Outputs: - * code or -1 is returned. - */ - -code_int -getcode() { - /* - * On the VAX, it is important to have the register declarations - * in exactly the order given, or the asm will break. - */ - register code_int code; - static int offset = 0, size = 0; - static char_type buf[BITS]; - register int r_off, bits; - register char_type *bp = buf; - - if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) { - /* - * If the next entry will be too big for the current code - * size, then we must increase the size. This implies reading - * a new buffer full, too. - */ - if ( free_ent > maxcode ) { - n_bits++; - if ( n_bits == maxbits ) - maxcode = maxmaxcode; /* won't get any bigger now */ - else - maxcode = MAXCODE(n_bits); - } - if ( clear_flg > 0) { - maxcode = MAXCODE (n_bits = INIT_BITS); - clear_flg = 0; - } - size = fread( buf, 1, n_bits, stdin ); - if ( size <= 0 ) - return -1; /* end of file */ - offset = 0; - /* Round size down to integral number of codes */ - size = (size << 3) - (n_bits - 1); - } - r_off = offset; - bits = n_bits; -#ifdef vax - asm( "extzv r10,r9,(r8),r11" ); -#else /* not a vax */ - /* - * Get to the first byte. - */ - bp += (r_off >> 3); - r_off &= 7; - /* Get first part (low order bits) */ -#ifdef NO_UCHAR - code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff; -#else - code = (*bp++ >> r_off); -#endif /* NO_UCHAR */ - bits -= (8 - r_off); - r_off = 8 - r_off; /* now, offset into code word */ - /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ - if ( bits >= 8 ) { -#ifdef NO_UCHAR - code |= (*bp++ & 0xff) << r_off; -#else - code |= *bp++ << r_off; -#endif /* NO_UCHAR */ - r_off += 8; - bits -= 8; - } - /* high order bits. */ - code |= (*bp & rmask[bits]) << r_off; -#endif /* vax */ - offset += n_bits; - - return code; -} - -char * -rindex(s, c) /* For those who don't have it in libc.a */ -register char *s, c; -{ - char *p; - for (p = NULL; *s; s++) - if (*s == c) - p = s; - return(p); -} - -#ifdef DEBUG -printcodes() -{ - /* - * Just print out codes from input file. For debugging. - */ - code_int code; - int col = 0, bits; - - bits = n_bits = INIT_BITS; - maxcode = MAXCODE(n_bits); - free_ent = ((block_compress) ? FIRST : 256 ); - while ( ( code = getcode() ) >= 0 ) { - if ( (code == CLEAR) && block_compress ) { - free_ent = FIRST - 1; - clear_flg = 1; - } - else if ( free_ent < maxmaxcode ) - free_ent++; - if ( bits != n_bits ) { - fprintf(stderr, "\nChange to %d bits\n", n_bits ); - bits = n_bits; - col = 0; - } - fprintf(stderr, "%5d%c", code, (col+=6) >= 74 ? (col = 0, '\n') : ' ' ); - } - putc( '\n', stderr ); - exit( 0 ); -} - -#ifdef XENIX_16 -code_int stab1[8192] ; -code_int stab2[8192] ; -code_int stab3[8192] ; -code_int stab4[8192] ; -code_int stab5[8192] ; -code_int stab6[8192] ; -code_int stab7[8192] ; -code_int stab8[8192] ; -code_int * sorttab[8] = {stab1, stab2, stab3, stab4, stab5, stab6, stab7, - stab8 } ; -#define stabof(i) (sorttab[(i) >> 13][(i) & 0x1fff]) -#else -code_int sorttab[SSIZE]; /* sorted pointers into htab */ -#define stabof(i) (sorttab[i]) -#endif - -dump_tab() /* dump string table */ -{ - register int i, first; - register ent; -#define STACK_SIZE 15000 - int stack_top = STACK_SIZE; - register c; - unsigned mbshift ; - - if(do_decomp == 0) { /* compressing */ - register int flag = 1; - - for(i=0; i<hsize; i++) { /* build sort pointers */ - if((long)htabof(i) >= 0) { - stabof(codetabof(i)) = i; - } - } - first = block_compress ? FIRST : 256; - for(i = first; i < free_ent; i++) { - fprintf(stderr, "%5d: \"", i); - de_stack[--stack_top] = '\n'; - de_stack[--stack_top] = '"'; - stack_top = in_stack((htabof(stabof(i))>>maxbits)&0xff, - stack_top); -/* for(ent=htabof(stabof(i)) & ((1<<maxbits)-1); */ - mbshift = ((1 << maxbits) - 1) ; - ent = htabof(stabof(i)) & mbshift ; - for(; - ent > 256; - /* ent=htabof(stabof(ent)) & ((1<<maxbits)-1)) { */ - ent=htabof(stabof(ent)) & mbshift) { - stack_top = in_stack(htabof(stabof(ent)) >> maxbits, - stack_top); - } - stack_top = in_stack(ent, stack_top); - fwrite( &de_stack[stack_top], 1, STACK_SIZE-stack_top, stderr); - stack_top = STACK_SIZE; - } - } else if(!debug) { /* decompressing */ - - for ( i = 0; i < free_ent; i++ ) { - ent = i; - c = tab_suffixof(ent); - if ( isascii(c) && isprint(c) ) - fprintf( stderr, "%5d: %5d/'%c' \"", - ent, tab_prefixof(ent), c ); - else - fprintf( stderr, "%5d: %5d/\\%03o \"", - ent, tab_prefixof(ent), c ); - de_stack[--stack_top] = '\n'; - de_stack[--stack_top] = '"'; - for ( ; ent != NULL; - ent = (ent >= FIRST ? tab_prefixof(ent) : NULL) ) { - stack_top = in_stack(tab_suffixof(ent), stack_top); - } - fwrite( &de_stack[stack_top], 1, STACK_SIZE - stack_top, stderr ); - stack_top = STACK_SIZE; - } - } -} - -int -in_stack(c, stack_top) - register c, stack_top; -{ - if ( (isascii(c) && isprint(c) && c != '\\') || c == ' ' ) { - de_stack[--stack_top] = c; - } else { - switch( c ) { - case '\n': de_stack[--stack_top] = 'n'; break; - case '\t': de_stack[--stack_top] = 't'; break; - case '\b': de_stack[--stack_top] = 'b'; break; - case '\f': de_stack[--stack_top] = 'f'; break; - case '\r': de_stack[--stack_top] = 'r'; break; - case '\\': de_stack[--stack_top] = '\\'; break; - default: - de_stack[--stack_top] = '0' + c % 8; - de_stack[--stack_top] = '0' + (c / 8) % 8; - de_stack[--stack_top] = '0' + c / 64; - break; - } - de_stack[--stack_top] = '\\'; - } - return stack_top; -} -#endif /* DEBUG */ - -writeerr() -{ - perror ( ofname ); - unlink ( ofname ); - exit ( 1 ); -} - -copystat(ifname, ofname) -char *ifname, *ofname; -{ - struct stat statbuf; - int mode; - time_t timep[2]; - - fclose(stdout); - if (stat(ifname, &statbuf)) { /* Get stat on input file */ - perror(ifname); - return; - } - if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) { - if(quiet) - fprintf(stderr, "%s: ", ifname); - fprintf(stderr, " -- not a regular file: unchanged"); - exit_stat = 1; - } else if (statbuf.st_nlink > 1) { - if(quiet) - fprintf(stderr, "%s: ", ifname); - fprintf(stderr, " -- has %d other links: unchanged", - statbuf.st_nlink - 1); - exit_stat = 1; - } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */ - if(!quiet) - fprintf(stderr, " -- file unchanged"); - } else { /* ***** Successful Compression ***** */ - exit_stat = 0; - mode = statbuf.st_mode & 07777; - if (chmod(ofname, mode)) /* Copy modes */ - perror(ofname); - chown(ofname, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */ - timep[0] = statbuf.st_atime; - timep[1] = statbuf.st_mtime; - utime(ofname, timep); /* Update last accessed and modified times */ - if (unlink(ifname)) /* Remove input file */ - perror(ifname); - if(!quiet) - fprintf(stderr, " -- replaced with %s", ofname); - return; /* Successful return */ - } - - /* Unsuccessful return -- one of the tests failed */ - if (unlink(ofname)) - perror(ofname); -} -/* - * This routine returns 1 if we are running in the foreground and stderr - * is a tty. - */ -foreground() -{ - if(bgnd_flag) { /* background? */ - return(0); - } else { /* foreground */ - if(isatty(2)) { /* and stderr is a tty */ - return(1); - } else { - return(0); - } - } -} - -onintr ( ) -{ - unlink ( ofname ); - exit ( 1 ); -} - -oops ( ) /* wild pointer -- assume bad input */ -{ - if ( do_decomp == 1 ) - fprintf ( stderr, "uncompress: corrupt input\n" ); - unlink ( ofname ); - exit ( 1 ); -} - -cl_block () /* table clear for block compress */ -{ - register long int rat; - - checkpoint = in_count + CHECK_GAP; -#ifdef DEBUG - if ( debug ) { - fprintf ( stderr, "count: %ld, ratio: ", in_count ); - prratio ( stderr, in_count, bytes_out ); - fprintf ( stderr, "\n"); - } -#endif /* DEBUG */ - - if(in_count > 0x007fffff) { /* shift will overflow */ - rat = bytes_out >> 8; - if(rat == 0) { /* Don't divide by zero */ - rat = 0x7fffffff; - } else { - rat = in_count / rat; - } - } else { - rat = (in_count << 8) / bytes_out; /* 8 fractional bits */ - } - if ( rat > ratio ) { - ratio = rat; - } else { - ratio = 0; -#ifdef DEBUG - if(verbose) - dump_tab(); /* dump string table */ -#endif - cl_hash ( (count_int) hsize ); - free_ent = FIRST; - clear_flg = 1; - output ( (code_int) CLEAR ); -#ifdef DEBUG - if(debug) - fprintf ( stderr, "clear\n" ); -#endif /* DEBUG */ - } -} - -cl_hash(hsize) /* reset code table */ - register count_int hsize; -{ -#ifndef XENIX_16 /* Normal machine */ - register count_int *htab_p = htab+hsize; -#else - register j; - register long k = hsize; - register count_int *htab_p; -#endif - register long i; - register long m1 = -1; - -#ifdef XENIX_16 - for(j=0; j<=8 && k>=0; j++,k-=8192) { - i = 8192; - if(k < 8192) { - i = k; - } - htab_p = &(htab[j][i]); - i -= 16; - if(i > 0) { -#else - i = hsize - 16; -#endif - do { /* might use Sys V memset(3) here */ - *(htab_p-16) = m1; - *(htab_p-15) = m1; - *(htab_p-14) = m1; - *(htab_p-13) = m1; - *(htab_p-12) = m1; - *(htab_p-11) = m1; - *(htab_p-10) = m1; - *(htab_p-9) = m1; - *(htab_p-8) = m1; - *(htab_p-7) = m1; - *(htab_p-6) = m1; - *(htab_p-5) = m1; - *(htab_p-4) = m1; - *(htab_p-3) = m1; - *(htab_p-2) = m1; - *(htab_p-1) = m1; - htab_p -= 16; - } while ((i -= 16) >= 0); -#ifdef XENIX_16 - } - } -#endif - for ( i += 16; i > 0; i-- ) - *--htab_p = m1; -} - -prratio(stream, num, den) -FILE *stream; -long int num, den; -{ - register int q; /* Doesn't need to be long */ - - if(num > 214748L) { /* 2147483647/10000 */ - q = num / (den / 10000L); - } else { - q = 10000L * num / den; /* Long calculations, though */ - } - if (q < 0) { - putc('-', stream); - q = -q; - } - fprintf(stream, "%d.%02d%%", q / 100, q % 100); -} - -version() -{ - fprintf(stderr, "%s\n", rcs_ident); - fprintf(stderr, "Options: "); -#ifdef vax - fprintf(stderr, "vax, "); -#endif -#ifdef NO_UCHAR - fprintf(stderr, "NO_UCHAR, "); -#endif -#ifdef SIGNED_COMPARE_SLOW - fprintf(stderr, "SIGNED_COMPARE_SLOW, "); -#endif -#ifdef XENIX_16 - fprintf(stderr, "XENIX_16, "); -#endif -#ifdef COMPATIBLE - fprintf(stderr, "COMPATIBLE, "); -#endif -#ifdef DEBUG - fprintf(stderr, "DEBUG, "); -#endif -#ifdef BSD4_2 - fprintf(stderr, "BSD4_2, "); -#endif - fprintf(stderr, "BITS = %d\n", BITS); -} *-*-END-of-src/compress.c-*-* echo x - src/virtterm.c 1>&2 sed 's/.//' >src/virtterm.c <<'*-*-END-of-src/virtterm.c-*-*' -/* - * Virtual terminal handler - * Written by Kenneth Almquist, AGS Computers (HO 4C601, X7105). - * Modified by Stephen Hemminger, to use TERMCAP (without curses) - */ - -#ifdef SCCSID -static char *SccsId = "@(#)virtterm.c 1.12 10/29/86"; -#endif /* SCCSID */ - -/*LINTLIBRARY*/ - -#include <stdio.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <signal.h> -#ifdef USG -#include <termio.h> -#else /* !USG */ -#include <sgtty.h> -#endif /* !USG */ - -/* - * These values for MAXPLEN and MAXLLEN are used to dimension arrays - * that hold strings of relative cursor motions. The actual arrays that - * are used to hold screen images are malloc'd. - */ -#define MAXPLEN 90 -#define MAXLLEN 160 - -#define BOTLINE (ROWS - 1) -#define DIRTY 01 - -/* terminal escape sequences from termcap */ -#define HO _tstr[0] /* home */ -#define CL _tstr[1] /* clear screen */ -#define CD _tstr[2] /* clear to end of screen */ -#define CE _tstr[3] /* clear to end of line */ -#define xUP _tstr[4] /* up one line */ -#define DO _tstr[5] /* down one line */ -#define US _tstr[6] /* underline */ -#define UE _tstr[7] /* underline end */ -#define BT _tstr[8] /* backtab */ -#define xBC _tstr[9] /* backspace */ -#define AL _tstr[10] /* insert line */ -#define DL _tstr[11] /* delete line */ -#define CM _tstr[12] /* cursor move */ -#define CH _tstr[13] /* cursor horizontal move */ -#define CV _tstr[14] /* cursor vertical move */ -#define CS _tstr[15] /* scrolling region */ -#define SF _tstr[16] /* scroll forwards */ -#define SR _tstr[17] /* scroll backwards */ -#define TI _tstr[18] /* start cursor mode */ -#define TE _tstr[19] /* end cursor mode */ -#define TA _tstr[20] /* tab char (if not \t) */ -#define CR _tstr[21] /* carriage return (if not \r) */ -#define xPC _tstr[22] /* for reading pad character */ -char PC; /* pad character */ -char *BC, *UP; /* external variables for tgoto */ - -static char sname[] = "hoclcdceupdousuebtbcaldlcmchcvcssfsrtitetacrpc"; -char *_tstr[23]; -int HOlen; /* length of HO string */ - - -/* terminal flags */ -#define BS _tflg[0] /* can backspace */ -#define AM _tflg[1] /* has auto margins */ -#define XN _tflg[2] /* no newline after wrap */ -#define RET !_tflg[3] /* has carriage return */ -#define NS _tflg[4] /* has SF (scroll forward) */ -#define PT _tflg[5] /* has tabs */ -#define XT _tflg[6] /* tabs are destructive */ -int GT = 1; /* tab stops on terminal are set */ - -static char bname[] = "bsamxnncnsptxt"; -char _tflg[7]; - - -extern char *tgoto(), *tgetstr(); -extern char *getenv(), *strcpy(); - -#define ULINE 0200 - -/* Constants accessable by user */ -int hasscroll; /* scrolling type, 0 == no scrolling */ -int ROWS; /* number of lines on screen */ -int COLS; /* width of screen */ - -struct line { - char len; - char flags; - char *l; /* pointer to actual line text, NO NULL @ end */ -}; - -int _row, _col; -int _srow, _scol; -struct line *_virt; /* what we want the screen to look like */ -struct line *_actual; /* What it actually looks like */ -int _uline = 0; -int _junked = 1; -int _curjunked; -int _dir = 1; -int _shifttop, _shiftbot; -int _shift; -int _scratched; -int vputc(); - -/* - * Tell refresh to shift lines in region upwards count lines. Count - * may be negative. The virtual image is not shifted; this may change - * later. The variable _scratched is set to supress all attempts to - * shift. - */ - -ushift(top, bot, count) -{ - if (_scratched) - return; - if (_shift != 0 && (_shifttop != top || _shiftbot != bot)) { - _scratched++; - return; - } - _shifttop = top; - _shiftbot = bot; - _shift += count; -} - -/* - * generate a beep on the terminal - */ -beep() -{ - vputc('\7'); -} - -/* - * Move to one line below the bottom of the screen. - */ -botscreen() -{ - _amove(BOTLINE, 0); - vputc('\n'); - vflush(); -} - -move(row, col) -{ - if (row < 0 || row >= ROWS || col < 0 || col >= COLS) - return; - _row = row; - _col = col; -} - - - -/* - * Output string at specified location. - */ -mvaddstr(row, col, str) -char *str; -{ - move(row, col); - addstr(str); -} - -addstr(s) -char *s; -{ - register char *p; - register struct line *lp; - register int col = _col; - - lp = &_virt[_row]; - if (lp->len < col) { - p = &lp->l[lp->len]; - while (lp->len < col) { - *p++ = ' '; - lp->len++; - } - } - for (p = s; *p != '\0'; p++) { - if (*p == '\n') { - lp->len = col; - lp->flags |= DIRTY; - col = 0; - if (++_row >= ROWS) - _row = 0; - lp = &_virt[_row]; - } - else { - lp->l[col] = *p; - lp->flags |= DIRTY; - if (++col >= COLS) { - lp->len = COLS; - col = 0; - if (++_row >= ROWS) - _row = 0; - lp = &_virt[_row]; - } - } - } - if (lp->len <= col) - lp->len = col; - _col = col; -} - -addch(c) -{ - register struct line *lp; - register char *p; - - lp = &_virt[_row]; - if (lp->len < _col) { - p = &lp->l[lp->len]; - while (lp->len < _col) { - *p++ = ' '; - lp->len++; - } - } - lp->l[_col] = c; - if (lp->len == _col) - lp->len++; - if (++_col >= COLS) { - _col = 0; - if (++_row >= ROWS) - _row = 0; - } - lp->flags |= DIRTY; -} - -/* - * Clear an entire line. - */ -clrline(row) -{ - register struct line *lp; - - lp = &_virt[row]; - if (lp->len > 0) { - lp->len = 0; - lp->flags |= DIRTY; - } -} - -erase() -{ - register i; - - for (i = 0; i < ROWS; i++) { - _virt[i].len = 0; - _virt[i].flags |= DIRTY; - } -} - -refresh() -{ - register i; - register char *p, *q; - register int j, len; - - if (checkin()) - return; - i = 1; - if (_junked) { - _sclear(); - _junked = 0; - } else if (! _scratched) { - if (_shift > 0) { - _ushift(_shifttop, _shiftbot, _shift); - } else if (_shift < 0) { - i = _dshift(_shifttop, _shiftbot, -_shift); - } else { - i = _dir; - } - } - _dir = i; - _shift = 0; - if (checkin()) - return; - _fixlines(); - for (i = _dir > 0 ? 0 : BOTLINE; i >= 0 && i < ROWS; i += _dir) { - if ((_virt[i].flags & DIRTY) == 0) - continue; - _ckclrlin(i); /* decide whether to do a clear line */ - /* probably should consider cd too */ - len = _virt[i].len; - if (_actual[i].len < len) - len = _actual[i].len; - p = _virt[i].l; - q = _actual[i].l; - for (j = 0; j < len; j++) { - if (*p != *q) { - /* Inline test for speed */ - if (i != _srow || j != _scol || _curjunked) - _amove(i, j); - _aputc(*p); - *q = *p; - } - p++; - q++; - } - len = _virt[i].len; - if (_actual[i].len > len) { - _clrtoeol(i, len); - } else { - for (; j < len; j++) { - if (*p != ' ') { - /* Inline test for speed */ - if (i != _srow || j != _scol || _curjunked) - _amove(i, j); - _aputc(*p); - } - *q++ = *p++; - } - _actual[i].len = len; - } - if (checkin()) - return; - } - _dir = 1; - _amove(_row, _col); - vflush(); /* flush output buffer */ - _scratched = 0; -} - -_dshift(top, bot, count) -{ - register i; - - if (count >= bot - top || hasscroll < 4) { /* must have CS or AL/DL */ - _scratched++; - return 1; - } - for (i = bot - count; _actual[i].len == 0; i--) - if (i == top) - return 1; - for (i = top; i <= bot; i++) - _virt[i].flags |= DIRTY; - for (i = bot; i >= top + count; i--) { - /* FIXME, this should be done by recirculating the pointers */ - register j; - j = _actual[i].len = _actual[i - count].len; - _actual[i].flags = _actual[i - count].flags; - strncpy(_actual[i].l, _actual[i - count].l, j); - } - for (; i >= top; i--) - _actual[i].len = 0; - - if (hasscroll != 5) { /* can we define scrolling region, and scroll back */ - tputs(tgoto(CS, bot, top), 1, vputc);/* define scroll region */ - _curjunked = 1; - _amove(top, 0); - for (i = count; --i >= 0;) - tputs(SR, 1, vputc);/* scroll back */ - tputs(tgoto(CS, BOTLINE, 0), 1, vputc); - _curjunked = 1; - } else { - _amove(bot - count + 1, 0); - if (CD && bot == BOTLINE) - tputs(CD, 1, vputc); - else { - for (i = count; --i >= 0;) - tputs(DL, ROWS - _srow, vputc); - } - _amove(top, 0); - for (i = count; --i >= 0;) - tputs(AL, ROWS - _srow, vputc); - } - return -1; -} - - -_ushift(top, bot, count) -{ - register i; - - if (count >= bot - top || hasscroll == 0) { - _scratched++; - return; - } - for (i = top + count; _actual[i].len == 0; i++) - if (i == bot) - return; - if (hasscroll == 1 || hasscroll == 3) { - /* we cheat and shift the entire screen */ - /* be sure we are shifting more lines into than out of position */ - if ((bot - top + 1) - count <= ROWS - (bot - top + 1)) - return; - top = 0, bot = BOTLINE; - } - for (i = top; i <= bot; i++) - _virt[i].flags |= DIRTY; - for (i = top; i <= bot - count; i++) { - /* FIXME, this should be done by recirculating the pointers */ - register int j; - j = _actual[i].len = _actual[i + count].len; - _actual[i].flags = _actual[i + count].flags; - strncpy(_actual[i].l, _actual[i + count].l, j); - } - for (; i <= bot; i++) - for (; i <= bot; i++) - _actual[i].len = 0; - - if (hasscroll != 5) { - if (top != 0 || bot != BOTLINE) { - tputs(tgoto(CS, bot, top), 0, vputc); - _curjunked = 1; - } - _amove(bot, 0); /* move to bottom */ - for (i = 0; i < count; i++) { - if (SF) /* scroll forward */ - tputs(SF, 1, vputc); - else - vputc('\n'); - } - if (top != 0 || bot != BOTLINE) { - tputs(tgoto(CS, BOTLINE, 0), 0, vputc); - _curjunked = 1; - } - } else { - _amove(top, 0); - for (i = count; --i >= 0;) - tputs(DL, ROWS - _srow, vputc); - if (bot < BOTLINE) { - _amove(bot - count + 1, 0); - for (i = count; --i >= 0;) - tputs(AL, ROWS - _srow, vputc); - } - } -} - -_sclear() -{ - register struct line *lp; - - tputs(CL, 0, vputc); - _srow = _scol = 0; - for (lp = _actual; lp < &_actual[ROWS]; lp++) { - lp->len = 0; - } - for (lp = _virt; lp < &_virt[ROWS]; lp++) { - if (lp->len != 0) - lp->flags |= DIRTY; - } -} - -_clrtoeol(row, col) -{ - register struct line *lp = &_actual[row]; - register i; - - if (CE && lp->len > col + 1) { - _amove(row, col); - tputs(CE, 1, vputc); - } else { - for (i = col ; i < lp->len ; i++) { - if (lp->l[i] != ' ') { - _amove(row, i); - _aputc(' '); - } - } - } - lp->len = col; -} - -_fixlines() -{ - register struct line *lp; - register char *p; - register int i; - - for (i = 0; i < ROWS; i++) { - lp = &_virt[i]; - if (lp->flags & DIRTY) { - for (p = &lp->l[lp->len]; --p >= lp->l && *p == ' ';) - ; - lp->len = (int) (p - lp->l) + 1; - if (lp->len == _actual[i].len && strncmp(lp->l, _actual[i].l, lp->len) == 0) - lp->flags &= ~DIRTY; - } - } -} - - -/* - * Consider clearing the line before overwriting it. - * We always clear a line if it has underlined characters in it - * because these can cause problems. Otherwise decide whether - * that will decrease the number of characters to change. This - * routine could probably be simplified with no great loss. - */ - -_ckclrlin(i) -{ - int eval; - int len; - int first; - register struct line *vp, *ap; - register int j; - - if (!CE) - return; - ap = &_actual[i]; - vp = &_virt[i]; - len = ap->len; - eval = -strlen(CE); - if (len > vp->len) { - len = vp->len; - eval = 0; - } - for (j = 0; j < len && vp->l[j] == ap->l[j]; j++) - ; - if (j == len) - return; - first = j; - while (j < len) { - if (vp->l[j] == ' ') { - if (ap->l[j] != ' ') { - while (++j < len && vp->l[j] == ' ' && ap->l[j] != ' ') { - eval++; - } - if (j == len) - eval++; - continue; - } - } - else { - if (vp->l[j] == ap->l[j]) { - while (++j < len && vp->l[j] == ap->l[j]) { - eval--; - } - continue; - } - } - j++; - } - if (US) { - for (j = 0 ; j < ap->len ; j++) { - if (ap->l[j] & ULINE) { - eval = 999; - if (first > j) - first = j; - break; - } - } - } - for (j = first; --j >= 0;) - if (vp->l[j] != ' ') - break; - if (j < 0) - first = 0; - if (eval > 0) { - _amove(i, first); - tputs(CE, 0, vputc); - _actual[i].len = first; - } -} - - - -/* - * Move routine - * first compute direct cursor address string and cost - * then relative motion string and cost, - * then home then relative and cost - * choose smallest and do it. - * - * The plod stuff is to build the strings (with padding) then decide - */ -static char *plodstr; /* current location in relmove string */ - -plodput(c) -{ - *plodstr++ = c; -} - -/* FIXME: speedup 1-char horiz moves: print the char that's there. */ -/* FIXME: avoid funniness if cm works. */ -/* FIXME: Avoid setul(0) if cursor motion OK in standout (XM?) */ -_amove(row, col) -{ - char direct[20]; - char rel[MAXPLEN*10 + MAXLLEN*10]; /* longest move is full screen */ - char ho[MAXPLEN*10 + MAXLLEN*10]; - int cost, newcost; - register char *movstr; - - if (row == _srow && col == _scol && _curjunked == 0) - return; - if (_uline) - _setul(0); /* Inline test for speed */ - - cost = 999; - if (CM) { - plodstr = direct; - tputs(tgoto(CM, col, row), 0, plodput); - cost = plodstr - direct; - movstr = direct; - } - if (_curjunked == 0) { - plodstr = rel; - if (_vmove(_srow, row) >= 0 - && (plodstr - rel) < cost /* after vmove */ - && _hmove(_scol, col, row) >= 0 - && (newcost = plodstr - rel) < cost) { /* after both */ - cost = newcost; - movstr = rel; - } - } - if (cost > HOlen) { /* is it worth calculating */ - plodstr = ho; - tputs(HO, 0, plodput); - if (_vmove(0, row) >= 0 - && (plodstr - ho) < cost /* after ho, vmove */ - && _hmove(0, col, row) >= 0 - && (newcost = plodstr - ho) < cost) { /* after all three */ - cost = newcost; - movstr = ho; - } - } - - if (cost < 999) - while (--cost >= 0) - vputc(*movstr++); - - _srow = row; - _scol = col; - _curjunked = 0; -} - -_vmove(orow, nrow) -{ - char direct[128]; - char *saveplod = plodstr; - - if (CV) { - plodstr = direct; - tputs(tgoto(CV, nrow, nrow), 0, plodput); - *plodstr = '\0'; - plodstr = saveplod; - } - if (orow > nrow) { /* cursor up */ - if (! UP) - return -1; - while (orow > nrow) { - tputs(UP, 1, plodput); - orow--; - } - } - while (orow < nrow) { /* cursor down */ - if (DO) - tputs(DO, 1, plodput); - else - *plodstr++ = '\n'; - orow++; - } - if (CV && plodstr - saveplod >= strlen(direct)) { - register char *p; - plodstr = saveplod; - for (p = direct ; *plodstr = *p++ ; plodstr++) - ; - } - return 0; -} - -_hmove(ocol, ncol, row) -{ - char direct[128]; - char ret[MAXLLEN*10]; - char *saveplod = plodstr; - char *movstr; - int cost, newcost; - - cost = 999; - if (CH) { - plodstr = direct; - tputs(tgoto(CH, ncol, ncol), 0, plodput); - cost = plodstr - direct; - movstr = direct; - plodstr = saveplod; - } - if (RET && ocol > ncol) { /* consider doing carriage return */ - plodstr = ret; - if (CR) - tputs(CR, 1, plodput); - else - *plodstr++ = '\r'; - if (_relhmove(0, ncol, row) >= 0 - && (newcost = plodstr - ret) < cost) { - cost = newcost; - movstr = ret; - } - plodstr = saveplod; - } - if (_relhmove(ocol, ncol, row) < 0) { - if (cost == 999) - return -1; - goto copy; - } - if (plodstr - saveplod > cost) { -copy: plodstr = saveplod; - while (--cost >= 0) - *plodstr++ = *movstr++; - } - return 0; -} - -_relhmove(ocol, ncol, row) -{ - int tab; - - if (ocol < ncol && PT && GT) { /* tab (nondestructive) */ - while ((tab = (ocol + 8) & ~07) <= ncol) { - if (TA) - tputs(TA, 1, plodput); - else - *plodstr++ = '\t'; - ocol = tab; - } - if (tab < COLS && tab - ncol < ncol - ocol) { - if (TA) - tputs(TA, 1, plodput); - else - *plodstr++ = '\t'; - ocol = tab; - } - } else if (BT && GT && ocol > ncol) { /* backwards tab */ - while ((tab = (ocol - 1) &~ 07) >= ncol) { - if (BS && tab == ocol - 1) { - if (BC) - tputs(BC, 1, plodput); - else - *plodstr++ = '\b'; - } else - tputs(BT, 1, plodput); - ocol = tab; - } - if (ncol - tab + 1 < ocol - ncol) { - tputs(BT, 1, plodput); - ocol = tab; - } - } - if (ocol > ncol) { /* cursor left */ - if (! BS) - return -1; - while (ocol > ncol) { - if (BC != NULL) - tputs(BC, 1, plodput); - else - *plodstr++ = '\b'; - ocol--; - } - } - if (ocol < ncol) { /* cursor right */ - register struct line *lp = &_actual[row]; - /* - * This code doesn't move over underlined characters properly, - * but in practice this doesn't seem to matter. - */ - while (ocol < ncol) { - if (ocol < lp->len) - *plodstr++ = lp->l[ocol]; - else - *plodstr++ = ' '; - ocol++; - } - } - return 0; -} - -_aputc(c) -{ - if (_uline != (c & ULINE)) /* Inline for speed */ - _setul(c & ULINE); - if (++_scol >= COLS) { - if (_srow == ROWS - 1) { - /* Don't ever paint last char of last line */ - _scol--; - return; - } - _curjunked++; /* Don't assume AM is right */ - } - vputc(c & ~ULINE); -} - - -_setul(on) -{ - if (on) { - if (_uline == 0 && US != NULL) { - tputs(US, 1, vputc); - _uline = ULINE; - } - } - else { - if (_uline != 0 && UE != NULL) { - tputs(UE, 1, vputc); - _uline = 0; - } - } -} - -/* - * Initialize termcap strings for later use. - */ - -/* - * Hacks to help with some Tek terminals - * rad@tek - */ -int tputs_len; -countit(c) { tputs_len++; } - -initterm() -{ - static char tcbuf[1024]; /* termcap buffer */ - register char *cp; -#ifdef USG - struct termio tio; -#else /* !USG */ - struct sgttyb ttyb; -#endif /* !USG */ - - if ((cp = getenv("TERM")) == NULL) - xerror("TERM not set in environment"); - - switch (tgetent(tcbuf, cp)) { - case 0: - xerror("Terminal not found in TERMCAP"); - case -1: - xerror("Can't open /etc/termcap"); - case 1: - break; - } -#ifdef TIOCGWINSZ - { - struct winsize ws; - int winch(); - - COLS = ROWS = -1; - if(ioctl(1, TIOCGWINSZ, &ws) == 0) { - ROWS = ws.ws_row; - COLS = ws.ws_col; - } - if(ROWS <= 0) - ROWS = tgetnum("li"); - if(COLS <= 0) - COLS = tgetnum("co"); - if ((ROWS <= 0) || (COLS <= 0)) - xerror("Can't get screen size"); - - signal(SIGWINCH, winch); /* allow for changing window size */ - } -#else /* !TIOCGWINSZ */ - if ((ROWS = tgetnum("li")) == -1 - || (COLS = tgetnum("co")) == -1) - xerror("Can't get screen size"); -#endif /* !TIOCGWINSZ */ - _zap(); - - if (CL == NULL) - xerror ("No clear screen defined"); - - if (HO == NULL && CM == NULL) - xerror("No home or cursor addressing"); - if (HO) - HOlen = strlen(HO); - else - HOlen = 999; - - PC = xPC ? xPC[0] : 0; - BC = xBC; - UP = xUP; - /* - * _vmove() may be called with a full-screen traverse, - * meaning it will put the UP (along with any padding) into - * the buffer as many as MAXPLEN times. This means that - * if the UP string would be more than 10 chars long (defined - * in _amove() ), the buffer might be overflowed (assuming - * CH is also large). - * This actually occurs with the Tek4023 termcap, where :up=1000UP: - * is used to fake vi into using :cm instead, due to the fact - * that a 4023 can't do upline relative motion at all. - * -rdoty@tek - */ - if (UP) { - tputs_len = 0; - tputs(UP, 1, countit); - if (tputs_len > 10 ) - UP = 0; - } - - if (tgetnum("ug") > 0) - US = UE = NULL; - - if (XT) /* Destructive tab code not included */ - PT = 0; /* to keep things simple */ - -#ifdef USG - if (ioctl(0, TCGETA, &tio) == 0) - GT = tio.c_oflag&TAB3; -#else /* !USG */ - if (ioctl(0, TIOCGETP, &ttyb) == 0) - GT = ttyb.sg_flags&XTABS; -#endif /* !USG */ - - { - char *thelines; - int i; - char *malloc(); - - thelines = malloc(2 * ROWS * COLS); - _virt = (struct line *)malloc(2 * ROWS * sizeof (struct line)); - _actual = _virt + ROWS; - for (i = 0; i < ROWS; i++) { - _virt[i].len = 0; - _virt[i].flags = 0; - _actual[i].len = 0; - _actual[i].flags = 0; - _virt[i].l = thelines; - thelines += COLS; - _actual[i].l = thelines; - thelines += COLS; - } - } - - /* Select article scrolling algorithm. We prefer scrolling region - over insert/delete line because it's faster on the HP */ - hasscroll = 0; - if (!NS) { - hasscroll = 1; - if (SR) - hasscroll = 3; - if (CS) - hasscroll++; - } - if (AL && DL && hasscroll != 4) - hasscroll = 5; -} - -rawterm() -{ - if (TI != NULL) - tputs(TI, 0, vputc); -} - -cookedterm() -{ - if (TE != NULL) { - tputs(TE, 0, vputc); - vflush(); - } -} - -/* get strings from termcap */ -_zap() -{ - static char tstrbuf[1024]; - static char *tp; - register char *namp, **sp, *bp; - - tp = tstrbuf; - sp = _tstr; - for (namp = sname; *namp; namp += 2) { - *sp++ = tgetstr(namp, &tp); - } - bp = _tflg; - for (namp = bname; *namp; namp += 2) { - *bp++ = tgetflag(namp, &tp); - } -} -#ifdef TIOCGWINSZ -/* - * window changed size -- update ROWS and COLS - * and then redraw screen - */ -winch() -{ - struct winsize ws; - int cols, rows; - - cols = rows = -1; - if(ioctl(1, TIOCGWINSZ, &ws) == 0) { - rows = ws.ws_row; - cols = ws.ws_col; - } - if (rows == ROWS && cols == COLS) { /* just redraw it if no change */ - _junked = 1; /* redraw */ - updscr(); - return; - } - - if(rows > 0) - ROWS = rows; - if(cols > 0) - COLS = cols; - - if (ROWS > MAXPLEN) - ROWS = MAXPLEN; - if (COLS > MAXLLEN) { - COLS = MAXLLEN; - AM = XN = 1; - } - - winch_upd(); -} -#endif TIOCGWINSZ *-*-END-of-src/virtterm.c-*-* echo x - src/decode.c 1>&2 sed 's/.//' >src/decode.c <<'*-*-END-of-src/decode.c-*-*' -#include <stdio.h> - -#ifdef SCCSID -static char *SccsId = "@(#)decode.c 1.3 5/15/85"; -#endif /* SCCSID */ - -/* - * This program is the inverse of encode - * - * It collects runs of 12 characters, combines pairs of those - * to form 6 13 bit numbers, extracts the top bit of each of - * those to make a 13th 6 bit character, and splits each of - * the remaining 6 12 bit numbers to form 12 6 bit ones. - * - * The strings of 6 bit numbers are collected into groups of - * 4 and converted into 3 8 bit characters. - * - * Now all that would be trivial, if we didn't need to worry - * about ending all this correctly. About 1/2 of the following - * program wouldn't be here if the ending didn't matter.... - */ - -/* - * the following pair of characters can never occur as a pair - * in legal input (since (90 * 91 + 90) > 2^13) - they are - * noticed at the beginning of a 12 char block, and serve to - * indicate that this block is the terminator. The character - * immediately following is the (expanded) terminator length. - */ -#define ENDMARK1 ((90*91 + 90) / 91) -#define ENDMARK2 ((90*91 + 90) % 91) - -main() -{ - register c; - register char *p; - register i; - register first = 1; - register cnt = 0; - int errcnt = 0; - char b12[12]; - char c12[12]; - - p = b12; - i = 12; - - while ((c = getchar()) != EOF) { - if (c < ' ' || c >= (' ' + 91)) { - if (errcnt++ == 0) - fprintf(stderr, "decode: Bad data\n"); - continue; - } - if (i == 10 && p[-1] == ENDMARK1 && p[-2] == ENDMARK2) { - cnt = c - ' '; - i = 12; - p -= 2; - continue; - } - *p++ = c - ' '; - if (--i == 0) { - if (p == &b12[12]) { - if (!first) - pack12(c12, 12, 0); - else - first = 0; - p = c12; - } else { - pack12(b12, 12, 0); - p = b12; - } - i = 12; - } - } - - if (p >= &b12[0] && p < &b12[12]) { - if (!first) - pack12(c12, 12, i == 12 ? cnt : 0); - } else - pack12(b12, 12, i == 12 ? cnt : 0); - - if (i != 12) { - if (p >= &b12[0] && p < &b12[12]) - pack12(b12, 12-i, cnt); - else - pack12(c12, 12-i, cnt); - } - - exit(0); -} - -static char b4[4]; -static int cnt = 0; - -pack12(p, n, last) - register char *p; - register n; - int last; -{ - register i; - register char *q; - char b13[13]; - - { - register c; - register c13; - - q = b13; - c13 = 0; - - for (i = 0; i < n; i += 2) { - c = *p++ * 91; - c += *p++; - c13 <<= 1; - if (c & (1 << 12)) - c13 |= 1; - *q++ = (c >> 6) & 0x3f; - *q++ = c & 0x3f; - } - *q++ = c13; - if (last) - q = &b13[last]; - } - - p = b13; - n = q - p; - i = cnt; - q = &b4[cnt]; - - while (--n > 0) { - *q++ = *p++; - if (++i == 4) { - char b3[3]; - register char *b = b4; - - /* inline expansion of pack6bit, to save calls ... */ - - q = b3; - *q++ = (b[0] << 2) | ((b[1] >> 4) & 0x3); - *q++ = (b[1] << 4) | ((b[2] >> 2) & 0xf); - *q = (b[2] << 6) | (b[3] & 0x3f); - - q = b3; - while (--i > 0) - putchar(*q++); - - q = b4; - } - } - - *q++ = *p++; /* the last octet */ - ++i; - - if (last || i == 4) { - pack6bit(b4, i, last); - i = 0; - } - - cnt = i; -} - -pack6bit(p, n, last) - register char *p; - register int n; - int last; -{ - register char *q; - register i = 3; - char b3[3]; - - if (last) { - i = p[n-1]; - if (i >= 3) { - fprintf(stderr, "Badly encoded file\n"); - i = 3; /* do the best we can */ - } - } - - q = b3; - *q++ = (p[0] << 2) | ((p[1] >> 4) & 0x3); - *q++ = (p[1] << 4) | ((p[2] >> 2) & 0xf); - *q = (p[2] << 6) | (p[3] & 0x3f); - - q = b3; - - while (--i >= 0) - putchar(*q++); -} *-*-END-of-src/decode.c-*-* exit