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
)
82 int lb_len
= lbuf_len(lb
);
86 while ((r
= strchr(s
, '\n'))) {
87 char *n
= malloc(r
- s
+ 2);
88 memcpy(n
, s
, r
- s
+ 1);
90 lbuf_insertline(lb
, pos
++, n
);
93 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
94 if (lb
->mark
[i
] >= pos
)
95 lb
->mark
[i
] += lbuf_len(lb
) - lb_len
;
96 end
= beg
+ lbuf_len(lb
) - lb_len
;
97 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
98 lbuf_mark(lb
, '[', beg
, 0);
99 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < end
- 1)
100 lbuf_mark(lb
, ']', end
- 1, 0);
104 /* low-level deletion */
105 static void lbuf_delete(struct lbuf
*lb
, int beg
, int end
)
108 for (i
= beg
; i
< end
; i
++)
110 memmove(lb
->ln
+ beg
, lb
->ln
+ end
, (lb
->ln_n
- end
) * sizeof(lb
->ln
[0]));
111 lb
->ln_n
-= end
- beg
;
112 for (i
= 0; i
< LEN(lb
->mark
); i
++) /* updating marks */
113 if (lb
->mark
[i
] > beg
)
114 lb
->mark
[i
] = MAX(beg
, lb
->mark
[i
] + beg
- end
);
115 if (lb
->mod_new
|| lb
->mark
['['] < 0 || lb
->mark
['['] > beg
)
116 lbuf_mark(lb
, '[', beg
, 0);
117 if (lb
->mod_new
|| lb
->mark
[']'] < 0 || lb
->mark
[']'] < beg
)
118 lbuf_mark(lb
, ']', beg
, 0);
122 /* append undo/redo history */
123 static void lbuf_opt(struct lbuf
*lb
, int ins
, int beg
, int end
)
125 struct lopt
*lo
= &lb
->hist
[0];
126 int n
= LEN(lb
->hist
);
129 for (i
= 0; i
< lb
->undo
; i
++)
130 lopt_done(&lb
->hist
[i
]);
131 memmove(lb
->hist
+ 1, lb
->hist
+ lb
->undo
,
132 (n
- lb
->undo
) * sizeof(lb
->hist
[0]));
133 memset(lb
->hist
+ n
- lb
->undo
+ 1, 0,
134 (lb
->undo
- 1) * sizeof(lb
->hist
[0]));
136 if (lb
->hist
[n
- 1].buf
)
137 lb
->useq_last
= lb
->hist
[n
- 1].seq
;
138 lopt_done(&lb
->hist
[n
- 1]);
139 memmove(lb
->hist
+ 1, lb
->hist
, (n
- 1) * sizeof(lb
->hist
[0]));
141 memset(lo
, 0, sizeof(*lo
));
145 lo
->buf
= lbuf_cp(lb
, beg
, end
);
150 void lbuf_rd(struct lbuf
*lbuf
, int fd
, int pos
)
156 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
157 sbuf_mem(sb
, buf
, nr
);
158 lbuf_put(lbuf
, pos
, sbuf_buf(sb
));
162 void lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
165 for (i
= beg
; i
< end
; i
++)
166 write(fd
, lbuf
->ln
[i
], strlen(lbuf
->ln
[i
]));
169 void lbuf_rm(struct lbuf
*lb
, int beg
, int end
)
175 lbuf_opt(lb
, 0, beg
, end
);
176 lbuf_delete(lb
, beg
, end
);
179 void lbuf_put(struct lbuf
*lb
, int pos
, char *s
)
181 int lb_len
= lbuf_len(lb
);
184 lbuf_insert(lb
, pos
, s
);
185 lbuf_opt(lb
, 1, pos
, pos
+ lbuf_len(lb
) - lb_len
);
188 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
193 for (i
= beg
; i
< end
; i
++)
195 sbuf_str(sb
, lb
->ln
[i
]);
196 return sbuf_done(sb
);
199 char *lbuf_get(struct lbuf
*lb
, int pos
)
201 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
204 int lbuf_len(struct lbuf
*lb
)
209 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
213 lbuf
->mark
[mark
] = pos
;
214 lbuf
->mark_off
[mark
] = off
;
217 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
219 if (mark
>= NMARKS
|| lbuf
->mark
[mark
] < 0)
221 *pos
= lbuf
->mark
[mark
];
223 *off
= lbuf
->mark_off
[mark
];
227 static struct lopt
*lbuf_lopt(struct lbuf
*lb
, int i
)
229 struct lopt
*lo
= &lb
->hist
[i
];
230 return i
>= 0 && i
< LEN(lb
->hist
) && lo
->buf
? lo
: NULL
;
233 static void lbuf_savemarks(struct lbuf
*lb
, struct lopt
*lo
)
236 lo
->mark
= malloc(sizeof(lb
->mark
));
237 lo
->mark_off
= malloc(sizeof(lb
->mark_off
));
238 for (i
= 0; i
< LEN(lb
->mark
); i
++)
240 lo
->mark
['*'] = lb
->mark
['*'];
241 lo
->mark_off
['*'] = lb
->mark_off
['*'];
244 static void lbuf_loadmarks(struct lbuf
*lb
, struct lopt
*lo
)
247 for (i
= 0; lo
->mark
&& i
< LEN(lb
->mark
); i
++) {
248 if (lo
->mark
[i
] >= 0) {
249 lb
->mark
[i
] = lo
->mark
[i
];
250 lb
->mark_off
[i
] = lo
->mark_off
[i
];
255 int lbuf_undo(struct lbuf
*lb
)
257 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
258 int useq
= lo
? lo
->seq
: 0;
262 while (lo
&& lo
->seq
== useq
) {
265 lbuf_delete(lb
, lo
->beg
, lo
->end
);
267 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
268 lbuf_loadmarks(lb
, lo
);
269 lo
= lbuf_lopt(lb
, lb
->undo
);
274 int lbuf_redo(struct lbuf
*lb
)
276 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
- 1);
277 int useq
= lo
? lo
->seq
: 0;
281 while (lo
&& lo
->seq
== useq
) {
284 lbuf_insert(lb
, lo
->beg
, lo
->buf
);
286 lbuf_delete(lb
, lo
->beg
, lo
->end
);
287 lbuf_loadmarks(lb
, lo
);
288 lo
= lbuf_lopt(lb
, lb
->undo
- 1);
293 static int lbuf_seq(struct lbuf
*lb
)
295 struct lopt
*lo
= lbuf_lopt(lb
, lb
->undo
);
296 return lo
? lo
->seq
: lb
->useq_last
;
299 /* mark buffer as saved and, if clear, clear the undo history */
300 void lbuf_saved(struct lbuf
*lb
, int clear
)
304 for (i
= 0; i
< LEN(lb
->hist
); i
++)
305 lopt_done(&lb
->hist
[i
]);
306 memset(lb
->hist
, 0, sizeof(lb
->hist
));
308 lb
->useq_last
= lb
->useq
;
310 lb
->useq_zero
= lbuf_seq(lb
);
313 /* was the file modified since the last lbuf_modreset() */
314 int lbuf_modified(struct lbuf
*lb
)
316 struct lopt
*lo
= lbuf_lopt(lb
, 0);
317 if (!lb
->undo
&& lo
&& !lo
->mark
)
318 lbuf_savemarks(lb
, lo
);
321 return lbuf_seq(lb
) != lb
->useq_zero
;