2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: delta.c /main/3 1995/11/01 19:10:54 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
31 * Copyright (c) 1995 AT&T Corp. *
32 * All Rights Reserved *
34 * This software is licensed by AT&T Corp. *
35 * under the terms and conditions of the license in *
36 * http://www.research.att.com/orgs/ssr/book/reuse *
38 * This software was created by the *
39 * Software Engineering Research Department *
40 * AT&T Bell Laboratories *
42 * For further information contact *
43 * gsf@research.att.com *
45 ***************************************************************/
47 /* : : generated by proto : : */
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__ "C"
57 #define __PROTO__(x) x
59 #define __PARAM__(n,o) n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
72 #define __PROTO__(x) ()
73 #define __OTORP__(x) x
74 #define __PARAM__(n,o) o
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__ ...
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a) va_start(p,a)
90 #define __VA_START__(p,a) va_start(p)
97 ** Compute delta commands to transform the source string 'src'
98 ** to the target string 'tar'. Small blockmoves are transformed
99 ** to blockadds for space efficiency.
100 ** Return -1 in case of error.
102 ** For details on computing blockmoves, see:
103 ** "The String-to-String Correction Problem with Block Moves"
104 ** W. Tichy, ACM TOCS, v.2, No.4, 1984, pp.309-321.
106 ** Written by Kiem-Phong Vo, 5/18/88
109 #define M_MAX 9 /* max size of a block move instruction */
110 #define A_MAX 5 /* max size of the header of an add instruction */
112 /* structure of a delta instruction */
115 int type; /* DELTA_MOVE or DELTA_ADD */
116 long size; /* size of the block being moved or added */
117 long addr; /* offset where the block starts */
118 struct _m_ *last; /* doubly linked list for easy insert/delete */
122 /* bases of the source and target strings */
123 static char *Bsrc, *Btar;
125 /* Data buffer area */
126 static char *Ddata, *Dend, *Dnext;
129 #define delinit(buf,fd) (Ddata=Dnext=buf, Dend=buf+BUFSIZE, Dfd=fd)
130 #define delflush() (write(Dfd,Ddata,Dnext-Ddata) >= 0 ? (Dnext=Ddata,0) : -1)
132 static int delputc __PARAM__((int byte), (byte)) __OTORP__(int byte;){
140 static int delputl __PARAM__((register int n, register long v), (n, v)) __OTORP__(register int n; register long v;){
144 for(i = 0; i < n; ++i)
146 c[i] = (unsigned char)(v%BASE);
149 for(i = n-1; i >= 0; --i)
150 if(delputc((char)c[i]) < 0)
155 static int delputs __PARAM__((register long n, register long addr), (n, addr)) __OTORP__(register long n; register long addr;){
158 memcpy(Dnext,Btar+addr,n);
165 if(write(Dfd,Btar+addr,n) != n)
171 /* write an instruction */
172 static int putMove __PARAM__((Move* ip), (ip)) __OTORP__(Move* ip;){
176 inst |= (NBYTE(ip->size)&07) << 3;
177 if(ip->type == DELTA_MOVE)
179 inst |= NBYTE(ip->addr)&07;
180 if(delputc(inst) < 0 ||
181 delputl(NBYTE(ip->size),ip->size) < 0 ||
182 delputl(NBYTE(ip->addr),ip->addr) < 0)
187 if(delputc(inst) < 0 ||
188 delputl(NBYTE(ip->size),ip->size) < 0 ||
189 delputs(ip->size,ip->addr) < 0)
195 /* constructor for Move */
196 static Move *newMove __PARAM__((int type, long size, long addr, Move* last), (type, size, addr, last)) __OTORP__(int type; long size; long addr; Move* last;){
197 register Move *ip = (Move*) malloc(sizeof(Move));
212 /* destructor for Move, return the elt after move */
213 static Move *delMove __PARAM__((Move* ip), (ip)) __OTORP__(Move* ip;){
214 register Move *next = ip->next;
215 register Move *last = ip->last;
221 return next ? next : last;
224 /* make a new add command */
225 static Move *makeAdd __PARAM__((char* beg, char* end, Move* last), (beg, end, last)) __OTORP__(char* beg; char* end; Move* last;){
228 ip = newMove(DELTA_ADD,(long)(end-beg),(long)(beg-Btar),NiL);
232 /* remove small previous adjacent moves */
235 register int a_size, cost_m, cost_a;
237 if(last->type == DELTA_ADD)
240 cost_m = NBYTE(last->size) + NBYTE(last->addr) +
241 NBYTE(ip->size) + ip->size;
242 a_size = ip->size + last->size;
243 cost_a = NBYTE(a_size) + a_size;
248 ip->addr -= last->size;
249 last = delMove(last);
252 /* merge with adjacent adds */
253 if(last && last->type == DELTA_ADD)
255 ip->size += last->size;
256 ip->addr -= last->size;
257 last = delMove(last);
268 /* check to see if a move is appropriate */
269 static int chkMove __PARAM__((long m_size, long m_addr, long a_size), (m_size, m_addr, a_size)) __OTORP__(long m_size; long m_addr; long a_size;){
270 register int cost_m, cost_a;
272 cost_m = NBYTE(m_size) + NBYTE(m_addr);
273 cost_a = NBYTE(m_size) + m_size;
277 /* it's good but it may be better to merge it to an add */
280 register int m_cost, a_cost;
282 m_cost = cost_m + NBYTE(a_size) + a_size;
284 a_cost = NBYTE(a_size) + a_size;
286 /* it is better to merge! */
294 /* optimize a sequence of moves */
295 static Move *optMove __PARAM__((register Move* s), (s)) __OTORP__(register Move* s;){
296 register long add, m_cost, a_cost;
297 register Move *ip, *last;
299 add = (s->last && s->last->type == DELTA_ADD) ? s->last->size : 0;
303 for(ip = s; ip; ip = ip->next)
305 register long cost_m, cost_a;
307 if(ip->type == DELTA_ADD || ip->size > (M_MAX+A_MAX))
310 m_cost += 1+NBYTE(ip->size)+NBYTE(ip->addr);
313 /* costs of alternatives */
318 cost_m += 1 + add + NBYTE(add);
321 if(ip->next && ip->next->type == DELTA_ADD)
323 cost_m += 1 + ip->next->size + NBYTE(ip->next->size);
324 cost_a += ip->next->size;
326 cost_a += 1 + NBYTE(cost_a);
328 /* conversion is bad */
332 /* convert the entire sequence to an add */
342 /* merge adjacent adds */
343 if((last = s->last) && last->type == DELTA_ADD)
345 last->size += s->size;
349 if(s->next && s->next->type == DELTA_ADD)
351 s->size += s->next->size;
362 delta __PARAM__((char* src, long n_src, char* tar, long n_tar, int delfd), (src, n_src, tar, n_tar, delfd)) __OTORP__(char* src; long n_src; char* tar; long n_tar; int delfd;){
363 register char *sp, *tp, *esrc, *etar;
364 register long size, addr;
367 char inst, buf[BUFSIZE];
369 /* initialize the output area */
372 /* output file sizes */
373 inst = DELTA_TYPE | ((NBYTE(n_src)&07) << 3) | (NBYTE(n_tar)&07);
374 if(delputc(inst) < 0)
376 if(delputl(NBYTE(n_src),n_src) < 0 || delputl(NBYTE(n_tar),n_tar) < 0)
382 esrc = src + n_src - 1;
383 etar = tar + n_tar - 1;
385 /* initialize list and last block */
389 /* try making suffix tree */
390 if(!(tree = n_tar > 0 ? bldsuftree(src,n_src) : (Suftree*)0))
392 /* not enough space for tree, remove matching prefix and suffix */
393 for(; src <= esrc && tar <= etar; ++src, ++tar)
396 if((size = src-Bsrc) > 0)
398 register int cost_m, cost_a;
400 cost_m = NBYTE(size) + NBYTE(0);
401 cost_a = NBYTE(size) + size;
404 moves = newMove(DELTA_MOVE,size,0L,NiL);
417 for(sp = esrc, tp = etar; sp >= src && tp >= tar; --sp, --tp)
420 if((size = esrc-sp) > 0)
423 if(chkMove(size,addr,0L) > 0)
425 last = newMove(DELTA_MOVE,size,addr,NiL);
435 /* try making the tree again */
436 tree = n_tar > 0 ? bldsuftree(src,n_src) : (Suftree*)0;
439 /* compute block moves */
446 size = mtchsuftree(tree,tar,n_tar,&match);
447 else size = mtchstring(src,n_src,tar,n_tar,&match);
451 size = chkMove(size,(long)(match-Bsrc),(long)(tp ? tp-tar : 0));
453 /* output a block move */
458 moves = makeAdd(tp,tar,moves);
463 moves = newMove(DELTA_MOVE,size,(long)(match-Bsrc),moves);
478 /* add any remaining blocks */
481 if(last && chkMove(last->size,last->addr,(long)(tar-tp)) <= 0)
484 last = delMove(last);
486 moves = makeAdd(tp,tar,moves);
496 /* release space use for string matching */
499 else mtchstring(NiL,0L,NiL,0L,NiL);
501 /* optimize move instructions */
509 for(; ip; ip = ip->next)
510 if(ip->type == DELTA_MOVE && ip->size <= (M_MAX+A_MAX))
511 moves = ip = optMove(ip);
517 /* write out the move instructions */
521 if(moves->type == DELTA_ADD)
524 if(putMove(moves) < 0)
526 moves = delMove(moves);
529 /* write ending token */
530 delputc((char)DELTA_TYPE);