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