Annotation of researchv10no/cmd/pack/pack.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *     Huffman encoding program 
        !             3:  *     Adapted April 1979, from program by T.G. Szymanski, March 1978
        !             4:  *     Usage:  pack [[ - ] filename ... ] filename ...
        !             5:  *             - option: enable/disable listing of statistics
        !             6:  */
        !             7: 
        !             8: #include  <stdio.h>
        !             9: #include <sys/types.h>
        !            10: #include <sys/stat.h>
        !            11: 
        !            12: #define        END     256
        !            13: #define        BLKSIZE 512
        !            14: #define NAMELEN 80
        !            15: #define PACKED 017436 /* <US><RS> - Unlikely value */
        !            16: #define        SUF0    '.'
        !            17: #define        SUF1    'z'
        !            18: 
        !            19: struct stat status, ostatus;
        !            20: 
        !            21: /* union for overlaying a long int with a set of four characters */
        !            22: union FOUR {
        !            23:        struct { long int lng; } l;
        !            24:        struct { char c0, c1, c2, c3; } c;
        !            25: };
        !            26: 
        !            27: /* character counters */
        !            28: long   count [END+1];
        !            29: union  FOUR insize;
        !            30: long   outsize;
        !            31: long   dictsize;
        !            32: int    diffbytes;
        !            33: 
        !            34: /* i/o stuff */
        !            35: char   vflag = 0;
        !            36: char   filename [NAMELEN];
        !            37: int    infile;         /* unpacked file */
        !            38: int    outfile;        /* packed file */
        !            39: char   inbuff [BLKSIZE];
        !            40: char   outbuff [BLKSIZE+4];
        !            41: 
        !            42: /* variables associated with the tree */
        !            43: int    maxlev;
        !            44: int    levcount [25];
        !            45: int    lastnode;
        !            46: int    parent [2*END+1];
        !            47: 
        !            48: /* variables associated with the encoding process */
        !            49: char   length [END+1];
        !            50: long   bits [END+1];
        !            51: union  FOUR mask;
        !            52: long   inc;
        !            53: #ifndef pdp11
        !            54: char *maskshuff[4] = {&(mask.c.c3), &(mask.c.c2), &(mask.c.c1), &(mask.c.c0)};
        !            55: #else
        !            56: char *maskshuff[4] = {&(mask.c.c1), &(mask.c.c0), &(mask.c.c3), &(mask.c.c2)};
        !            57: #endif
        !            58: 
        !            59: /* the heap */
        !            60: int    n;
        !            61: struct heap {
        !            62:        long int count;
        !            63:        int node;
        !            64: } heap [END+2];
        !            65: #define hmove(a,b) {(b).count = (a).count; (b).node = (a).node;}
        !            66: 
        !            67: /* gather character frequency statistics */
        !            68: /* return 1 if successful, 0 otherwise */
        !            69: input ()
        !            70: {
        !            71:        register int i;
        !            72:        for (i=0; i<END; i++)
        !            73:                count[i] = 0;
        !            74:        while ((i = read(infile, inbuff, BLKSIZE)) > 0)
        !            75:                while (i > 0)
        !            76:                        count[inbuff[--i]&0377] += 2;
        !            77:        if (i == 0)
        !            78:                return (1);
        !            79:        printf (": read error");
        !            80:        return (0);
        !            81: }
        !            82: 
        !            83: /* encode the current file */
        !            84: /* return 1 if successful, 0 otherwise */
        !            85: output ()
        !            86: {
        !            87:        int c, i, inleft;
        !            88:        char *inp;
        !            89:        register char **q, *outp;
        !            90:        register int bitsleft;
        !            91:        long temp;
        !            92: 
        !            93:        /* output ``PACKED'' header */
        !            94:        outbuff[0] = 037;       /* ascii US */
        !            95:        outbuff[1] = 036;       /* ascii RS */
        !            96:        /* output the length and the dictionary */
        !            97:        temp = insize.l.lng;
        !            98:        for (i=5; i>=2; i--) {
        !            99:                outbuff[i] =  (char) (temp & 0377);
        !           100:                temp >>= 8;
        !           101:        }
        !           102:        outp = &outbuff[6];
        !           103:        *outp++ = maxlev;
        !           104:        for (i=1; i<maxlev; i++)
        !           105:                *outp++ = levcount[i];
        !           106:        *outp++ = levcount[maxlev]-2;
        !           107:        for (i=1; i<=maxlev; i++)
        !           108:                for (c=0; c<END; c++)
        !           109:                        if (length[c] == i)
        !           110:                                *outp++ = c;
        !           111:        dictsize = outp-&outbuff[0];
        !           112: 
        !           113:        /* output the text */
        !           114:        lseek(infile, 0L, 0);
        !           115:        outsize = 0;
        !           116:        bitsleft = 8;
        !           117:        inleft = 0;
        !           118:        do {
        !           119:                if (inleft <= 0) {
        !           120:                        inleft = read(infile, inp = &inbuff[0], BLKSIZE);
        !           121:                        if (inleft < 0) {
        !           122:                                printf (": read error");
        !           123:                                return (0);
        !           124:                        }
        !           125:                }
        !           126:                c = (--inleft < 0) ? END : (*inp++ & 0377);
        !           127:                mask.l.lng = bits[c]<<bitsleft;
        !           128:                q = &maskshuff[0];
        !           129:                if (bitsleft == 8)
        !           130:                        *outp = **q++;
        !           131:                else
        !           132:                        *outp |= **q++;
        !           133:                bitsleft -= length[c];
        !           134:                while (bitsleft < 0) {
        !           135:                        *++outp = **q++;
        !           136:                        bitsleft += 8;
        !           137:                }
        !           138:                if (outp >= &outbuff[BLKSIZE]) {
        !           139:                        if (write(outfile, outbuff, BLKSIZE) != BLKSIZE) {
        !           140: wrerr:                         printf (".z: write error");
        !           141:                                return (0);
        !           142:                        }
        !           143:                        ((union FOUR *) outbuff)->l.lng = ((union FOUR *) &outbuff[BLKSIZE])->l.lng;
        !           144:                        outp -= BLKSIZE;
        !           145:                        outsize += BLKSIZE;
        !           146:                }
        !           147:        } while (c != END);
        !           148:        if (bitsleft < 8)
        !           149:                outp++;
        !           150:        c = outp-outbuff;
        !           151:        if (write(outfile, outbuff, c) != c)
        !           152:                goto wrerr;
        !           153:        outsize += c;
        !           154:        return (1);
        !           155: }
        !           156: 
        !           157: /* makes a heap out of heap[i],...,heap[n] */
        !           158: heapify (i)
        !           159: {
        !           160:        register int k;
        !           161:        int lastparent;
        !           162:        struct heap heapsubi;
        !           163:        hmove (heap[i], heapsubi);
        !           164:        lastparent = n/2;
        !           165:        while (i <= lastparent) {
        !           166:                k = 2*i;
        !           167:                if (heap[k].count > heap[k+1].count && k < n)
        !           168:                        k++;
        !           169:                if (heapsubi.count < heap[k].count)
        !           170:                        break;
        !           171:                hmove (heap[k], heap[i]);
        !           172:                i = k;
        !           173:        }
        !           174:        hmove (heapsubi, heap[i]);
        !           175: }
        !           176: 
        !           177: /* return 1 after successful packing, 0 otherwise */
        !           178: int packfile ()
        !           179: {
        !           180:        register int c, i, p;
        !           181:        long bitsout;
        !           182: 
        !           183:        /* gather frequency statistics */
        !           184:        if (input() == 0)
        !           185:                return (0);
        !           186: 
        !           187:        /* put occurring chars in heap with their counts */
        !           188:        diffbytes = -1;
        !           189:        count[END] = 1;
        !           190:        insize.l.lng = n = 0;
        !           191:        for (i=END; i>=0; i--) {
        !           192:                parent[i] = 0;
        !           193:                if (count[i] > 0) {
        !           194:                        diffbytes++;
        !           195:                        insize.l.lng += count[i];
        !           196:                        heap[++n].count = count[i];
        !           197:                        heap[n].node = i;
        !           198:                }
        !           199:        }
        !           200:        insize.l.lng >>= 1;
        !           201:        for (i=n/2; i>=1; i--)
        !           202:                heapify(i);
        !           203: 
        !           204:        /* build Huffman tree */
        !           205:        lastnode = END;
        !           206:        while (n > 1) {
        !           207:                parent[heap[1].node] = ++lastnode;
        !           208:                inc = heap[1].count;
        !           209:                hmove (heap[n], heap[1]);
        !           210:                n--;
        !           211:                heapify(1);
        !           212:                parent[heap[1].node] = lastnode;
        !           213:                heap[1].node = lastnode;
        !           214:                heap[1].count += inc;
        !           215:                heapify(1);
        !           216:        }
        !           217:        parent[lastnode] = 0;
        !           218: 
        !           219:        /* assign lengths to encoding for each character */
        !           220:        bitsout = maxlev = 0;
        !           221:        for (i=1; i<=24; i++)
        !           222:                levcount[i] = 0;
        !           223:        for (i=0; i<=END; i++) {
        !           224:                c = 0;
        !           225:                for (p=parent[i]; p!=0; p=parent[p])
        !           226:                        c++;
        !           227:                levcount[c]++;
        !           228:                length[i] = c;
        !           229:                if (c > maxlev)
        !           230:                        maxlev = c;
        !           231:                bitsout += c*(count[i]>>1);
        !           232:        }
        !           233:        if (maxlev > 24) {
        !           234:                /* can't occur unless insize.l.lng >= 2**24 */
        !           235:                printf (": Huffman tree has too many levels");
        !           236:                return(0);
        !           237:        }
        !           238: 
        !           239:        /* bitch if no compression, but do it anyway */
        !           240:        outsize = ((bitsout+7)>>3)+6+maxlev+diffbytes;
        !           241:        if ((insize.l.lng+BLKSIZE-1)/BLKSIZE <= (outsize+BLKSIZE-1)/BLKSIZE) {
        !           242:                printf (": no saving");
        !           243:        }
        !           244: 
        !           245:        /* compute bit patterns for each character */
        !           246:        inc = 1L << 24;
        !           247:        inc >>= maxlev;
        !           248:        mask.l.lng = 0;
        !           249:        for (i=maxlev; i>0; i--) {
        !           250:                for (c=0; c<=END; c++)
        !           251:                        if (length[c] == i) {
        !           252:                                bits[c] = mask.l.lng;
        !           253:                                mask.l.lng += inc;
        !           254:                        }
        !           255:                mask.l.lng &= ~inc;
        !           256:                inc <<= 1;
        !           257:        }
        !           258: 
        !           259:        return (output());
        !           260: }
        !           261: 
        !           262: main(argc, argv)
        !           263: int argc; char *argv[];
        !           264: {
        !           265:        register int i;
        !           266:        register char *cp;
        !           267:        int k, sep;
        !           268:        int fcount =0; /* count failures */
        !           269: 
        !           270:        for (k=1; k<argc; k++)
        !           271:        {       if (argv[k][0] == '-' && argv[k][1] == '\0')
        !           272:                {       vflag = 1 - vflag;
        !           273:                        continue;
        !           274:                }
        !           275:                fcount++; /* increase failure count - expect the worst */
        !           276:                printf ("%s: %s", argv[0], argv[k]);
        !           277:                sep = -1;  cp = filename;
        !           278:                for (i=0; i < (NAMELEN-3) && (*cp = argv[k][i]); i++)
        !           279:                        if (*cp++ == '/') sep = i;
        !           280:                if (cp[-1]==SUF1 && cp[-2]==SUF0)
        !           281:                {       printf (": already packed\n");
        !           282:                        continue;
        !           283:                }
        !           284:                if (i >= (NAMELEN-3) || (i-sep) > 13)
        !           285:                {       printf (": file name too long\n");
        !           286:                        continue;
        !           287:                }
        !           288:                if ((infile = open (filename, 0)) < 0)
        !           289:                {       printf (": cannot open\n");
        !           290:                        continue;
        !           291:                }
        !           292:                fstat(infile,&status);
        !           293:                if (status.st_mode&040000)
        !           294:                {       printf (": cannot pack a directory\n");
        !           295:                        goto closein;
        !           296:                }
        !           297:                if( status.st_nlink != 1 )
        !           298:                {       printf(": has links\n");
        !           299:                        goto closein;
        !           300:                }
        !           301:                *cp++ = SUF0;  *cp++ = SUF1;  *cp = '\0';
        !           302:                if( stat(filename, &ostatus) != -1)
        !           303:                {
        !           304:                        printf(".z: already exists\n");
        !           305:                        goto closein;
        !           306:                }
        !           307:                if ((outfile = creat (filename, status.st_mode&07777)) < 0)
        !           308:                {       printf (".z: cannot create\n");
        !           309:                        goto closein;
        !           310:                }
        !           311:                chown (filename, status.st_uid, status.st_gid);
        !           312: 
        !           313:                if (packfile())
        !           314:                {       unlink(argv[k]);
        !           315:                        fcount--;  /* success after all */
        !           316:                        if(insize.l.lng != 0){
        !           317:                                printf (": %.1f%% Compression\n",
        !           318:                                        ((double)(-outsize+(insize.l.lng))/(double)insize.l.lng)*100);
        !           319:                                /* output statistics */
        !           320:                                if (vflag) {
        !           321:                                        printf("        from %ld to %ld bytes\n",  insize.l.lng, outsize);
        !           322:                                        printf("        Huffman tree has %d levels below root\n", maxlev);
        !           323:                                        printf("        %d distinct bytes in input\n", diffbytes);
        !           324:                                        printf("        dictionary overhead = %ld bytes\n", dictsize);
        !           325:                                        printf("        effective  entropy  = %.2f bits/byte\n", 
        !           326:                                                ((double) outsize / (double) insize.l.lng) * 8 );
        !           327:                                        printf("        asymptotic entropy  = %.2f bits/byte\n", 
        !           328:                                                ((double) (outsize-dictsize) / (double) insize.l.lng) * 8 );
        !           329:                                }
        !           330:                        }
        !           331:                        else printf(": empty file\n");
        !           332:                }
        !           333:                else
        !           334:                {       printf (" - file unchanged\n");
        !           335:                        unlink(filename);
        !           336:                }
        !           337: 
        !           338:       closein: close (outfile);
        !           339:                close (infile);
        !           340:                utime(filename, &status.st_atime);/* preserve acc & mod times */
        !           341:        }
        !           342:        return (fcount);
        !           343: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.