11 char *buf
; /* text inserted or deleted */
12 int ins
; /* insertion operation if non-zero */
14 int seq
; /* operation number */
19 int mark
[NMARKS
]; /* mark lines */
20 int mark_off
[NMARKS
]; /* mark line offsets */
21 struct lopt hist
[128]; /* buffer history */
22 int undo
; /* current index into hist[] */
23 int useq
; /* current operation sequence */
24 char **ln
; /* lines */
25 int ln_n
; /* number of lbuf in l[] */
26 int ln_sz
; /* size of l[] */
27 int mod_new
; /* clear modification marks */
28 int useq_zero
; /* useq for lbuf_saved() */
29 int useq_last
; /* useq before hist[] */
32 struct lbuf
*lbuf_make(void)
34 struct lbuf
*lb
= malloc(sizeof(*lb
));
36 memset(lb
, 0, sizeof(*lb
));
37 for (i
= 0; i
< LEN(lb
->mark
); i
++)
42 void lbuf_free(struct lbuf
*lb
)
45 for (i
= 0; i
< lb
->ln_n
; i
++)
47 for (i
= 0; i
< LEN(lb
->hist
); i
++)
48 free(lb
->hist
[i
].buf
);
53 /* insert a line at pos */
54 static void lbuf_insertline(struct lbuf
*lb
, int pos
, char *s
)
56 if (lb
->ln_n
== lb
->ln_sz
) {
57 int nsz
= lb
->ln_sz
+ 512;
58 char **nln
= malloc(nsz
* sizeof(nln
[0]));
59 memcpy(nln
, lb
->ln
, lb
->ln_n
* sizeof(lb
->ln
[0]));
64 memmove(lb
->ln
+ pos
+ 1, lb
->ln
+ pos
,
65 (lb
->ln_n
- pos
) * sizeof(lb
->ln
[0]));
70 /* low-level insertion */
71 static void lbuf_insert(struct lbuf
*lb
, int pos
, char *s
)
75 int lb_len
= lbuf_len(lb
);
79 for (i
= 0; i
< len
; i
++) {
80 sbuf_chr(sb
, (unsigned char) s
[i
]);
82 lbuf_insertline(lb
, pos
++, sbuf_done(sb
));
87 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
88 if (lb
->mark
[i
] >= pos
)
89 lb
->mark
[i
] += lbuf_len(lb
) - lb_len
;
90 end
= beg
+ lbuf_len(lb
) - lb_len
;
91 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
92 lbuf_mark(lb
, '[', beg
, 0);
93 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < end
- 1)
94 lbuf_mark(lb
, ']', end
- 1, 0);
98 /* low-level deletion */
99 static void lbuf_delete(struct lbuf
*lb
, int beg
, int end
)
102 for (i
= beg
; i
< end
; i
++)
104 memmove(lb
->ln
+ beg
, lb
->ln
+ end
, (lb
->ln_n
- end
) * sizeof(lb
->ln
[0]));
105 lb
->ln_n
-= end
- beg
;
106 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
107 if (lb
->mark
[i
] > beg
)
108 lb
->mark
[i
] = MAX(beg
, lb
->mark
[i
] + beg
- end
);
109 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
110 lbuf_mark(lb
, '[', beg
, 0);
111 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < beg
)
112 lbuf_mark(lb
, ']', beg
, 0);
116 /* append undo/redo history */
117 static void lbuf_opt(struct lbuf
*lb
, int ins
, int beg
, int end
)
119 struct lopt
*lo
= &lb
->hist
[0];
120 int n
= LEN(lb
->hist
);
123 for (i
= 0; i
< lb
->undo
; i
++)
124 free(lb
->hist
[i
].buf
);
125 memmove(lb
->hist
+ 1, lb
->hist
+ lb
->undo
,
126 (n
- lb
->undo
) * sizeof(lb
->hist
[0]));
127 for (i
= n
- lb
->undo
+ 1; i
< n
; i
++)
128 lb
->hist
[i
].buf
= NULL
;
130 if (lb
->hist
[n
- 1].buf
)
131 lb
->useq_last
= lb
->hist
[n
- 1].seq
;
132 free(lb
->hist
[n
- 1].buf
);
133 memmove(lb
->hist
+ 1, lb
->hist
, (n
- 1) * sizeof(lb
->hist
[0]));
138 lo
->buf
= lbuf_cp(lb
, beg
, end
);
143 void lbuf_rd(struct lbuf
*lbuf
, int fd
, int pos
)
149 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
150 sbuf_mem(sb
, buf
, nr
);
151 lbuf_put(lbuf
, pos
, sbuf_buf(sb
));
155 void lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
158 for (i
= beg
; i
< end
; i
++)
159 write(fd
, lbuf
->ln
[i
], strlen(lbuf
->ln
[i
]));
162 void lbuf_rm(struct lbuf
*lb
, int beg
, int end
)
166 lbuf_opt(lb
, 0, beg
, end
);
167 lbuf_delete(lb
, beg
, end
);
170 void lbuf_put(struct lbuf
*lb
, int pos
, char *s
)
172 int lb_len
= lbuf_len(lb
);
173 lbuf_insert(lb
, pos
, s
);
174 lbuf_opt(lb
, 1, pos
, pos
+ lbuf_len(lb
) - lb_len
);
177 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
182 for (i
= beg
; i
< end
; i
++)
184 sbuf_str(sb
, lb
->ln
[i
]);
185 return sbuf_done(sb
);
188 char *lbuf_get(struct lbuf
*lb
, int pos
)
190 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
193 int lbuf_len(struct lbuf
*lb
)
198 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
202 lbuf
->mark
[mark
] = pos
;
203 lbuf
->mark_off
[mark
] = off
;
206 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
208 if (mark
>= NMARKS
|| lbuf
->mark
[mark
] < 0)
210 *pos
= lbuf
->mark
[mark
];
212 *off
= lbuf
->mark_off
[mark
];
216 static struct lopt
*lbuf_lopt(struct lbuf
*lb
, int i
)
218 struct lopt
*lo
= &lb
->hist
[i
];
219 return i
>= 0 && i
< LEN(lb
->hist
) && lo
->buf
? lo
: NULL
;
222 int lbuf_undo(struct lbuf
*lb
)
224 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
225 int useq
= lo
? lo
->seq
: 0;
229 while (lo
&& lo
->seq
== useq
) {
232 lbuf_delete(lb
, lo
->beg
, lo
->end
);
234 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
235 lo
= lbuf_lopt(lb
, lb
->undo
);
240 int lbuf_redo(struct lbuf
*lb
)
242 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
- 1);
243 int useq
= lo
? lo
->seq
: 0;
247 while (lo
&& lo
->seq
== useq
) {
250 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
252 lbuf_delete(lb
, lo
->beg
, lo
->end
);
253 lo
= lbuf_lopt(lb
, lb
->undo
- 1);
258 static int lbuf_seq(struct lbuf
*lb
)
260 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
261 return lo
? lo
->seq
: lb
->useq_last
;
264 /* mark buffer as saved and, if clear, clear the undo history */
265 void lbuf_saved(struct lbuf
*lb
, int clear
)
269 for (i
= 0; i
< LEN(lb
->hist
); i
++)
270 free(lb
->hist
[i
].buf
);
271 memset(lb
->hist
, 0, sizeof(lb
->hist
));
273 lb
->useq_last
= lb
->useq
;
275 lb
->useq_zero
= lbuf_seq(lb
);
278 /* was the file modified since the last lbuf_modreset() */
279 int lbuf_modified(struct lbuf
*lb
)
283 return lbuf_seq(lb
) != lb
->useq_zero
;