#include <stdio.h> #include <stdlib.h> #include <string.h> #include "gramscii.h" static int LONG_STEP; /* line_t and lineset_t management */ void ensure_line_length(line_t *l, int len){ char *tmp; if (l->sz < len + 1){ tmp = realloc(l->s, (len+1) * 2 * sizeof(char)); if (!tmp){ fprintf(stderr, "Unable to allocate string\n"); exit(1); } l->s = tmp; l->sz = (len + 1) * 2; } } void alloc_line(line_t *l){ char *tmp; l->sz = WIDTH+1; tmp = malloc((l->sz) * sizeof(char)); if (tmp == NULL){ fprintf(stderr, "unable to allocate line\n"); exit(1); } l->s = tmp; memset(l->s, BG, l->sz); l->lst = -1; l->s[0]='\0'; } void ensure_num_lines(lineset_t *ls, int n){ line_t *tmp; if (n > ls->sz){ if (ls->sz == 0) ls->l=NULL; tmp = realloc(ls->l, (n + LONG_STEP) * sizeof(line_t)); if (tmp == NULL){ fprintf(stderr, "Unable to allocate memory for more lines"); exit(1); } else { ls->l = tmp; while ( ls->sz < n + LONG_STEP){ alloc_line(&(ls->l[ls->sz])); ls->sz ++; } } } } void dump_lines(lineset_t ls, FILE *f){ int i; for (i=0; i<ls.num ;i++){ fprintf(f, "%d:%s\n", i, ls.l[i].s); } fflush(f); } void pad_line_to_length(char *s, int W){ int i; for (i=strlen(s); i<W; i++){ s[i] = BG; } } /* cut/yank/paste/undo management */ void yank_region(int x1, int y1, int x2, int y2){ int N, W, i; N = y2 - y1 + 1; W = x2 - x1 + 1; ensure_num_lines(&cutbuf, N); for (i=y1; i<=y2; i++){ ensure_line_length(&(cutbuf.l[i-y1]), W); memcpy(cutbuf.l[i-y1].s, screen.l[i].s + x1, x2-x1+1); if (strlen(cutbuf.l[i-y1].s) < W) pad_line_to_length(cutbuf.l[i-y1].s, W); cutbuf.l[i-y1].s[W] = '\0'; cutbuf.l[i-y1].n = i; } cutbuf.num = N; #ifdef DEBUG dump_lines(cutbuf, stderr); #endif } void paste_region(int x1, int y1){ int i, curlen, pastelen; i = y1; while( i < HEIGHT && i < y1 + cutbuf.num){ pastelen = strlen(cutbuf.l[i-y1].s); curlen = strlen(screen.l[i].s); memcpy(screen.l[i].s + x1, cutbuf.l[i-y1].s, pastelen); if (curlen <= x1) /* double-check this line below */ pad_line_to_length(screen.l[i].s + curlen, x1 - curlen); if (curlen <= x1 + pastelen) screen.l[i].s[x1 + pastelen] = '\0'; screen.l[i].lst = strlen(screen.l[i].s) - 1; #ifdef DEBUG fprintf(stderr, "%d.lst: %d\n", i, screen.l[i].lst); #endif i += 1; modified = 1; } redraw(); } void copy_lines_to_ring(int y1, int y2, int which){ int i, len, idx; lineset_t *tmp; if (y1 > y2){ y1 ^= y2; y2 ^= y1; y1 ^= y2; } if (undo_cur > undo_lst) undo_cur = undo_lst; if (which == PRV_STATE){ /* adding a new previous state */ undo_cur += 2; idx = undo_cur; } else idx = undo_cur + 1; if (idx >= undo_sz - 1){ undo_sz += 10; tmp = realloc(undo, undo_sz * sizeof(lineset_t)); if (tmp == NULL){ fprintf(stderr, "Error allocating undo buffer"); exit(1); } undo = tmp; } ensure_num_lines(&(undo[idx]), y2 - y1 + 1); for(i=y1; i<=y2; i++){ len = strlen(screen.l[i].s); ensure_line_length(&(undo[idx].l[i-y1]), len); strcpy(undo[idx].l[i-y1].s, screen.l[i].s); undo[idx].l[i-y1].n = i; undo[idx].l[i-y1].lst = screen.l[i].lst; } undo[idx].num = y2 - y1 + 1; if (which == PRV_STATE) undo_lst = undo_cur; #ifdef DEBUG fprintf(stderr, "undo_ring: y1: %d y2: %d idx: %d\n", y1, y2, idx); for(i=0; i<undo[idx].num; i++){ fprintf(stderr, "UU: %d| %s\n", undo[idx].l[i].n, undo[idx].l[i].s); } #endif } void invalidate_undo(){ if (undo_lst > undo_cur) undo_lst = undo_cur; }