8 #define NMARKS_BASE ('z' - 'a' + 2)
13 char *ins
; /* inserted text */
14 char *del
; /* deleted text */
15 int pos
, n_ins
, n_del
; /* modification location */
16 int pos_off
; /* cursor line offset */
17 int seq
; /* operation number */
18 int *mark
, *mark_off
; /* saved marks */
23 int mark
[NMARKS
]; /* mark lines */
24 int mark_off
[NMARKS
]; /* mark line offsets */
25 char **ln
; /* buffer lines */
26 int ln_n
; /* number of lines in ln[] */
27 int ln_sz
; /* size of ln[] */
28 int useq
; /* current operation sequence */
29 struct lopt
*hist
; /* buffer history */
30 int hist_sz
; /* size of hist[] */
31 int hist_n
; /* current history head in hist[] */
32 int hist_u
; /* current undo head in hist[] */
33 int useq_zero
; /* useq for lbuf_saved() */
34 int useq_last
; /* useq before hist[] */
37 struct lbuf
*lbuf_make(void)
39 struct lbuf
*lb
= malloc(sizeof(*lb
));
41 memset(lb
, 0, sizeof(*lb
));
42 for (i
= 0; i
< LEN(lb
->mark
); i
++)
48 static void lopt_done(struct lopt
*lo
)
56 static void lbuf_savemark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
58 if (lb
->mark
[m
] >= 0) {
60 lo
->mark
= malloc(sizeof(lb
->mark
));
61 lo
->mark_off
= malloc(sizeof(lb
->mark_off
));
62 memset(lo
->mark
, 0xff, sizeof(lb
->mark
));
64 lo
->mark
[m
] = lb
->mark
[m
];
65 lo
->mark_off
[m
] = lb
->mark_off
[m
];
69 static void lbuf_loadmark(struct lbuf
*lb
, struct lopt
*lo
, int m
)
71 if (lo
->mark
&& lo
->mark
[m
] >= 0) {
72 lb
->mark
[m
] = lo
->mark
[m
];
73 lb
->mark_off
[m
] = lo
->mark_off
[m
];
77 static int markidx(int mark
)
81 if (mark
== '\'' || mark
== '`')
92 static void lbuf_savepos(struct lbuf
*lb
, struct lopt
*lo
)
94 if (lb
->mark
[markidx('*')] >= 0)
95 lo
->pos_off
= lb
->mark_off
[markidx('*')];
98 static void lbuf_loadpos(struct lbuf
*lb
, struct lopt
*lo
)
100 lb
->mark
[markidx('*')] = lo
->pos
;
101 lb
->mark_off
[markidx('*')] = lo
->pos_off
;
104 void lbuf_free(struct lbuf
*lb
)
107 for (i
= 0; i
< lb
->ln_n
; i
++)
109 for (i
= 0; i
< lb
->hist_n
; i
++)
110 lopt_done(&lb
->hist
[i
]);
116 /* insert a line at pos */
117 static void lbuf_insertline(struct lbuf
*lb
, int pos
, char *s
)
119 if (lb
->ln_n
== lb
->ln_sz
) {
120 int nsz
= lb
->ln_sz
+ 512;
121 char **nln
= malloc(nsz
* sizeof(nln
[0]));
122 memcpy(nln
, lb
->ln
, lb
->ln_n
* sizeof(lb
->ln
[0]));
127 memmove(lb
->ln
+ pos
+ 1, lb
->ln
+ pos
,
128 (lb
->ln_n
- pos
) * sizeof(lb
->ln
[0]));
133 /* low-level replacement */
134 static void lbuf_replace(struct lbuf
*lb
, char *s
, int pos
, int n_del
)
139 for (i
= 0; i
< n_del
; i
++)
140 free(lb
->ln
[pos
+ i
]);
141 memmove(lb
->ln
+ pos
, lb
->ln
+ pos
+ n_del
,
142 (lb
->ln_n
- pos
- n_del
) * sizeof(lb
->ln
[0]));
144 while (s
&& (r
= strchr(s
, '\n'))) {
145 char *n
= malloc(r
- s
+ 2);
146 memcpy(n
, s
, r
- s
+ 1);
148 lbuf_insertline(lb
, pos
+ n_ins
++, n
);
151 for (i
= 0; i
< LEN(lb
->mark
); i
++) { /* updating marks */
152 if (!s
&& lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
154 else if (lb
->mark
[i
] >= pos
+ n_del
)
155 lb
->mark
[i
] += n_ins
- n_del
;
156 else if (lb
->mark
[i
] >= pos
+ n_ins
)
157 lb
->mark
[i
] = pos
+ n_ins
- 1;
159 lbuf_mark(lb
, '[', pos
, 0);
160 lbuf_mark(lb
, ']', pos
+ (n_ins
? n_ins
- 1 : 0), 0);
163 static int uc_newlines(char *s
)
166 for (n
= 0; (s
= strchr(s
, '\n')); n
++)
171 /* append undo/redo history */
172 static void lbuf_opt(struct lbuf
*lb
, char *buf
, int pos
, int n_del
)
176 for (i
= lb
->hist_u
; i
< lb
->hist_n
; i
++)
177 lopt_done(&lb
->hist
[i
]);
178 lb
->hist_n
= lb
->hist_u
;
179 if (lb
->hist_n
== lb
->hist_sz
) {
180 int sz
= lb
->hist_sz
+ 128;
181 struct lopt
*hist
= malloc(sz
* sizeof(hist
[0]));
182 memcpy(hist
, lb
->hist
, lb
->hist_n
* sizeof(hist
[0]));
187 lo
= &lb
->hist
[lb
->hist_n
];
189 lb
->hist_u
= lb
->hist_n
;
190 memset(lo
, 0, sizeof(*lo
));
193 lo
->del
= n_del
? lbuf_cp(lb
, pos
, pos
+ n_del
) : NULL
;
194 lo
->n_ins
= buf
? uc_newlines(buf
) : 0;
195 lo
->ins
= buf
? uc_dup(buf
) : NULL
;
197 lbuf_savepos(lb
, lo
);
198 for (i
= 0; i
< NMARKS_BASE
; i
++)
199 if (lb
->mark
[i
] >= pos
&& lb
->mark
[i
] < pos
+ n_del
)
200 lbuf_savemark(lb
, lo
, i
);
203 int lbuf_rd(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
209 while ((nr
= read(fd
, buf
, sizeof(buf
))) > 0)
210 sbuf_mem(sb
, buf
, nr
);
212 lbuf_edit(lbuf
, sbuf_buf(sb
), beg
, end
);
217 int lbuf_wr(struct lbuf
*lbuf
, int fd
, int beg
, int end
)
220 for (i
= beg
; i
< end
; i
++) {
221 char *ln
= lbuf
->ln
[i
];
223 long nl
= strlen(ln
);
225 long nc
= write(fd
, ln
+ nw
, nl
- nw
);
234 /* replace lines beg through end with buf */
235 void lbuf_edit(struct lbuf
*lb
, char *buf
, int beg
, int end
)
241 if (beg
== end
&& !buf
)
243 lbuf_opt(lb
, buf
, beg
, end
- beg
);
244 lbuf_replace(lb
, buf
, beg
, end
- beg
);
247 char *lbuf_cp(struct lbuf
*lb
, int beg
, int end
)
252 for (i
= beg
; i
< end
; i
++)
254 sbuf_str(sb
, lb
->ln
[i
]);
255 return sbuf_done(sb
);
258 char *lbuf_get(struct lbuf
*lb
, int pos
)
260 return pos
>= 0 && pos
< lb
->ln_n
? lb
->ln
[pos
] : NULL
;
263 int lbuf_len(struct lbuf
*lb
)
268 void lbuf_mark(struct lbuf
*lbuf
, int mark
, int pos
, int off
)
270 if (markidx(mark
) >= 0) {
271 lbuf
->mark
[markidx(mark
)] = pos
;
272 lbuf
->mark_off
[markidx(mark
)] = off
;
276 int lbuf_jump(struct lbuf
*lbuf
, int mark
, int *pos
, int *off
)
278 int mk
= markidx(mark
);
279 if (mk
< 0 || lbuf
->mark
[mk
] < 0)
281 *pos
= lbuf
->mark
[mk
];
283 *off
= lbuf
->mark_off
[mk
];
287 int lbuf_undo(struct lbuf
*lb
)
292 useq
= lb
->hist
[lb
->hist_u
- 1].seq
;
293 while (lb
->hist_u
&& lb
->hist
[lb
->hist_u
- 1].seq
== useq
) {
294 struct lopt
*lo
= &lb
->hist
[--(lb
->hist_u
)];
295 lbuf_replace(lb
, lo
->del
, lo
->pos
, lo
->n_ins
);
296 lbuf_loadpos(lb
, lo
);
297 for (i
= 0; i
< LEN(lb
->mark
); i
++)
298 lbuf_loadmark(lb
, lo
, i
);
303 int lbuf_redo(struct lbuf
*lb
)
306 if (lb
->hist_u
== lb
->hist_n
)
308 useq
= lb
->hist
[lb
->hist_u
].seq
;
309 while (lb
->hist_u
< lb
->hist_n
&& lb
->hist
[lb
->hist_u
].seq
== useq
) {
310 struct lopt
*lo
= &lb
->hist
[lb
->hist_u
++];
311 lbuf_replace(lb
, lo
->ins
, lo
->pos
, lo
->n_del
);
312 lbuf_loadpos(lb
, lo
);
317 static int lbuf_seq(struct lbuf
*lb
)
319 return lb
->hist_u
? lb
->hist
[lb
->hist_u
- 1].seq
: lb
->useq_last
;
322 /* mark buffer as saved and, if clear, clear the undo history */
323 void lbuf_saved(struct lbuf
*lb
, int clear
)
327 for (i
= 0; i
< lb
->hist_n
; i
++)
328 lopt_done(&lb
->hist
[i
]);
331 lb
->useq_last
= lb
->useq
;
333 lb
->useq_zero
= lbuf_seq(lb
);
337 /* was the file modified since the last lbuf_modreset() */
338 int lbuf_modified(struct lbuf
*lb
)
341 return lbuf_seq(lb
) != lb
->useq_zero
;