hyx

Minimalist but powerful terminal hex editor
git clone https://git.sinitax.com/yx7/hyx
Log | Files | Refs | sfeed.txt

history.c (1978B)


      1
      2#include "common.h"
      3#include "history.h"
      4#include "blob.h"
      5
      6#include <string.h>
      7
      8struct diff {
      9    enum op_type type;
     10    size_t pos;
     11    byte *data;
     12    size_t len;
     13    struct diff *next;
     14};
     15
     16static void diff_apply(struct blob *blob, struct diff *diff)
     17{
     18    switch (diff->type) {
     19    case REPLACE:
     20        blob_replace(blob, diff->pos, diff->data, diff->len, false);
     21        break;
     22    case INSERT:
     23        blob_insert(blob, diff->pos, diff->data, diff->len, false);
     24        break;
     25    case DELETE:
     26        blob_delete(blob, diff->pos, diff->len, false);
     27        break;
     28    default:
     29        die("unknown operation");
     30    }
     31}
     32
     33void history_init(struct diff **history)
     34{
     35    *history = NULL;
     36}
     37
     38void history_free(struct diff **history)
     39{
     40    struct diff *tmp, *cur = *history;
     41    while (cur) {
     42        tmp = cur;
     43        cur = cur->next;
     44        free(tmp->data);
     45        free(tmp);
     46    }
     47    *history = NULL;
     48}
     49
     50/* pushes a diff that _undoes_ the passed operation */
     51void history_save(struct diff **history, enum op_type type, struct blob *blob, size_t pos, size_t len)
     52{
     53    struct diff *diff = malloc_strict(sizeof(*diff));
     54    diff->type = type;
     55    diff->pos = pos;
     56    diff->len = len;
     57    diff->next = *history;
     58
     59    switch (type) {
     60    case DELETE:
     61        diff->type = INSERT;
     62        /* fall-through */
     63    case REPLACE:
     64        blob_read_strict(blob, pos, diff->data = malloc_strict(len), len);
     65        break;
     66    case INSERT:
     67        diff->type = DELETE;
     68        diff->data = NULL;
     69        break;
     70    default:
     71        die("unknown operation");
     72    }
     73
     74    *history = diff;
     75}
     76
     77bool history_step(struct diff **from, struct blob *blob, struct diff **to, size_t *pos)
     78{
     79    struct diff *diff = *from;
     80
     81    if (!diff)
     82        return false;
     83
     84    if (pos)
     85        *pos = diff->pos;
     86
     87    if (to)
     88        history_save(to, diff->type, blob, diff->pos, diff->len);
     89
     90    *from = diff->next;
     91    diff_apply(blob, diff);
     92    free(diff->data);
     93    free(diff);
     94
     95    return true;
     96}
     97