/* check to see if a move is appropriate */ static int chkMove(long m_size, long m_addr, long a_size) { register int cost_m, cost_a; cost_m = NBYTE(m_size) + NBYTE(m_addr); cost_a = NBYTE(m_size) + m_size; if(cost_m >= cost_a) return 0; /* it's good but it may be better to merge it to an add */ if(a_size > 0) { register int m_cost, a_cost; m_cost = cost_m + NBYTE(a_size) + a_size; a_size += m_size; a_cost = NBYTE(a_size) + a_size; /* it is better to merge! */ if(m_cost >= a_cost) return 0; } return m_size; }
void _frmergebox(Frame *f, int bn) /* merge bn and bn+1 */ { Frbox *b; b = &f->box[bn]; _frinsure(f, bn, NBYTE(&b[0])+NBYTE(&b[1])+1); strcpy((char*)runeindex(b[0].a.ptr, b[0].nrune), (char*)b[1].a.ptr); b[0].wid += b[1].wid; b[0].nrune += b[1].nrune; _frdelbox(f, bn+1, bn+1); }
/* make a new add command */ static Move *makeAdd(char* beg, char* end, Move* last) { register Move *ip; ip = newMove(DELTA_ADD,(long)(end-beg),(long)(beg-Btar),NiL); if(!ip) return 0; /* remove small previous adjacent moves */ while(last) { register int a_size, cost_m, cost_a; if(last->type == DELTA_ADD) break; cost_m = NBYTE(last->size) + NBYTE(last->addr) + NBYTE(ip->size) + ip->size; a_size = ip->size + last->size; cost_a = NBYTE(a_size) + a_size; if(cost_m < cost_a) break; ip->size = a_size; ip->addr -= last->size; last = delMove(last); } /* merge with adjacent adds */ if(last && last->type == DELTA_ADD) { ip->size += last->size; ip->addr -= last->size; last = delMove(last); } if(last) { last->next = ip; ip->last = last; } return ip; }
int movb(int addr, int addrs) { int n, z; put_value_b(addr, *get_byte_from_memory(addrs)); int op = *get_byte_from_memory(addr); NBYTE(n, op); Z(z, op); set_flags(n, z, 0, flags.C); return 0; }
/* write an instruction */ static int putMove(Move* ip) { register char inst; inst = ip->type; inst |= (NBYTE(ip->size)&07) << 3; if(ip->type == DELTA_MOVE) { inst |= NBYTE(ip->addr)&07; if(delputc(inst) < 0 || delputl(NBYTE(ip->size),ip->size) < 0 || delputl(NBYTE(ip->addr),ip->addr) < 0) return -1; } else { if(delputc(inst) < 0 || delputl(NBYTE(ip->size),ip->size) < 0 || delputs(ip->size,ip->addr) < 0) return -1; } return 0; }
static void dupbox(Frame *f, int bn) { uchar *p; if(f->box[bn].nrune < 0) berror("dupbox"); _fraddbox(f, bn, 1); if(f->box[bn].nrune >= 0){ p = _frallocstr(NBYTE(&f->box[bn])+1); strcpy((char*)p, (char*)f->box[bn].a.ptr); f->box[bn+1].a.ptr = p; } }
int cmpb(int addr, int addrs) { int n, z, v, c; int diff; diff = *get_byte_from_memory(addrs) - *get_byte_from_memory(addr); VBYTE(v, diff); CBYTE(c, diff); NBYTE(n, diff); Z(z, diff); set_flags(n, z, v, c); return 0; }
int incb(int addr, int addrs) { int n, z, v; int op; op = *get_byte_from_memory(addr) + 1; put_value_b(addr, *get_byte_from_memory(addr) + 1); VBYTE(v, op); NBYTE(n, op); Z(z, op); set_flags(n, z, v, flags.C); return 0; }
void _frinsure(Frame *f, int bn, unsigned n) { Frbox *b; uchar *p; b = &f->box[bn]; if(b->nrune < 0) berror("_frinsure"); if(ROUNDUP(b->nrune) > n) /* > guarantees room for terminal NUL */ return; p = _frallocstr(n); b = &f->box[bn]; memmove(p, b->a.ptr, NBYTE(b)+1); free(b->a.ptr); b->a.ptr = p; }
/* the real thing */ int delta(char* src, long n_src, char* tar, long n_tar, int delfd) { register char *sp, *tp, *esrc, *etar; register long size, addr; Suftree *tree; Move *moves, *last; char inst, buf[BUFSIZE]; /* initialize the output area */ delinit(buf,delfd); /* output file sizes */ inst = DELTA_TYPE | ((NBYTE(n_src)&07) << 3) | (NBYTE(n_tar)&07); if(delputc(inst) < 0) return -1; if(delputl(NBYTE(n_src),n_src) < 0 || delputl(NBYTE(n_tar),n_tar) < 0) return -1; /* bases */ Bsrc = src; Btar = tar; esrc = src + n_src - 1; etar = tar + n_tar - 1; /* initialize list and last block */ moves = 0; last = 0; /* try making suffix tree */ if(!(tree = n_tar > 0 ? bldsuftree(src,n_src) : (Suftree*)0)) { /* not enough space for tree, remove matching prefix and suffix */ for(; src <= esrc && tar <= etar; ++src, ++tar) if(*src != *tar) break; if((size = src-Bsrc) > 0) { register int cost_m, cost_a; cost_m = NBYTE(size) + NBYTE(0); cost_a = NBYTE(size) + size; if(cost_m < cost_a) { moves = newMove(DELTA_MOVE,size,0L,NiL); if(!moves) return -1; n_src -= src-Bsrc; n_tar -= tar-Btar; } else { src = Bsrc; tar = Btar; } } for(sp = esrc, tp = etar; sp >= src && tp >= tar; --sp, --tp) if(*sp != *tp) break; if((size = esrc-sp) > 0) { addr = sp+1-Bsrc; if(chkMove(size,addr,0L) > 0) { last = newMove(DELTA_MOVE,size,addr,NiL); if(!last) return -1; esrc = sp; etar = tp; n_tar = etar-tar+1; n_src = esrc-src+1; } } /* try making the tree again */ tree = n_tar > 0 ? bldsuftree(src,n_src) : (Suftree*)0; } /* compute block moves */ tp = 0; while(n_tar > 0) { char *match; if(tree) size = mtchsuftree(tree,tar,n_tar,&match); else size = mtchstring(src,n_src,tar,n_tar,&match); if(size < 0) return -1; if(size > 0) size = chkMove(size,(long)(match-Bsrc),(long)(tp ? tp-tar : 0)); /* output a block move */ if(size > 0) { if(tp) { moves = makeAdd(tp,tar,moves); if(!moves) return -1; tp = 0; } moves = newMove(DELTA_MOVE,size,(long)(match-Bsrc),moves); if(!moves) return -1; tar += size; n_tar -= size; } else { if(!tp) tp = tar; tar += 1; n_tar -= 1; } } /* add any remaining blocks */ if(tp) { if(last && chkMove(last->size,last->addr,(long)(tar-tp)) <= 0) { tar += last->size; last = delMove(last); } moves = makeAdd(tp,tar,moves); if(!moves) return -1; } if(last) { moves->next = last; last->last = moves; } /* release space use for string matching */ if(tree) delsuftree(tree); else mtchstring(NiL,0L,NiL,0L,NiL); /* optimize move instructions */ if(moves) { register Move *ip; ip = moves; while(ip->last) ip = ip->last; for(; ip; ip = ip->next) if(ip->type == DELTA_MOVE && ip->size <= (M_MAX+A_MAX)) moves = ip = optMove(ip); while(moves->last) moves = moves->last; } /* write out the move instructions */ addr = 0L; while(moves) { if(moves->type == DELTA_ADD) moves->addr = addr; addr += moves->size; if(putMove(moves) < 0) return -1; moves = delMove(moves); } /* write ending token */ delputc((char)DELTA_TYPE); /* flush buffer */ return delflush(); }
/* optimize a sequence of moves */ static Move *optMove(register Move* s) { register long add, m_cost, a_cost; register Move *ip, *last; add = (s->last && s->last->type == DELTA_ADD) ? s->last->size : 0; m_cost = 0; a_cost = 0; for(ip = s; ip; ip = ip->next) { register long cost_m, cost_a; if(ip->type == DELTA_ADD || ip->size > (M_MAX+A_MAX)) break; m_cost += 1+NBYTE(ip->size)+NBYTE(ip->addr); a_cost += ip->size; /* costs of alternatives */ cost_m = m_cost; cost_a = a_cost; if(add > 0) { cost_m += 1 + add + NBYTE(add); cost_a += add; } if(ip->next && ip->next->type == DELTA_ADD) { cost_m += 1 + ip->next->size + NBYTE(ip->next->size); cost_a += ip->next->size; } cost_a += 1 + NBYTE(cost_a); /* conversion is bad */ if(cost_m < cost_a) continue; /* convert the entire sequence to an add */ s->type = DELTA_ADD; while(ip != s) { last = ip->last; s->size += ip->size; delMove(ip); ip = last; } /* merge adjacent adds */ if((last = s->last) && last->type == DELTA_ADD) { last->size += s->size; delMove(s); s = last; } if(s->next && s->next->type == DELTA_ADD) { s->size += s->next->size; delMove(s->next); } /* done */ break; } return s; }