11 char *buf
; /* text inserted or deleted */
12 int ins
; /* insertion operation if non-zero */
14 int seq
; /* operation number */
15 int *mark
, *mark_off
; /* saved marks */
20 int mark
[NMARKS
]; /* mark lines */
21 int mark_off
[NMARKS
]; /* mark line offsets */
22 struct lopt hist
[128]; /* buffer history */
23 int undo
; /* current index into hist[] */
24 int useq
; /* current operation sequence */
25 char **ln
; /* lines */
26 int ln_n
; /* number of lbuf in l[] */
27 int ln_sz
; /* size of l[] */
28 int mod_new
; /* clear modification marks */
29 int useq_zero
; /* useq for lbuf_saved() */
30 int useq_last
; /* useq before hist[] */
33 struct lbuf
*lbuf_make(void)
35 struct lbuf
*lb
= malloc(sizeof(*lb
));
37 memset(lb
, 0, sizeof(*lb
));
38 for (i
= 0; i
< LEN(lb
->mark
); i
++)
44 static void lopt_done(struct lopt
*lo
)
51 void lbuf_free(struct lbuf
*lb
)
54 for (i
= 0; i
< lb
->ln_n
; i
++)
56 for (i
= 0; i
< LEN(lb
->hist
); i
++)
57 lopt_done(&lb
->hist
[i
]);
62 /* insert a line at pos */
63 static void lbuf_insertline(struct lbuf
*lb
, int pos
, char *s
)
65 if (lb
->ln_n
== lb
->ln_sz
) {
66 int nsz
= lb
->ln_sz
+ 512;
67 char **nln
= malloc(nsz
* sizeof(nln
[0]));
68 memcpy(nln
, lb
->ln
, lb
->ln_n
* sizeof(lb
->ln
[0]));
73 memmove(lb
->ln
+ pos
+ 1, lb
->ln
+ pos
,
74 (lb
->ln_n
- pos
) * sizeof(lb
->ln
[0]));
79 /* low-level insertion */
80 static void lbuf_insert(struct lbuf
*lb
, int pos
, char *s
)
84 int lb_len
= lbuf_len(lb
);
88 for (i
= 0; i
< len
; i
++) {
89 sbuf_chr(sb
, (unsigned char) s
[i
]);
91 lbuf_insertline(lb
, pos
++, sbuf_done(sb
));
96 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
97 if (lb
->mark
[i
] >= pos
)
98 lb
->mark
[i
] += lbuf_len(lb
) - lb_len
;
99 end
= beg
+ lbuf_len(lb
) - lb_len
;
100 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
101 lbuf_mark(lb
, '[', beg
, 0);
102 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < end
- 1)
103 lbuf_mark(lb
, ']', end
- 1, 0);
107 /* low-level deletion */
108 static void lbuf_delete(struct lbuf
*lb
, int beg
, int end
)
111 for (i
= beg
; i
< end
; i
++)
113 memmove(lb
->ln
+ beg
, lb
->ln
+ end
, (lb
->ln_n
- end
) * sizeof(lb
->ln
[0]));
114 lb
->ln_n
-= end
- beg
;
115 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
116 if (lb
->mark
[i
] > beg
)
117 lb
->mark
[i
] = MAX(beg
, lb
->mark
[i
] + beg
- end
);
118 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
119 lbuf_mark(lb
, '[', beg
, 0);
120 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < beg
)
121 lbuf_mark(lb
, ']', beg
, 0);
125 /* append undo/redo history */
126 static void lbuf_opt(struct lbuf
*lb
, int ins
, int beg
, int end
)
128 struct lopt
*lo
= &lb
->hist
[0];
129 int n
= LEN(lb
->hist
);
132 for (i
= 0; i
< lb
->undo
; i
++)
133 lopt_done(&lb
->hist
[i
]);
134 memmove(lb
->hist
+ 1, lb
->hist
+ lb
->undo
,
135 (n
- lb
->undo
) * sizeof(lb
->hist
[0]));
136 memset(lb
->hist
+ n
- lb
->undo
+ 1, 0,
137 (lb
->undo
- 1) * sizeof(lb
->hist
[0]));
139 if (lb
->hist
[n
- 1].buf
)
140 lb
->useq_last
= lb
->hist
[n
- 1].seq
;
141 lopt_done(&lb
->hist
[n
- 1]);
142 memmove(lb
->hist
+ 1, lb
->hist
, (n
- 1) * sizeof(lb
->hist
[0]));
144 memset(lo
, 0, sizeof(*lo
));
148 lo
->buf
= lbuf_cp(lb
, beg
, end
);
153 void lbuf_rd(struct lbuf
*lbuf
, int fd
, int pos
)
159 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
160 sbuf_mem(sb
, buf
, nr
);
161 lbuf_put(lbuf
, pos
, sbuf_buf(sb
));
165 void lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
168 for (i
= beg
; i
< end
; i
++)
169 write(fd
, lbuf
->ln
[i
], strlen(lbuf
->ln
[i
]));
172 void lbuf_rm(struct lbuf
*lb
, int beg
, int end
)
178 lbuf_opt(lb
, 0, beg
, end
);
179 lbuf_delete(lb
, beg
, end
);
182 void lbuf_put(struct lbuf
*lb
, int pos
, char *s
)
184 int lb_len
= lbuf_len(lb
);
187 lbuf_insert(lb
, pos
, s
);
188 lbuf_opt(lb
, 1, pos
, pos
+ lbuf_len(lb
) - lb_len
);
191 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
196 for (i
= beg
; i
< end
; i
++)
198 sbuf_str(sb
, lb
->ln
[i
]);
199 return sbuf_done(sb
);
202 char *lbuf_get(struct lbuf
*lb
, int pos
)
204 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
207 int lbuf_len(struct lbuf
*lb
)
212 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
216 lbuf
->mark
[mark
] = pos
;
217 lbuf
->mark_off
[mark
] = off
;
220 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
222 if (mark
>= NMARKS
|| lbuf
->mark
[mark
] < 0)
224 *pos
= lbuf
->mark
[mark
];
226 *off
= lbuf
->mark_off
[mark
];
230 static struct lopt
*lbuf_lopt(struct lbuf
*lb
, int i
)
232 struct lopt
*lo
= &lb
->hist
[i
];
233 return i
>= 0 && i
< LEN(lb
->hist
) && lo
->buf
? lo
: NULL
;
236 static void lbuf_savemarks(struct lbuf
*lb
, struct lopt
*lo
)
239 lo
->mark
= malloc(sizeof(lb
->mark
));
240 lo
->mark_off
= malloc(sizeof(lb
->mark_off
));
241 for (i
= 0; i
< LEN(lb
->mark
); i
++)
243 lo
->mark
['*'] = lb
->mark
['*'];
244 lo
->mark_off
['*'] = lb
->mark_off
['*'];
247 static void lbuf_loadmarks(struct lbuf
*lb
, struct lopt
*lo
)
250 for (i
= 0; lo
->mark
&& i
< LEN(lb
->mark
); i
++) {
251 if (lo
->mark
[i
] >= 0) {
252 lb
->mark
[i
] = lo
->mark
[i
];
253 lb
->mark_off
[i
] = lo
->mark_off
[i
];
258 int lbuf_undo(struct lbuf
*lb
)
260 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
261 int useq
= lo
? lo
->seq
: 0;
265 while (lo
&& lo
->seq
== useq
) {
268 lbuf_delete(lb
, lo
->beg
, lo
->end
);
270 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
271 lbuf_loadmarks(lb
, lo
);
272 lo
= lbuf_lopt(lb
, lb
->undo
);
277 int lbuf_redo(struct lbuf
*lb
)
279 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
- 1);
280 int useq
= lo
? lo
->seq
: 0;
284 while (lo
&& lo
->seq
== useq
) {
287 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
289 lbuf_delete(lb
, lo
->beg
, lo
->end
);
290 lbuf_loadmarks(lb
, lo
);
291 lo
= lbuf_lopt(lb
, lb
->undo
- 1);
296 static int lbuf_seq(struct lbuf
*lb
)
298 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
299 return lo
? lo
->seq
: lb
->useq_last
;
302 /* mark buffer as saved and, if clear, clear the undo history */
303 void lbuf_saved(struct lbuf
*lb
, int clear
)
307 for (i
= 0; i
< LEN(lb
->hist
); i
++)
308 lopt_done(&lb
->hist
[i
]);
309 memset(lb
->hist
, 0, sizeof(lb
->hist
));
311 lb
->useq_last
= lb
->useq
;
313 lb
->useq_zero
= lbuf_seq(lb
);
316 /* was the file modified since the last lbuf_modreset() */
317 int lbuf_modified(struct lbuf
*lb
)
319 struct lopt
*lo
= lbuf_lopt(lb
, 0);
320 if (!lb
->undo
&& lo
&& !lo
->mark
)
321 lbuf_savemarks(lb
, lo
);
324 return lbuf_seq(lb
) != lb
->useq_zero
;