Annotation of researchv10dc/cmd/odist/pax/src/lib/libodelta/delta.c, revision 1.1

1.1     ! root        1: #include       "update.h"
        !             2: #include       "suftree.h"
        !             3: 
        !             4: /*
        !             5: **     Compute delta commands to transform the source string 'src'
        !             6: **     to the target string 'tar'. Small blockmoves are transformed
        !             7: **     to blockadds for space efficiency.
        !             8: **     Return -1 in case of error.
        !             9: **
        !            10: **     For details on computing blockmoves, see:
        !            11: **     "The String-to-String Correction Problem with Block Moves"
        !            12: **     W. Tichy, ACM TOCS, v.2, No.4, 1984, pp.309-321.
        !            13: **
        !            14: **     Written by Kiem-Phong Vo, 5/18/88
        !            15: */
        !            16: 
        !            17: extern char    *malloc();
        !            18: 
        !            19: #define M_MAX  9       /* max size of a block move instruction */
        !            20: #define A_MAX  5       /* max size of the header of an add instruction */
        !            21: 
        !            22: /* structure of a delta instruction */
        !            23: typedef struct _m_
        !            24: {
        !            25:        int             type;   /* DELTA_MOVE or DELTA_ADD */
        !            26:        long            size;   /* size of the block being moved or added */
        !            27:        long            addr;   /* offset where the block starts */
        !            28:        struct _m_      *last;  /* doubly linked list for easy insert/delete */
        !            29:        struct _m_      *next;
        !            30: } Move;
        !            31: 
        !            32: /* bases of the source and target strings */
        !            33: static char    *Bsrc, *Btar;
        !            34: 
        !            35: /* Data buffer area */
        !            36: static char    *Ddata, *Dend, *Dnext;
        !            37: static int     Dfd;
        !            38: 
        !            39: #define delinit(buf,fd)        (Ddata=Dnext=buf, Dend=buf+BUFSIZE, Dfd=fd)
        !            40: #define delflush()     (write(Dfd,Ddata,Dnext-Ddata) >= 0 ? (Dnext=Ddata,0) : -1)
        !            41: 
        !            42: static int delputc(byte)
        !            43: char   byte;
        !            44: {
        !            45:        if(Dnext == Dend)
        !            46:                if(delflush() < 0)
        !            47:                        return -1;
        !            48:        *Dnext++ = byte;
        !            49:        return 0;
        !            50: }
        !            51: 
        !            52: static int delputl(n,v)
        !            53: register int   n;
        !            54: register long  v;
        !            55: {
        !            56:        register int    i;
        !            57:        unsigned char   c[4];
        !            58: 
        !            59:        for(i = 0; i < n; ++i)
        !            60:        {
        !            61:                c[i] = (unsigned char)(v%BASE);
        !            62:                v /= BASE;
        !            63:        }
        !            64:        for(i = n-1; i >= 0; --i)
        !            65:                if(delputc((char)c[i]) < 0)
        !            66:                        return -1;
        !            67:        return 0;
        !            68: }
        !            69: 
        !            70: static int delputs(n,addr)
        !            71: register long  n;
        !            72: register long  addr;
        !            73: {
        !            74:        if(n < (Dend-Dnext))
        !            75:        {
        !            76:                memcopy(Dnext,Btar+addr,n);
        !            77:                Dnext += n;
        !            78:        }
        !            79:        else
        !            80:        {
        !            81:                if(delflush() < 0)
        !            82:                        return -1;
        !            83:                if(write(Dfd,Btar+addr,n) != n)
        !            84:                        return -1;
        !            85:        }
        !            86:        return 0;
        !            87: }
        !            88: 
        !            89: /* write an instruction */
        !            90: static int putMove(this)
        !            91: Move   *this;
        !            92: {
        !            93:        register char   inst;
        !            94: 
        !            95:        inst = this->type;
        !            96:        inst |= (NBYTE(this->size)&07) << 3;
        !            97:        if(this->type == DELTA_MOVE)
        !            98:        {
        !            99:                inst |= NBYTE(this->addr)&07;
        !           100:                if(delputc(inst) < 0 ||
        !           101:                   delputl(NBYTE(this->size),this->size) < 0 ||
        !           102:                   delputl(NBYTE(this->addr),this->addr) < 0)
        !           103:                        return -1;
        !           104:        }
        !           105:        else
        !           106:        {
        !           107:                if(delputc(inst) < 0 ||
        !           108:                   delputl(NBYTE(this->size),this->size) < 0 ||
        !           109:                   delputs(this->size,this->addr) < 0)
        !           110:                        return -1;
        !           111:        }
        !           112:        return 0;
        !           113: }
        !           114: 
        !           115: /* constructor for Move */
        !           116: static Move *newMove(type,size,addr,last)
        !           117: int    type;
        !           118: long   size;
        !           119: long   addr;
        !           120: Move   *last;
        !           121: {
        !           122:        register Move *this = (Move*) malloc(sizeof(Move));
        !           123:        if(this == NIL(Move))
        !           124:                return NIL(Move);
        !           125:        this->type = type;
        !           126:        this->size = size;
        !           127:        this->addr = addr;
        !           128:        if(last)
        !           129:        {
        !           130:                last->next = this;
        !           131:                this->last = last;
        !           132:        }
        !           133:        else    this->last = NIL(Move);
        !           134:        this->next = NIL(Move);
        !           135:        return this;
        !           136: }
        !           137: 
        !           138: /* destructor for Move, return the elt after move */
        !           139: static Move *delMove(this)
        !           140: Move   *this;
        !           141: {
        !           142:        register Move *next = this->next;
        !           143:        register Move *last = this->last;
        !           144:        if(last)
        !           145:                last->next = next;
        !           146:        if(next)
        !           147:                next->last = last;
        !           148:        free((char*)this); 
        !           149:        return next ? next : last;
        !           150: }
        !           151: 
        !           152: /* make a new add command */
        !           153: static Move *makeAdd(beg,end,last)
        !           154: char   *beg, *end;
        !           155: Move   *last;
        !           156: {
        !           157:        register Move   *this;
        !           158: 
        !           159:        this = newMove(DELTA_ADD,(long)(end-beg),(long)(beg-Btar),NIL(Move));
        !           160:        if(!this)
        !           161:                return NIL(Move);
        !           162: 
        !           163:        /* remove small previous adjacent moves */
        !           164:        while(last)
        !           165:        {
        !           166:                register int a_size, cost_m, cost_a;
        !           167: 
        !           168:                if(last->type == DELTA_ADD)
        !           169:                        break;
        !           170: 
        !           171:                cost_m = NBYTE(last->size) + NBYTE(last->addr) +
        !           172:                         NBYTE(this->size) + this->size;
        !           173:                a_size = this->size + last->size;
        !           174:                cost_a = NBYTE(a_size) + a_size;
        !           175:                if(cost_m < cost_a)
        !           176:                        break;
        !           177: 
        !           178:                this->size  = a_size;
        !           179:                this->addr -= last->size;
        !           180:                last = delMove(last);
        !           181:        }
        !           182: 
        !           183:        /* merge with adjacent adds */
        !           184:        if(last && last->type == DELTA_ADD)
        !           185:        {
        !           186:                this->size += last->size;
        !           187:                this->addr -= last->size;
        !           188:                last = delMove(last);
        !           189:        }
        !           190: 
        !           191:        if(last)
        !           192:        {
        !           193:                last->next = this;
        !           194:                this->last = last;
        !           195:        }
        !           196:        return this;
        !           197: }
        !           198: 
        !           199: /* check to see if a move is appropriate */
        !           200: static int chkMove(m_size,m_addr,a_size)
        !           201: long   m_size, m_addr, a_size;
        !           202: {
        !           203:        register int cost_m, cost_a;
        !           204: 
        !           205:        cost_m = NBYTE(m_size) + NBYTE(m_addr);
        !           206:        cost_a = NBYTE(m_size) + m_size;
        !           207:        if(cost_m >= cost_a)
        !           208:                return 0;
        !           209: 
        !           210:        /* it's good but it may be better to merge it to an add */
        !           211:        if(a_size > 0)
        !           212:        {
        !           213:                register int m_cost, a_cost;
        !           214: 
        !           215:                m_cost = cost_m + NBYTE(a_size) + a_size;
        !           216:                a_size += m_size;
        !           217:                a_cost = NBYTE(a_size) + a_size;
        !           218: 
        !           219:                /* it is better to merge! */
        !           220:                if(m_cost >= a_cost)
        !           221:                        return 0;
        !           222:        }
        !           223: 
        !           224:        return m_size;
        !           225: }
        !           226: 
        !           227: /* optimize a sequence of moves */
        !           228: static Move *optMove(s)
        !           229: register Move *s;
        !           230: {
        !           231:        register long   add, m_cost, a_cost;
        !           232:        register Move   *this, *last;
        !           233: 
        !           234:        add = (s->last && s->last->type == DELTA_ADD) ? s->last->size : 0;
        !           235: 
        !           236:        m_cost = 0;
        !           237:        a_cost = 0;
        !           238:        for(this = s; this != NIL(Move); this = this->next)
        !           239:        {
        !           240:                register long cost_m, cost_a;
        !           241: 
        !           242:                if(this->type == DELTA_ADD || this->size > (M_MAX+A_MAX))
        !           243:                        break;
        !           244: 
        !           245:                m_cost += 1+NBYTE(this->size)+NBYTE(this->addr);
        !           246:                a_cost += this->size;
        !           247: 
        !           248:                /* costs of alternatives */
        !           249:                cost_m = m_cost;
        !           250:                cost_a = a_cost;
        !           251:                if(add > 0)
        !           252:                {
        !           253:                        cost_m += 1 + add + NBYTE(add);
        !           254:                        cost_a += add;
        !           255:                }
        !           256:                if(this->next && this->next->type == DELTA_ADD)
        !           257:                {
        !           258:                        cost_m += 1 + this->next->size + NBYTE(this->next->size);
        !           259:                        cost_a += this->next->size;
        !           260:                }
        !           261:                cost_a += 1 + NBYTE(cost_a);
        !           262: 
        !           263:                /* conversion is bad */
        !           264:                if(cost_m < cost_a)
        !           265:                        continue;
        !           266: 
        !           267:                /* convert the entire sequence to an add */
        !           268:                s->type = DELTA_ADD;
        !           269:                while(this != s)
        !           270:                {
        !           271:                        last = this->last;
        !           272:                        s->size += this->size;
        !           273:                        (void)delMove(this);
        !           274:                        this = last;
        !           275:                }
        !           276: 
        !           277:                /* merge adjacent adds */
        !           278:                if((last = s->last) && last->type == DELTA_ADD)
        !           279:                {
        !           280:                        last->size += s->size;
        !           281:                        (void)delMove(s);
        !           282:                        s = last;
        !           283:                } 
        !           284:                if(s->next && s->next->type == DELTA_ADD)
        !           285:                {
        !           286:                        s->size += s->next->size;
        !           287:                        (void)delMove(s->next);
        !           288:                }
        !           289:                /* done */
        !           290:                break;
        !           291:        }
        !           292:        return s;
        !           293: }
        !           294: 
        !           295: /* the real thing */
        !           296: delta(src,n_src,tar,n_tar,delfd)
        !           297: char   *src;
        !           298: long   n_src;
        !           299: char   *tar;
        !           300: long   n_tar;
        !           301: int    delfd;
        !           302: {
        !           303:        register char   *sp, *tp, *esrc, *etar;
        !           304:        register long   size, addr;
        !           305:        Suftree         *tree;
        !           306:        Move            *moves, *last;
        !           307:        char            inst, buf[BUFSIZE];
        !           308:        long            mtchstring();
        !           309: 
        !           310:        /* initialize the output area */
        !           311:        delinit(buf,delfd);
        !           312: 
        !           313:        /* output file sizes */
        !           314:        inst = DELTA_TYPE | ((NBYTE(n_src)&07) << 3) | (NBYTE(n_tar)&07);
        !           315:        if(delputc(inst) < 0)
        !           316:                return -1;
        !           317:        if(delputl(NBYTE(n_src),n_src) < 0 || delputl(NBYTE(n_tar),n_tar) < 0)
        !           318:                return -1;
        !           319: 
        !           320:        /* bases */
        !           321:        Bsrc = src;
        !           322:        Btar = tar;
        !           323:        esrc = src + n_src - 1;
        !           324:        etar = tar + n_tar - 1;
        !           325: 
        !           326:        /* initialize list and last block */
        !           327:        moves = NIL(Move);
        !           328:        last = NIL(Move);
        !           329: 
        !           330:        /* try making suffix tree */
        !           331:        if(!(tree = n_tar > 0 ? bldsuftree(src,n_src) : NIL(Suftree)))
        !           332:        {
        !           333:                /* not enough space for tree, remove matching prefix and suffix */
        !           334:                for(; src <= esrc && tar <= etar; ++src, ++tar)
        !           335:                        if(*src != *tar)
        !           336:                                break;
        !           337:                if((size = src-Bsrc) > 0)
        !           338:                {
        !           339:                        register int cost_m, cost_a;
        !           340: 
        !           341:                        cost_m = NBYTE(size) + NBYTE(0);
        !           342:                        cost_a = NBYTE(size) + size;
        !           343:                        if(cost_m < cost_a)
        !           344:                        {
        !           345:                                moves = newMove(DELTA_MOVE,size,0L,NIL(Move));
        !           346:                                if(!moves)
        !           347:                                        return -1;
        !           348:                                n_src -= src-Bsrc;
        !           349:                                n_tar -= tar-Btar;
        !           350:                        }
        !           351:                        else
        !           352:                        {
        !           353:                                src = Bsrc;
        !           354:                                tar = Btar;
        !           355:                        }
        !           356:                }
        !           357: 
        !           358:                for(sp = esrc, tp = etar; sp >= src && tp >= tar; --sp, --tp)
        !           359:                        if(*sp != *tp)
        !           360:                                break;
        !           361:                if((size = esrc-sp) > 0)
        !           362:                {
        !           363:                        addr = sp+1-Bsrc;
        !           364:                        if(chkMove(size,addr,0L) > 0)
        !           365:                        {
        !           366:                                last = newMove(DELTA_MOVE,size,addr,NIL(Move));
        !           367:                                if(!last)
        !           368:                                        return -1;
        !           369:                                esrc = sp;
        !           370:                                etar = tp;
        !           371:                                n_tar = etar-tar+1;
        !           372:                                n_src = esrc-src+1;
        !           373:                        }
        !           374:                }
        !           375: 
        !           376:                /* try making the tree again */
        !           377:                tree = n_tar > 0 ? bldsuftree(src,n_src) : NIL(Suftree);
        !           378:        }
        !           379: 
        !           380:        /* compute block moves */
        !           381:        tp = NIL(char);
        !           382:        while(n_tar > 0)
        !           383:        {
        !           384:                char    *match;
        !           385: 
        !           386:                if(tree)
        !           387:                        size = mtchsuftree(tree,tar,n_tar,&match);
        !           388:                else    size = mtchstring(src,n_src,tar,n_tar,&match);
        !           389:                if(size < 0)
        !           390:                        return -1;
        !           391:                if(size > 0)
        !           392:                        size = chkMove(size,(long)(match-Bsrc),(long)(tp ? tp-tar : 0));
        !           393: 
        !           394:                /* output a block move */
        !           395:                if(size > 0)
        !           396:                {
        !           397:                        if(tp)
        !           398:                        {
        !           399:                                moves = makeAdd(tp,tar,moves);
        !           400:                                if(!moves)
        !           401:                                        return -1;
        !           402:                                tp = NIL(char);
        !           403:                        }
        !           404:                        moves = newMove(DELTA_MOVE,size,(long)(match-Bsrc),moves);
        !           405:                        if(!moves)
        !           406:                                return -1;
        !           407:                        tar += size;
        !           408:                        n_tar -= size;
        !           409:                }
        !           410:                else
        !           411:                {
        !           412:                        if(!tp)
        !           413:                                tp = tar;
        !           414:                        tar += 1;
        !           415:                        n_tar -= 1;
        !           416:                }
        !           417:        }
        !           418: 
        !           419:        /* add any remaining blocks */
        !           420:        if(tp)
        !           421:        {
        !           422:                if(last && chkMove(last->size,last->addr,(long)(tar-tp)) <= 0)
        !           423:                {
        !           424:                        tar += last->size;
        !           425:                        last = delMove(last);
        !           426:                }
        !           427:                moves = makeAdd(tp,tar,moves);
        !           428:                if(!moves)
        !           429:                        return -1;
        !           430:        }
        !           431:        if(last)
        !           432:        {
        !           433:                moves->next = last;
        !           434:                last->last = moves;
        !           435:        }
        !           436: 
        !           437:        /* release space use for string matching */
        !           438:        if(tree)
        !           439:                delsuftree(tree);
        !           440:        else    mtchstring(NIL(char),0L,NIL(char),0L,NIL(char*));
        !           441: 
        !           442:        /* optimize move instructions */
        !           443:        if(moves)
        !           444:        {
        !           445:                register Move   *this;
        !           446: 
        !           447:                this = moves;
        !           448:                while(this->last)
        !           449:                        this = this->last;
        !           450:                for(; this != NIL(Move); this = this->next)
        !           451:                        if(this->type == DELTA_MOVE && this->size <= (M_MAX+A_MAX))
        !           452:                                moves = this = optMove(this);
        !           453: 
        !           454:                while(moves->last)
        !           455:                        moves = moves->last;
        !           456:        }
        !           457: 
        !           458:        /* write out the move instructions */
        !           459:        addr = 0L;
        !           460:        while(moves)
        !           461:        {
        !           462:                if(moves->type == DELTA_ADD)
        !           463:                        moves->addr = addr;
        !           464:                addr += moves->size;
        !           465:                if(putMove(moves) < 0)
        !           466:                        return -1;
        !           467:                moves = delMove(moves);
        !           468:        }
        !           469: 
        !           470:        /* write ending token */
        !           471:        delputc((char)DELTA_TYPE);
        !           472: 
        !           473:        /* flush buffer */
        !           474:        return delflush();
        !           475: }

unix.superglobalmegacorp.com

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