Ticket #120: xdiff.c.patch

File xdiff.c.patch, 25.1 KB (added by dborca, 14 years ago)
  • mc-4.6.2-pre1

    diff -Naur mc-4.6.2-pre1~/src/xdiff.c mc-4.6.2-pre1/src/xdiff.c
    old new  
     1/* 
     2 * Copyright (c) 2009 Daniel Borca  All rights reserved. 
     3 * 
     4 * This program is free software; you can redistribute it and/or modify 
     5 * it under the terms of the GNU General Public License as published by 
     6 * the Free Software Foundation; either version 2 of the License, or 
     7 * (at your option) any later version. 
     8 * 
     9 * This program is distributed in the hope that it will be useful, 
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     12 * GNU General Public License for more details. 
     13 * 
     14 * You should have received a copy of the GNU General Public License 
     15 * along with this program; if not, write to the Free Software 
     16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
     17 */ 
     18 
     19 
     20#include <config.h> 
     21#include <errno.h> 
     22#include <sys/stat.h> 
     23#include "global.h" 
     24#include "tty.h" 
     25#include "cmd.h" 
     26#include "dialog.h" 
     27#include "widget.h" 
     28#include "color.h" 
     29#include "help.h" 
     30#include "key.h" 
     31#include "wtools.h" 
     32#include "charsets.h" 
     33#include "zutil.h" 
     34#include "ydiff.h" 
     35#include "xdiff.h" 
     36 
     37 
     38#ifdef USE_DIFF_VIEW 
     39 
     40#define VERTICAL_SPLIT          0 
     41 
     42#define REINIT_READ_LEFT        (1 << 0) 
     43#define REINIT_READ_RIGHT       (1 << 1) 
     44#define REINIT_REALLOC          (1 << 2) 
     45 
     46#define XDIFF_IN_LEFT           (1 << 0) 
     47#define XDIFF_IN_RIGHT          (1 << 1) 
     48#define XDIFF_DIFFERENT         (1 << 2) 
     49 
     50typedef struct { 
     51    Widget widget; 
     52 
     53    const char *file[2];        /* filenames */ 
     54    const char *label[2]; 
     55    FBUF *f[2]; 
     56    char *fdata, *diffs, *data[2]; 
     57    size_t sz[2]; 
     58    off_t offs[2]; 
     59    off_t last[2]; 
     60    off_t end[2]; 
     61    off_t max; 
     62    size_t pbytes; 
     63    size_t maxmem; 
     64    int nbytes; 
     65    int owidth; 
     66    int move[2]; 
     67 
     68    int view_quit:1;            /* Quit flag */ 
     69 
     70    int size; 
     71    int half1; 
     72    int half2; 
     73    int bias; 
     74    int subtract; 
     75    int new_frame; 
     76    int display_numbers; 
     77    int ord; 
     78    int full; 
     79    int last_found; 
     80} WDiff; 
     81 
     82 
     83#define OPTX 50 
     84#define OPTY 7 
     85 
     86static QuickWidget diffopt_widgets[] = { 
     87    { quick_button,   6,   10, 3, OPTY, N_("&Cancel"),                 0, B_CANCEL, NULL, NULL, NULL }, 
     88    { quick_button,   3,   10, 3, OPTY, N_("&OK"),                     0, B_ENTER,  NULL, NULL, NULL }, 
     89    NULL_QuickWidget 
     90}; 
     91 
     92static QuickDialog diffopt = { 
     93    OPTX, OPTY, -1, -1, 
     94    N_(" Diff Options "), "[Diff Options]", 
     95    diffopt_widgets, 0 
     96}; 
     97 
     98 
     99#define error_dialog(h, s) query_dialog(h, s, D_ERROR, 1, _("&Dismiss")) 
     100 
     101 
     102/* diff engine ***************************************************************/ 
     103 
     104 
     105static int 
     106redo_diff (WDiff *view, int flags, size_t pbytes) 
     107{ 
     108    if (flags & REINIT_REALLOC) { 
     109        if (pbytes > view->maxmem) { 
     110            void *p = realloc(view->fdata, 3 * pbytes); 
     111            if (p == NULL) { 
     112                view->view_quit = 1; 
     113                return -1; 
     114            } 
     115            view->fdata = p; 
     116            view->maxmem = pbytes; 
     117        } 
     118        view->pbytes = pbytes; 
     119        view->diffs = view->fdata; 
     120        view->data[0] = view->diffs + pbytes; 
     121        view->data[1] = view->data[0] + pbytes; 
     122        flags = REINIT_READ_LEFT | REINIT_READ_RIGHT; 
     123    } 
     124    if (flags & REINIT_READ_LEFT) { 
     125        f_seek(view->f[0], view->offs[0], SEEK_SET); 
     126        view->sz[0] = f_read(view->f[0], view->data[0], pbytes); 
     127        if (view->sz[0]) { 
     128            if (view->sz[0] < pbytes) { 
     129                view->end[0] = view->offs[0] + view->sz[0]; 
     130            } 
     131        } else { 
     132            view->end[0] = f_seek(view->f[0], 0, SEEK_END); 
     133        } 
     134    } 
     135    if (flags & REINIT_READ_RIGHT) { 
     136        f_seek(view->f[1], view->offs[1], SEEK_SET); 
     137        view->sz[1] = f_read(view->f[1], view->data[1], pbytes); 
     138        if (view->sz[1]) { 
     139            if (view->sz[1] < pbytes) { 
     140                view->end[1] = view->offs[1] + view->sz[1]; 
     141            } 
     142        } else { 
     143            view->end[1] = f_seek(view->f[1], 0, SEEK_END); 
     144        } 
     145    } 
     146    if (flags & (REINIT_READ_LEFT | REINIT_READ_RIGHT)) { 
     147        size_t i, len; 
     148        char *data1 = view->data[0]; 
     149        char *data2 = view->data[1]; 
     150        char *diffs = view->diffs; 
     151        size_t sz1 = view->sz[0]; 
     152        size_t sz2 = view->sz[1]; 
     153        len = sz1; 
     154        if (len > sz2) { 
     155            len = sz2; 
     156        } 
     157        memset(diffs, 0, pbytes); 
     158        for (i = 0; i < len; i++) { 
     159            diffs[i] = XDIFF_IN_LEFT | XDIFF_IN_RIGHT; 
     160            if (data1[i] != data2[i]) { 
     161                diffs[i] |= XDIFF_DIFFERENT; 
     162            } 
     163        } 
     164        for (i = len; i < sz1; i++) { 
     165            diffs[i] = XDIFF_IN_LEFT | XDIFF_DIFFERENT; 
     166        } 
     167        for (i = len; i < sz2; i++) { 
     168            diffs[i] = XDIFF_IN_RIGHT | XDIFF_DIFFERENT; 
     169        } 
     170    } 
     171    view->max = view->end[0]; 
     172    if (view->max < view->end[1]) { 
     173        view->max = view->end[1]; 
     174    } 
     175    return 0; 
     176} 
     177 
     178 
     179/* stuff *********************************************************************/ 
     180 
     181 
     182/** 
     183 * Read offset from string. 
     184 * 
     185 * \param[in,out] str string to parse 
     186 * \param[out] n extracted offset 
     187 * 
     188 * \return 0 if success, otherwise non-zero 
     189 */ 
     190static int 
     191scan_unsigned (const char **str, off_t *n) 
     192{ 
     193    const char *p = *str; 
     194    char *q; 
     195    errno = 0; 
     196    *n = strtoul(p, &q, 0); /* XXX strtoull */ 
     197    if (errno || p == q) { 
     198        return -1; 
     199    } 
     200    *str = q; 
     201    return 0; 
     202} 
     203 
     204 
     205static int 
     206get_nibbles (off_t n) 
     207{ 
     208    int d = 1; 
     209    while (n >>= 4) { 
     210        d++; 
     211    } 
     212    return d; 
     213} 
     214 
     215 
     216static int 
     217find_prev_hunk (WDiff *view) 
     218{ 
     219    int i; 
     220    int pbytes = view->pbytes; 
     221 
     222    for (;;) { 
     223        int sub; 
     224        int sub1 = pbytes; 
     225        int sub2 = pbytes; 
     226 
     227        if (sub1 > view->offs[0]) { 
     228            sub1 = view->offs[0]; 
     229        } 
     230        if (sub2 > view->offs[1]) { 
     231            sub2 = view->offs[1]; 
     232        } 
     233 
     234        sub = sub1; 
     235        if (sub > sub2) { 
     236            sub = sub2; 
     237        } 
     238 
     239        if (sub == 0) { 
     240            return 0; 
     241        } 
     242 
     243        view->offs[0] -= sub; 
     244        view->offs[1] -= sub; 
     245 
     246        if (redo_diff(view, REINIT_READ_LEFT | REINIT_READ_RIGHT, pbytes) < 0) { 
     247            return -1; 
     248        } 
     249 
     250        i = sub; 
     251        while (i > 0 && !(view->diffs[i - 1] & XDIFF_DIFFERENT)) { 
     252            i--; 
     253        } 
     254        if (i > 0) { 
     255            break; 
     256        } 
     257    } 
     258 
     259    for (;;) { 
     260        int sub; 
     261        int sub1 = pbytes; 
     262        int sub2 = pbytes; 
     263 
     264        while (i > 0 && (view->diffs[i - 1] & XDIFF_DIFFERENT)) { 
     265            i--; 
     266        } 
     267        if (i > 0) { 
     268            view->offs[0] += i; 
     269            view->offs[1] += i; 
     270            break; 
     271        } 
     272 
     273        if (sub1 > view->offs[0]) { 
     274            sub1 = view->offs[0]; 
     275        } 
     276        if (sub2 > view->offs[1]) { 
     277            sub2 = view->offs[1]; 
     278        } 
     279 
     280        sub = sub1; 
     281        if (sub > sub2) { 
     282            sub = sub2; 
     283        } 
     284 
     285        if (sub == 0) { 
     286            return 0; 
     287        } 
     288 
     289        view->offs[0] -= sub; 
     290        view->offs[1] -= sub; 
     291 
     292        if (redo_diff(view, REINIT_READ_LEFT | REINIT_READ_RIGHT, pbytes) < 0) { 
     293            return -1; 
     294        } 
     295 
     296        i = sub; 
     297    } 
     298    return 0; 
     299} 
     300 
     301 
     302static int 
     303find_next_hunk (WDiff *view) 
     304{ 
     305    int i; 
     306    int pbytes = view->pbytes; 
     307 
     308    for (;;) { 
     309        i = 0; 
     310        while (i < pbytes && (view->diffs[i] & XDIFF_DIFFERENT)) { 
     311            i++; 
     312        } 
     313        if (i < pbytes) { 
     314            break; 
     315        } 
     316        view->offs[0] += i; 
     317        view->offs[1] += i; 
     318        if (redo_diff(view, REINIT_READ_LEFT | REINIT_READ_RIGHT, pbytes) < 0) { 
     319            return -1; 
     320        } 
     321    } 
     322 
     323    for (;;) { 
     324        while (i < pbytes && !(view->diffs[i] & XDIFF_DIFFERENT) && view->diffs[i]) { 
     325            i++; 
     326        } 
     327        view->offs[0] += i; 
     328        view->offs[1] += i; 
     329        if (i < pbytes) { 
     330            break; 
     331        } 
     332        if (redo_diff(view, REINIT_READ_LEFT | REINIT_READ_RIGHT, pbytes) < 0) { 
     333            return -1; 
     334        } 
     335        i = 0; 
     336    } 
     337 
     338    return 0; 
     339} 
     340 
     341 
     342/* view routines and callbacks ***********************************************/ 
     343 
     344 
     345static void 
     346view_compute_split (WDiff *view, int i) 
     347{ 
     348    view->bias += i; 
     349#if !VERTICAL_SPLIT 
     350    if (view->bias < 2 - view->half1) { 
     351        view->bias = 2 - view->half1; 
     352    } 
     353    if (view->bias > view->half2 - 2) { 
     354        view->bias = view->half2 - 2; 
     355    } 
     356#else   /* VERTICAL_SPLIT */ 
     357    if (view->bias < 1 - view->half1) { 
     358        view->bias = 1 - view->half1; 
     359    } 
     360    if (view->bias > view->half2 - 1) { 
     361        view->bias = view->half2 - 1; 
     362    } 
     363#endif  /* VERTICAL_SPLIT */ 
     364} 
     365 
     366 
     367static void 
     368view_compute_areas (WDiff *view) 
     369{ 
     370#if !VERTICAL_SPLIT 
     371    view->size = LINES - 2; 
     372    view->half1 = COLS / 2; 
     373    view->half2 = COLS - view->half1; 
     374#else   /* VERTICAL_SPLIT */ 
     375    int height = LINES - 3; 
     376 
     377    view->size = COLS; 
     378    view->half1 = height / 2; 
     379    view->half2 = height - view->half1; 
     380#endif  /* VERTICAL_SPLIT */ 
     381 
     382    view_compute_split(view, 0); 
     383} 
     384 
     385 
     386static int 
     387view_init (WDiff *view, const char *file1, const char *file2, const char *label1, const char *label2) 
     388{ 
     389    FBUF *f[2]; 
     390 
     391    f[0] = f_open(file1, O_RDONLY); 
     392    if (f[0] == NULL) { 
     393        return -1; 
     394    } 
     395    f[1] = f_open(file2, O_RDONLY); 
     396    if (f[1] == NULL) { 
     397        f_close(f[0]); 
     398        return -1; 
     399    } 
     400 
     401    view->file[0] = file1; 
     402    view->file[1] = file2; 
     403    view->label[0] = label1; 
     404    view->label[1] = label2; 
     405    view->f[0] = f[0]; 
     406    view->f[1] = f[1]; 
     407    view->fdata = NULL; 
     408    view->diffs = NULL; 
     409    view->data[0] = NULL; 
     410    view->data[1] = NULL; 
     411    view->move[0] = 1; 
     412    view->move[1] = 1; 
     413    view->end[0] = f_seek(f[0], 0, SEEK_END); 
     414    view->end[1] = f_seek(f[1], 0, SEEK_END); 
     415    view->max = view->end[0]; 
     416    if (view->max < view->end[1]) { 
     417        view->max = view->end[1]; 
     418    } 
     419 
     420    view->view_quit = 0; 
     421 
     422    view->bias = 0; 
     423    view->subtract = 0; 
     424    view->new_frame = 1; 
     425    view->display_numbers = 1; 
     426    view->ord = 0; 
     427    view->full = 0; 
     428    view->last_found = -1; 
     429 
     430    view_compute_areas(view); 
     431    return 0; 
     432} 
     433 
     434 
     435static int 
     436view_reinit (WDiff *view) 
     437{ 
     438    if (quick_dialog(&diffopt) != B_CANCEL) { 
     439        return redo_diff(view, REINIT_READ_LEFT | REINIT_READ_RIGHT, view->pbytes); 
     440    } 
     441    return 0; 
     442} 
     443 
     444 
     445static void 
     446view_fini (WDiff *view) 
     447{ 
     448    free(view->fdata); 
     449 
     450    f_close(view->f[1]); 
     451    f_close(view->f[0]); 
     452} 
     453 
     454 
     455static int 
     456view_display_file (WDiff *view, int ord, 
     457                   int r, int c, int height, int width, 
     458#if VERTICAL_SPLIT 
     459                   int total_height, 
     460#endif  /* VERTICAL_SPLIT */ 
     461                   int owidth) 
     462{ 
     463    int i, j, k; 
     464    char buf[BUFSIZ]; 
     465    const char *data = view->data[ord]; 
     466    const char *diffs = view->diffs; 
     467    off_t offset = view->offs[ord]; 
     468    int nbytes = view->nbytes; 
     469 
     470    off_t mask = 0; 
     471 
     472    int available = width - (nbytes * 4 + 1); 
     473    if (owidth > available - 1) { 
     474        owidth = available - 1; 
     475        if (owidth < 0) { 
     476            owidth = 0; 
     477        } 
     478    } 
     479 
     480    if (owidth > 0) { 
     481        mask = ((((off_t)1 << ((owidth - 1) * 4)) - 1) << 4) | 0xF; 
     482        owidth++; 
     483    } 
     484 
     485    if ((int)sizeof(buf) <= width) { 
     486        /* abnormal, but avoid buffer overflow */ 
     487        return -1; 
     488    } 
     489 
     490    for (j = 0; j < height; j++) { 
     491        int ch; 
     492        int stop = 1; 
     493 
     494        tty_gotoyx(r + j, c); 
     495 
     496        if (owidth > 0) { 
     497            sprintf(buf, "%0*llX ", owidth - 1, offset & mask); 
     498            tty_setcolor(MARKED_COLOR); 
     499            tty_print_nstring(buf, owidth); 
     500        } 
     501 
     502        for (i = owidth, k = 0; k < nbytes; k++, i += 3) { 
     503            ch = *data++; 
     504            if (diffs[k] & (1 << ord)) { 
     505                stop = 0; 
     506                sprintf(buf + i, "%02X ", ch & 0xFF); 
     507                ch = convert_to_display_c(ch); 
     508                if (!is_printable(ch)) { 
     509                    ch = '.'; 
     510                } 
     511            } else { 
     512                buf[i + 0] = ' '; 
     513                buf[i + 1] = ' '; 
     514                buf[i + 2] = ' '; 
     515                buf[i + 3] = '\0'; 
     516                ch = ' '; 
     517            } 
     518            buf[owidth + 3 * nbytes + 1 + k] = ch; 
     519            if (diffs[k] & XDIFF_DIFFERENT) { 
     520                tty_setcolor(VIEW_UNDERLINED_COLOR); 
     521            } else { 
     522                tty_setcolor(NORMAL_COLOR); 
     523            } 
     524            tty_print_nstring(buf + i, 3); 
     525        } 
     526 
     527        tty_setcolor(NORMAL_COLOR); 
     528        if (i < width) { 
     529            buf[i] = ' '; 
     530            tty_print_char(buf[i]); 
     531            i++; 
     532        } 
     533 
     534        for (k = 0; k < nbytes; k++, i++) { 
     535            if (*diffs++ & XDIFF_DIFFERENT) { 
     536                tty_setcolor(VIEW_UNDERLINED_COLOR); 
     537            } else { 
     538                tty_setcolor(NORMAL_COLOR); 
     539            } 
     540            tty_print_char(buf[i] & 0xFF); 
     541        } 
     542 
     543        tty_setcolor(NORMAL_COLOR); 
     544        for (; i < width; i++) { 
     545            buf[i] = ' '; 
     546            tty_print_char(buf[i]); 
     547        } 
     548 
     549        buf[width] = '\0';      /* XXX we fully construct the buffer, but don't necessarily have to */ 
     550 
     551        offset += nbytes; 
     552        if (stop) { 
     553            break; 
     554        } 
     555    } 
     556#if VERTICAL_SPLIT 
     557    height = total_height; 
     558#endif  /* VERTICAL_SPLIT */ 
     559    if (j < height) { 
     560        memset(buf, ' ', width); 
     561        buf[width] = '\0'; 
     562        for (; j < height; j++) { 
     563            tty_gotoyx(r + j, c); 
     564            tty_print_nstring(buf, width); 
     565        } 
     566    } 
     567 
     568    return 0; 
     569} 
     570 
     571 
     572static void 
     573view_status (WDiff *view, int ord, int width, int pos) 
     574{ 
     575    char buf[BUFSIZ]; 
     576    int filename_width; 
     577    off_t skip_offs = view->offs[ord]; 
     578    int moves = view->move[ord]; 
     579 
     580    tty_setcolor(SELECTED_COLOR); 
     581 
     582#if !VERTICAL_SPLIT 
     583    tty_gotoyx(0, pos); 
     584#else   /* VERTICAL_SPLIT */ 
     585    tty_gotoyx(pos, 0); 
     586#endif  /* VERTICAL_SPLIT */ 
     587 
     588    filename_width = width - 22; 
     589    if (filename_width < 8) { 
     590        filename_width = 8; 
     591    } 
     592    if (filename_width >= (int)sizeof(buf)) { 
     593        /* abnormal, but avoid buffer overflow */ 
     594        filename_width = sizeof(buf) - 1; 
     595    } 
     596    trim(strip_home_and_password(view->label[ord]), buf, filename_width); 
     597    tty_printf("%-*s   %s%-16lX ", filename_width, buf, moves ? "0x" : "--", skip_offs); 
     598} 
     599 
     600 
     601static void 
     602view_update (WDiff *view) 
     603{ 
     604    int size = view->size; 
     605    int min_size; 
     606    int size1; 
     607    int size2; 
     608    int pbytes; 
     609    int owidth = 0; 
     610    off_t u = view->max - 1; 
     611 
     612    if (view->offs[0] > u) { 
     613        view->offs[0] = u; 
     614    } 
     615    if (view->offs[1] > u) { 
     616        view->offs[1] = u; 
     617    } 
     618    if (view->offs[0] < 0) { 
     619        view->offs[0] = 0; 
     620    } 
     621    if (view->offs[1] < 0) { 
     622        view->offs[1] = 0; 
     623    } 
     624 
     625    /* XXX some more sanity checks (LINES/COLS)? */ 
     626#if !VERTICAL_SPLIT 
     627    if (size < 2) { 
     628        return; 
     629    } 
     630 
     631    size1 = view->half1 + view->bias; 
     632    size2 = view->half2 - view->bias; 
     633    if (view->full) { 
     634        size1 = COLS; 
     635        size2 = 0; 
     636    } 
     637 
     638    if (view->display_numbers) { 
     639#if 0 
     640        off_t n = view->max;    /* XXX might change at each redo_diff */ 
     641        for (owidth = 1; n >>= 4; owidth++) { 
     642        } 
     643#else 
     644        owidth = 4; 
     645#endif 
     646    } 
     647#else   /* VERTICAL_SPLIT */ 
     648 
     649    size1 = view->half1 + view->bias; 
     650    size2 = view->half2 - view->bias; 
     651    if (view->full) { 
     652        size1 = LINES - 2; 
     653        size2 = 0; 
     654    } 
     655 
     656    min_size = size1; 
     657    if (size2 && size2 < size1) { 
     658        min_size = size2; 
     659    } 
     660 
     661    if (view->display_numbers) { 
     662        owidth = 4; 
     663        if (size >= 8 + 16 * 4 + 2) { 
     664            owidth = 8; 
     665        } 
     666    } 
     667#endif  /* VERTICAL_SPLIT */ 
     668 
     669    if (view->new_frame) { 
     670        Dlg_head *h = view->widget.parent; 
     671 
     672#if !VERTICAL_SPLIT 
     673        min_size = size1; 
     674        if (size2 && size2 < size1) { 
     675            min_size = size2; 
     676        } 
     677        view->nbytes = min_size - 2 - 1; 
     678#else   /* VERTICAL_SPLIT */ 
     679        view->nbytes = size - 1; 
     680#endif  /* VERTICAL_SPLIT */ 
     681        if (owidth) { 
     682            if (view->nbytes - 4 >= owidth + 1) { 
     683                view->nbytes -= owidth + 1; 
     684            } else if (view->nbytes - 4 > 1) { 
     685                view->nbytes = 4; 
     686            } 
     687        } 
     688        if (view->nbytes < 0) { 
     689            view->nbytes = 0;   /* XXX sanity checks should prevent this */ 
     690        } 
     691        view->nbytes /= 4; 
     692        if (view->nbytes <= view->subtract) { 
     693            view->subtract = view->nbytes - 1; 
     694            if (view->subtract < 0) { 
     695                view->subtract = 0; 
     696            } 
     697        } 
     698        view->nbytes -= view->subtract; 
     699#if !VERTICAL_SPLIT 
     700        pbytes = view->nbytes * (size - 2); 
     701#else   /* VERTICAL_SPLIT */ 
     702        pbytes = view->nbytes * min_size; 
     703#endif  /* VERTICAL_SPLIT */ 
     704        if (redo_diff(view, REINIT_REALLOC, pbytes) < 0) { 
     705            return; 
     706        } 
     707        view->last[0] = view->offs[0]; 
     708        view->last[1] = view->offs[1]; 
     709 
     710        tty_setcolor(NORMAL_COLOR); 
     711#if !VERTICAL_SPLIT 
     712        if (size1 > 1) { 
     713            draw_double_box(h, 1, 0,     size, size1); 
     714        } 
     715        if (size2 > 1) { 
     716            draw_double_box(h, 1, size1, size, size2); 
     717        } 
     718#endif  /* !VERTICAL_SPLIT */ 
     719 
     720        view->new_frame = 0; 
     721    } 
     722 
     723    if (view->last[0] != view->offs[0] || view->last[1] != view->offs[1]) { 
     724        int flags = 0; 
     725        if (view->last[0] != view->offs[0]) { 
     726            flags |= REINIT_READ_LEFT; 
     727        } 
     728        if (view->last[1] != view->offs[1]) { 
     729            flags |= REINIT_READ_RIGHT; 
     730        } 
     731        if (redo_diff(view, flags, view->pbytes) < 0) { 
     732            return; 
     733        } 
     734        view->last[0] = view->offs[0]; 
     735        view->last[1] = view->offs[1]; 
     736    } 
     737 
     738#if !VERTICAL_SPLIT 
     739    if (size1 > 2) { 
     740        view_status(view, view->ord,     size1, 0); 
     741        view_display_file(view, view->ord,     2,         1,         size - 2, size1 - 2,        owidth); 
     742    } 
     743    if (size2 > 2) { 
     744        view_status(view, view->ord ^ 1, size2, size1); 
     745        view_display_file(view, view->ord ^ 1, 2,         size1 + 1, size - 2, size2 - 2,        owidth); 
     746    } 
     747#else   /* VERTICAL_SPLIT */ 
     748    if (size1 > 0) { 
     749        view_status(view, view->ord,     size, 0); 
     750        view_display_file(view, view->ord,     1,         0,         min_size, size,      size1, owidth); 
     751    } 
     752    if (size2 > 0) { 
     753        view_status(view, view->ord ^ 1, size, size1 + 1); 
     754        view_display_file(view, view->ord ^ 1, size1 + 2, 0,         min_size, size,      size2, owidth); 
     755    } 
     756#endif  /* VERTICAL_SPLIT */ 
     757} 
     758 
     759 
     760static void 
     761view_redo (WDiff *view) 
     762{ 
     763    /* XXX this is here only because of [yz]diff.  Our owidth may change unexpectedly, so don't update it here */ 
     764    view_reinit(view); 
     765} 
     766 
     767 
     768static void 
     769view_search (WDiff *view, int again) 
     770{ 
     771    if (again < 0) { 
     772        return; 
     773    } 
     774 
     775    /* XXX */ 
     776    error_dialog(_("Search"), _(" Search not yet implemented ")); 
     777} 
     778 
     779 
     780static void 
     781view_search_cmd (WDiff *view) 
     782{ 
     783    view_search(view, 0); 
     784} 
     785 
     786 
     787static void 
     788view_edit (WDiff *view, int ord) 
     789{ 
     790    /* XXX */ 
     791    error_dialog(_("Edit"), _(" Edit not yet implemented ")); 
     792} 
     793 
     794 
     795static void 
     796view_edit_cmd (WDiff *view) 
     797{ 
     798    view_edit(view, view->ord); 
     799} 
     800 
     801 
     802static void 
     803view_goto_cmd (WDiff *view) 
     804{ 
     805    static char prev[256]; 
     806    /* XXX some statics here, to be remembered between runs */ 
     807 
     808    off_t address; 
     809    char *input; 
     810 
     811    input = input_dialog(_(" Goto Address "), _(" Enter Address: "), prev); 
     812    if (input != NULL) { 
     813        const char *s = input; 
     814        if (scan_unsigned(&s, &address) == 0 && *s == '\0') { 
     815            if (view->move[0]) view->offs[0] = address; 
     816            if (view->move[1]) view->offs[1] = address; 
     817            view->last_found = -1; 
     818            view_update(view); 
     819        } 
     820        g_free(input); 
     821    } 
     822} 
     823 
     824 
     825static void 
     826view_help_cmd (void) 
     827{ 
     828    interactive_display(NULL, "[Binary Diff Viewer]"); 
     829} 
     830 
     831 
     832static void 
     833view_quit_cmd (WDiff *view) 
     834{ 
     835    dlg_stop(view->widget.parent); 
     836} 
     837 
     838 
     839static void 
     840view_labels (WDiff *view) 
     841{ 
     842    Dlg_head *h = view->widget.parent; 
     843 
     844    buttonbar_set_label(h, 1, Q_("ButtonBar|Help"), view_help_cmd); 
     845 
     846    buttonbar_set_label_data(h, 4, Q_("ButtonBar|Edit"), (buttonbarfn)view_edit_cmd, view); 
     847    buttonbar_set_label_data(h, 5, Q_("ButtonBar|Goto"), (buttonbarfn)view_goto_cmd, view); 
     848    buttonbar_set_label_data(h, 7, Q_("ButtonBar|Search"), (buttonbarfn)view_search_cmd, view); 
     849    buttonbar_set_label_data(h, 10, Q_("ButtonBar|Quit"), (buttonbarfn)view_quit_cmd, view); 
     850} 
     851 
     852 
     853static int 
     854view_event (Gpm_Event *event, void *x) 
     855{ 
     856    WDiff *view = (WDiff *)x; 
     857    int result = MOU_NORMAL; 
     858 
     859    /* We are not interested in the release events */ 
     860    if (!(event->type & (GPM_DOWN | GPM_DRAG))) { 
     861        return result; 
     862    } 
     863 
     864    /* Wheel events */ 
     865    if ((event->buttons & GPM_B_UP) && (event->type & GPM_DOWN)) { 
     866        if (view->move[0]) view->offs[0] -= view->nbytes; 
     867        if (view->move[1]) view->offs[1] -= view->nbytes; 
     868        view_update(view); 
     869        return result; 
     870    } 
     871    if ((event->buttons & GPM_B_DOWN) && (event->type & GPM_DOWN)) { 
     872        if (view->move[0]) view->offs[0] += view->nbytes; 
     873        if (view->move[1]) view->offs[1] += view->nbytes; 
     874        view_update(view); 
     875        return result; 
     876    } 
     877 
     878    return result; 
     879} 
     880 
     881 
     882static cb_ret_t 
     883view_handle_key (WDiff *view, int c) 
     884{ 
     885    c = convert_from_input_c(c); 
     886 
     887    switch (c) { 
     888        case 'l': 
     889            view->display_numbers ^= 1; 
     890            view->new_frame = 1; 
     891            return MSG_HANDLED; 
     892 
     893        case 'f': 
     894            view->full ^= 1; 
     895            view->new_frame = 1; 
     896            return MSG_HANDLED; 
     897 
     898        case '=': /* XXX testing only */ 
     899            if (!view->full) { 
     900                view->bias = 0; 
     901                view->new_frame = 1; 
     902            } 
     903            return MSG_HANDLED; 
     904 
     905        case '>': /* XXX testing only */ 
     906            if (!view->full) { 
     907                view_compute_split(view, 1); 
     908                view->new_frame = 1; 
     909            } 
     910            return MSG_HANDLED; 
     911 
     912        case '<': /* XXX testing only */ 
     913            if (!view->full) { 
     914                view_compute_split(view, -1); 
     915                view->new_frame = 1; 
     916            } 
     917            return MSG_HANDLED; 
     918 
     919        case '+': 
     920            if (view->subtract) { 
     921                view->subtract--; 
     922                view->new_frame = 1; 
     923            } 
     924            return MSG_HANDLED; 
     925        case '-': 
     926            view->subtract++; 
     927            view->new_frame = 1; 
     928            return MSG_HANDLED; 
     929 
     930        case '1': 
     931            view->move[0] = 1; 
     932            view->move[1] ^= 1; 
     933            return MSG_HANDLED; 
     934        case '2': 
     935            view->move[0] ^= 1; 
     936            view->move[1] = 1; 
     937            return MSG_HANDLED; 
     938 
     939        case XCTRL('u'): { 
     940            int tmp = view->move[0]; 
     941            view->move[0] = view->move[1]; 
     942            view->move[1] = tmp; 
     943            view->ord ^= 1; 
     944            return MSG_HANDLED; 
     945        } 
     946 
     947        case XCTRL('r'): 
     948            view_redo(view); 
     949            return MSG_HANDLED; 
     950 
     951        case 'n': 
     952            find_next_hunk(view); 
     953            return MSG_HANDLED; 
     954 
     955        case 'p': 
     956            find_prev_hunk(view); 
     957            return MSG_HANDLED; 
     958 
     959        case KEY_BACKSPACE: 
     960            view->last_found = -1; 
     961            return MSG_HANDLED; 
     962 
     963        case KEY_F(4): 
     964            view_edit(view, view->ord); 
     965            return MSG_HANDLED; 
     966 
     967        case KEY_F(14): 
     968            view_edit(view, view->ord ^ 1); 
     969            return MSG_HANDLED; 
     970 
     971        case KEY_F(17): 
     972            view_search(view, 1); 
     973            return MSG_HANDLED; 
     974 
     975        case KEY_HOME: 
     976        case KEY_M_CTRL | KEY_PPAGE: 
     977            view->last_found = -1; 
     978            if (view->move[0]) view->offs[0] = 0; 
     979            if (view->move[1]) view->offs[1] = 0; 
     980            return MSG_HANDLED; 
     981 
     982        case KEY_END: 
     983        case KEY_M_CTRL | KEY_NPAGE: 
     984            view->last_found = -1; 
     985            if (view->move[0]) view->offs[0] = view->max - 1; 
     986            if (view->move[1]) view->offs[1] = view->max - 1; 
     987            return MSG_HANDLED; 
     988 
     989        case KEY_UP: 
     990            if (view->move[0]) view->offs[0] -= view->nbytes; 
     991            if (view->move[1]) view->offs[1] -= view->nbytes; 
     992            return MSG_HANDLED; 
     993 
     994        case KEY_DOWN: 
     995            if (view->move[0]) view->offs[0] += view->nbytes; 
     996            if (view->move[1]) view->offs[1] += view->nbytes; 
     997            return MSG_HANDLED; 
     998 
     999        case KEY_NPAGE: 
     1000            if (view->move[0]) view->offs[0] += view->pbytes; 
     1001            if (view->move[1]) view->offs[1] += view->pbytes; 
     1002            return MSG_HANDLED; 
     1003 
     1004        case KEY_PPAGE: 
     1005            if (view->move[0]) view->offs[0] -= view->pbytes; 
     1006            if (view->move[1]) view->offs[1] -= view->pbytes; 
     1007            return MSG_HANDLED; 
     1008 
     1009        case KEY_LEFT: 
     1010            if (view->move[0]) view->offs[0]--; 
     1011            if (view->move[1]) view->offs[1]--; 
     1012            return MSG_HANDLED; 
     1013 
     1014        case KEY_RIGHT: 
     1015            if (view->move[0]) view->offs[0]++; 
     1016            if (view->move[1]) view->offs[1]++; 
     1017            return MSG_HANDLED; 
     1018 
     1019        case KEY_M_CTRL | KEY_LEFT: 
     1020            if (view->move[0]) view->offs[0] -= 16; 
     1021            if (view->move[1]) view->offs[1] -= 16; 
     1022            return MSG_HANDLED; 
     1023 
     1024        case KEY_M_CTRL | KEY_RIGHT: 
     1025            if (view->move[0]) view->offs[0] += 16; 
     1026            if (view->move[1]) view->offs[1] += 16; 
     1027            return MSG_HANDLED; 
     1028 
     1029        case XCTRL('o'): 
     1030            view_other_cmd(); 
     1031            return MSG_HANDLED; 
     1032 
     1033        case 't': 
     1034            diff_view(view->file[0], view->file[1], view->label[0], view->label[1]); 
     1035            return MSG_HANDLED; 
     1036 
     1037        case 'q': 
     1038        case XCTRL('g'): 
     1039        case ESC_CHAR: 
     1040            view->view_quit = 1; 
     1041            return MSG_HANDLED; 
     1042    } 
     1043 
     1044    /* Key not used */ 
     1045    return MSG_NOT_HANDLED; 
     1046} 
     1047 
     1048 
     1049static cb_ret_t 
     1050view_callback (Widget *w, widget_msg_t msg, int parm) 
     1051{ 
     1052    cb_ret_t i; 
     1053    WDiff *view = (WDiff *)w; 
     1054    Dlg_head *h = view->widget.parent; 
     1055 
     1056    switch (msg) { 
     1057        case WIDGET_INIT: 
     1058            view_labels(view); 
     1059            return MSG_HANDLED; 
     1060 
     1061        case WIDGET_DRAW: 
     1062            view->new_frame = 1; 
     1063            view_update(view); 
     1064            return MSG_HANDLED; 
     1065 
     1066        case WIDGET_CURSOR: 
     1067            return MSG_HANDLED; 
     1068 
     1069        case WIDGET_KEY: 
     1070            i = view_handle_key((WDiff *)view, parm); 
     1071            if (view->view_quit) 
     1072                dlg_stop(h); 
     1073            else { 
     1074                view_update(view); 
     1075            } 
     1076            return i; 
     1077 
     1078        case WIDGET_IDLE: 
     1079            return MSG_HANDLED; 
     1080 
     1081        case WIDGET_FOCUS: 
     1082            view_labels(view); 
     1083            return MSG_HANDLED; 
     1084 
     1085        case WIDGET_DESTROY: 
     1086            return MSG_HANDLED; 
     1087 
     1088        default: 
     1089            return default_proc(msg, parm); 
     1090    } 
     1091} 
     1092 
     1093 
     1094static void 
     1095view_adjust_size (Dlg_head *h) 
     1096{ 
     1097    WDiff *view; 
     1098    WButtonBar *bar; 
     1099 
     1100    /* Look up the viewer and the buttonbar, we assume only two widgets here */ 
     1101    view = (WDiff *)find_widget_type(h, view_callback); 
     1102    bar = find_buttonbar(h); 
     1103    widget_set_size(&view->widget, 0, 0, LINES, COLS); 
     1104    widget_set_size((Widget *)bar, LINES - 1, 0, 1, COLS); 
     1105 
     1106    view_compute_areas(view); 
     1107} 
     1108 
     1109 
     1110static cb_ret_t 
     1111view_dialog_callback (Dlg_head *h, dlg_msg_t msg, int parm) 
     1112{ 
     1113    switch (msg) { 
     1114        case DLG_RESIZE: 
     1115            view_adjust_size(h); 
     1116            return MSG_HANDLED; 
     1117 
     1118        default: 
     1119            return default_dlg_callback(h, msg, parm); 
     1120    } 
     1121} 
     1122 
     1123 
     1124int 
     1125xdiff_view (const char *file1, const char *file2, const char *label1, const char *label2) 
     1126{ 
     1127    int error; 
     1128    WDiff *view; 
     1129    WButtonBar *bar; 
     1130    Dlg_head *view_dlg; 
     1131 
     1132    /* Create dialog and widgets, put them on the dialog */ 
     1133    view_dlg = 
     1134        create_dlg(0, 0, LINES, COLS, NULL, view_dialog_callback, 
     1135                   "[Binary Diff Viewer]", NULL, DLG_WANT_TAB); 
     1136 
     1137    view = g_new0(WDiff, 1); 
     1138 
     1139    init_widget(&view->widget, 0, 0, LINES - 1, COLS, 
     1140                (callback_fn)view_callback, 
     1141                (mouse_h)view_event); 
     1142 
     1143    widget_want_cursor(view->widget, 0); 
     1144 
     1145    bar = buttonbar_new(1); 
     1146 
     1147    add_widget(view_dlg, bar); 
     1148    add_widget(view_dlg, view); 
     1149 
     1150    error = view_init(view, file1, file2, label1, label2); 
     1151 
     1152    /* Please note that if you add another widget, 
     1153     * you have to modify view_adjust_size to 
     1154     * be aware of it 
     1155     */ 
     1156    if (!error) { 
     1157        run_dlg(view_dlg); 
     1158        view_search(view, -1); 
     1159        view_fini(view); 
     1160    } 
     1161    destroy_dlg(view_dlg); 
     1162 
     1163    return error; 
     1164} 
     1165#endif