xref: /aosp_15_r20/external/toybox/toys/pending/vi.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* vi.c - You can't spell "evil" without "vi".
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2015 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2019 Jarno Mäkipää <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker  *
6*cf5a6c84SAndroid Build Coastguard Worker  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html
7*cf5a6c84SAndroid Build Coastguard Worker 
8*cf5a6c84SAndroid Build Coastguard Worker USE_VI(NEWTOY(vi, ">1s:c:", TOYFLAG_USR|TOYFLAG_BIN))
9*cf5a6c84SAndroid Build Coastguard Worker 
10*cf5a6c84SAndroid Build Coastguard Worker config VI
11*cf5a6c84SAndroid Build Coastguard Worker   bool "vi"
12*cf5a6c84SAndroid Build Coastguard Worker   default n
13*cf5a6c84SAndroid Build Coastguard Worker   help
14*cf5a6c84SAndroid Build Coastguard Worker     usage: vi [-s SCRIPT] FILE
15*cf5a6c84SAndroid Build Coastguard Worker 
16*cf5a6c84SAndroid Build Coastguard Worker     Visual text editor. Predates keyboards with standardized cursor keys.
17*cf5a6c84SAndroid Build Coastguard Worker     If you don't know how to use it, hit the ESC key, type :q! and press ENTER.
18*cf5a6c84SAndroid Build Coastguard Worker 
19*cf5a6c84SAndroid Build Coastguard Worker     -s	run SCRIPT as if typed at keyboard (like -c "source SCRIPT")
20*cf5a6c84SAndroid Build Coastguard Worker     -c	run SCRIPT of ex commands
21*cf5a6c84SAndroid Build Coastguard Worker 
22*cf5a6c84SAndroid Build Coastguard Worker     The editor is usually in one of three modes:
23*cf5a6c84SAndroid Build Coastguard Worker 
24*cf5a6c84SAndroid Build Coastguard Worker       Hit ESC for "vi mode" where each key is a command.
25*cf5a6c84SAndroid Build Coastguard Worker       Hit : for "ex mode" which runs command lines typed at bottom of screen.
26*cf5a6c84SAndroid Build Coastguard Worker       Hit i (from vi mode) for "insert mode" where typing adds to the file.
27*cf5a6c84SAndroid Build Coastguard Worker 
28*cf5a6c84SAndroid Build Coastguard Worker     ex mode commands (ESC to exit ex mode):
29*cf5a6c84SAndroid Build Coastguard Worker 
30*cf5a6c84SAndroid Build Coastguard Worker       q   Quit (exit editor if no unsaved changes)
31*cf5a6c84SAndroid Build Coastguard Worker       q!  Quit discarding unsaved changes
32*cf5a6c84SAndroid Build Coastguard Worker       w   Write changed contents to file (optionally to NAME argument)
33*cf5a6c84SAndroid Build Coastguard Worker       wq  Write to file, then quit
34*cf5a6c84SAndroid Build Coastguard Worker 
35*cf5a6c84SAndroid Build Coastguard Worker     vi mode single key commands:
36*cf5a6c84SAndroid Build Coastguard Worker       i  switch to insert mode (until next ESC)
37*cf5a6c84SAndroid Build Coastguard Worker       u  undo last change (can be repeated)
38*cf5a6c84SAndroid Build Coastguard Worker       a  append (move one character right, switch to insert mode)
39*cf5a6c84SAndroid Build Coastguard Worker       A  append (jump to end of line, switch to insert mode)
40*cf5a6c84SAndroid Build Coastguard Worker 
41*cf5a6c84SAndroid Build Coastguard Worker     vi mode commands that prompt for more data on bottom line:
42*cf5a6c84SAndroid Build Coastguard Worker       :  switch to ex mode
43*cf5a6c84SAndroid Build Coastguard Worker       /  search forwards for regex
44*cf5a6c84SAndroid Build Coastguard Worker       ?  search backwards for regex
45*cf5a6c84SAndroid Build Coastguard Worker       .  repeat last command
46*cf5a6c84SAndroid Build Coastguard Worker 
47*cf5a6c84SAndroid Build Coastguard Worker       [count][cmd][motion]
48*cf5a6c84SAndroid Build Coastguard Worker       cmd: c d y
49*cf5a6c84SAndroid Build Coastguard Worker       motion: 0 b e G H h j k L l M w $ f F
50*cf5a6c84SAndroid Build Coastguard Worker 
51*cf5a6c84SAndroid Build Coastguard Worker       [count][cmd]
52*cf5a6c84SAndroid Build Coastguard Worker       cmd: D I J O n o p x dd yy
53*cf5a6c84SAndroid Build Coastguard Worker 
54*cf5a6c84SAndroid Build Coastguard Worker       [cmd]
55*cf5a6c84SAndroid Build Coastguard Worker       cmd: / ? : A a i CTRL_D CTRL_B CTRL_E CTRL_F CTRL_Y \e \b
56*cf5a6c84SAndroid Build Coastguard Worker 
57*cf5a6c84SAndroid Build Coastguard Worker       [cmd]
58*cf5a6c84SAndroid Build Coastguard Worker       \b \e \n 'set list' 'set nolist' d $ % g v
59*cf5a6c84SAndroid Build Coastguard Worker */
60*cf5a6c84SAndroid Build Coastguard Worker #define FOR_vi
61*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
62*cf5a6c84SAndroid Build Coastguard Worker #define CTL(a) a-'@'
63*cf5a6c84SAndroid Build Coastguard Worker 
64*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
65*cf5a6c84SAndroid Build Coastguard Worker   char *c, *s;
66*cf5a6c84SAndroid Build Coastguard Worker 
67*cf5a6c84SAndroid Build Coastguard Worker   char *filename;
68*cf5a6c84SAndroid Build Coastguard Worker   int vi_mode, tabstop, list, cur_col, cur_row, scr_row, drawn_row, drawn_col,
69*cf5a6c84SAndroid Build Coastguard Worker       count0, count1, vi_mov_flag;
70*cf5a6c84SAndroid Build Coastguard Worker   unsigned screen_height, screen_width;
71*cf5a6c84SAndroid Build Coastguard Worker   char vi_reg, *last_search;
72*cf5a6c84SAndroid Build Coastguard Worker   struct str_line {
73*cf5a6c84SAndroid Build Coastguard Worker     int alloc, len;
74*cf5a6c84SAndroid Build Coastguard Worker     char *data;
75*cf5a6c84SAndroid Build Coastguard Worker   } *il;
76*cf5a6c84SAndroid Build Coastguard Worker   size_t screen, cursor; //offsets
77*cf5a6c84SAndroid Build Coastguard Worker   //yank buffer
78*cf5a6c84SAndroid Build Coastguard Worker   struct yank_buf {
79*cf5a6c84SAndroid Build Coastguard Worker     char reg;
80*cf5a6c84SAndroid Build Coastguard Worker     int alloc;
81*cf5a6c84SAndroid Build Coastguard Worker     char *data;
82*cf5a6c84SAndroid Build Coastguard Worker   } yank;
83*cf5a6c84SAndroid Build Coastguard Worker 
84*cf5a6c84SAndroid Build Coastguard Worker   size_t filesize;
85*cf5a6c84SAndroid Build Coastguard Worker // mem_block contains RO data that is either original file as mmap
86*cf5a6c84SAndroid Build Coastguard Worker // or heap allocated inserted data
87*cf5a6c84SAndroid Build Coastguard Worker   struct block_list {
88*cf5a6c84SAndroid Build Coastguard Worker     struct block_list *next, *prev;
89*cf5a6c84SAndroid Build Coastguard Worker     struct mem_block {
90*cf5a6c84SAndroid Build Coastguard Worker       size_t size, len;
91*cf5a6c84SAndroid Build Coastguard Worker       enum alloc_flag {
92*cf5a6c84SAndroid Build Coastguard Worker         MMAP,  //can be munmap() before exit()
93*cf5a6c84SAndroid Build Coastguard Worker         HEAP,  //can be free() before exit()
94*cf5a6c84SAndroid Build Coastguard Worker         STACK, //global or stack perhaps toybuf
95*cf5a6c84SAndroid Build Coastguard Worker       } alloc;
96*cf5a6c84SAndroid Build Coastguard Worker       const char *data;
97*cf5a6c84SAndroid Build Coastguard Worker     } *node;
98*cf5a6c84SAndroid Build Coastguard Worker   } *text;
99*cf5a6c84SAndroid Build Coastguard Worker 
100*cf5a6c84SAndroid Build Coastguard Worker // slices do not contain actual allocated data but slices of data in mem_block
101*cf5a6c84SAndroid Build Coastguard Worker // when file is first opened it has only one slice.
102*cf5a6c84SAndroid Build Coastguard Worker // after inserting data into middle new mem_block is allocated for insert data
103*cf5a6c84SAndroid Build Coastguard Worker // and 3 slices are created, where first and last slice are pointing to original
104*cf5a6c84SAndroid Build Coastguard Worker // mem_block with offsets, and middle slice is pointing to newly allocated block
105*cf5a6c84SAndroid Build Coastguard Worker // When deleting, data is not freed but mem_blocks are sliced more such way that
106*cf5a6c84SAndroid Build Coastguard Worker // deleted data left between 2 slices
107*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list {
108*cf5a6c84SAndroid Build Coastguard Worker     struct slice_list *next, *prev;
109*cf5a6c84SAndroid Build Coastguard Worker     struct slice {
110*cf5a6c84SAndroid Build Coastguard Worker       size_t len;
111*cf5a6c84SAndroid Build Coastguard Worker       const char *data;
112*cf5a6c84SAndroid Build Coastguard Worker     } *node;
113*cf5a6c84SAndroid Build Coastguard Worker   } *slices;
114*cf5a6c84SAndroid Build Coastguard Worker )
115*cf5a6c84SAndroid Build Coastguard Worker 
116*cf5a6c84SAndroid Build Coastguard Worker static const char *blank = " \n\r\t";
117*cf5a6c84SAndroid Build Coastguard Worker static const char *specials = ",.:;=-+*/(){}<>[]!@#$%^&|\\?\"\'";
118*cf5a6c84SAndroid Build Coastguard Worker 
119*cf5a6c84SAndroid Build Coastguard Worker //get utf8 length and width at same time
utf8_lnw(int * width,char * s,int bytes)120*cf5a6c84SAndroid Build Coastguard Worker static int utf8_lnw(int *width, char *s, int bytes)
121*cf5a6c84SAndroid Build Coastguard Worker {
122*cf5a6c84SAndroid Build Coastguard Worker   unsigned wc;
123*cf5a6c84SAndroid Build Coastguard Worker   int length = 1;
124*cf5a6c84SAndroid Build Coastguard Worker 
125*cf5a6c84SAndroid Build Coastguard Worker   if (*s == '\t') *width = TT.tabstop;
126*cf5a6c84SAndroid Build Coastguard Worker   else {
127*cf5a6c84SAndroid Build Coastguard Worker     length = utf8towc(&wc, s, bytes);
128*cf5a6c84SAndroid Build Coastguard Worker     if (length < 1) length = 0, *width = 0;
129*cf5a6c84SAndroid Build Coastguard Worker     else *width = wcwidth(wc);
130*cf5a6c84SAndroid Build Coastguard Worker   }
131*cf5a6c84SAndroid Build Coastguard Worker   return length;
132*cf5a6c84SAndroid Build Coastguard Worker }
133*cf5a6c84SAndroid Build Coastguard Worker 
utf8_dec(char key,char * utf8_scratch,int * sta_p)134*cf5a6c84SAndroid Build Coastguard Worker static int utf8_dec(char key, char *utf8_scratch, int *sta_p)
135*cf5a6c84SAndroid Build Coastguard Worker {
136*cf5a6c84SAndroid Build Coastguard Worker   int len = 0;
137*cf5a6c84SAndroid Build Coastguard Worker   char *c = utf8_scratch;
138*cf5a6c84SAndroid Build Coastguard Worker   c[*sta_p] = key;
139*cf5a6c84SAndroid Build Coastguard Worker   if (!(*sta_p))  *c = key;
140*cf5a6c84SAndroid Build Coastguard Worker   if (*c < 0x7F) return *sta_p = 1;
141*cf5a6c84SAndroid Build Coastguard Worker   if ((*c & 0xE0) == 0xc0) len = 2;
142*cf5a6c84SAndroid Build Coastguard Worker   else if ((*c & 0xF0) == 0xE0 ) len = 3;
143*cf5a6c84SAndroid Build Coastguard Worker   else if ((*c & 0xF8) == 0xF0 ) len = 4;
144*cf5a6c84SAndroid Build Coastguard Worker   else return *sta_p = 0;
145*cf5a6c84SAndroid Build Coastguard Worker 
146*cf5a6c84SAndroid Build Coastguard Worker   if (++*sta_p == 1) return 0;
147*cf5a6c84SAndroid Build Coastguard Worker   if ((c[*sta_p-1] & 0xc0) != 0x80) return *sta_p = 0;
148*cf5a6c84SAndroid Build Coastguard Worker 
149*cf5a6c84SAndroid Build Coastguard Worker   if (*sta_p == len) return !(c[(*sta_p)] = 0);
150*cf5a6c84SAndroid Build Coastguard Worker 
151*cf5a6c84SAndroid Build Coastguard Worker   return 0;
152*cf5a6c84SAndroid Build Coastguard Worker }
153*cf5a6c84SAndroid Build Coastguard Worker 
utf8_last(char * str,int size)154*cf5a6c84SAndroid Build Coastguard Worker static char* utf8_last(char* str, int size)
155*cf5a6c84SAndroid Build Coastguard Worker {
156*cf5a6c84SAndroid Build Coastguard Worker   char *end = str+size;
157*cf5a6c84SAndroid Build Coastguard Worker   int pos = size, len, width = 0;
158*cf5a6c84SAndroid Build Coastguard Worker 
159*cf5a6c84SAndroid Build Coastguard Worker   for (;pos >= 0; end--, pos--) {
160*cf5a6c84SAndroid Build Coastguard Worker     len = utf8_lnw(&width, end, size-pos);
161*cf5a6c84SAndroid Build Coastguard Worker     if (len && width) return end;
162*cf5a6c84SAndroid Build Coastguard Worker   }
163*cf5a6c84SAndroid Build Coastguard Worker   return 0;
164*cf5a6c84SAndroid Build Coastguard Worker }
165*cf5a6c84SAndroid Build Coastguard Worker 
dlist_add_before(struct double_list ** head,struct double_list ** list,char * data)166*cf5a6c84SAndroid Build Coastguard Worker struct double_list *dlist_add_before(struct double_list **head,
167*cf5a6c84SAndroid Build Coastguard Worker   struct double_list **list, char *data)
168*cf5a6c84SAndroid Build Coastguard Worker {
169*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *new = xmalloc(sizeof(struct double_list));
170*cf5a6c84SAndroid Build Coastguard Worker   new->data = data;
171*cf5a6c84SAndroid Build Coastguard Worker   if (*list == *head) *head = new;
172*cf5a6c84SAndroid Build Coastguard Worker 
173*cf5a6c84SAndroid Build Coastguard Worker   dlist_add_nomalloc(list, new);
174*cf5a6c84SAndroid Build Coastguard Worker   return new;
175*cf5a6c84SAndroid Build Coastguard Worker }
176*cf5a6c84SAndroid Build Coastguard Worker 
dlist_add_after(struct double_list ** head,struct double_list ** list,char * data)177*cf5a6c84SAndroid Build Coastguard Worker struct double_list *dlist_add_after(struct double_list **head,
178*cf5a6c84SAndroid Build Coastguard Worker   struct double_list **list, char *data)
179*cf5a6c84SAndroid Build Coastguard Worker {
180*cf5a6c84SAndroid Build Coastguard Worker   struct double_list *new = xmalloc(sizeof(struct double_list));
181*cf5a6c84SAndroid Build Coastguard Worker   new->data = data;
182*cf5a6c84SAndroid Build Coastguard Worker 
183*cf5a6c84SAndroid Build Coastguard Worker   if (*list) {
184*cf5a6c84SAndroid Build Coastguard Worker     new->prev = *list;
185*cf5a6c84SAndroid Build Coastguard Worker     new->next = (*list)->next;
186*cf5a6c84SAndroid Build Coastguard Worker     (*list)->next->prev = new;
187*cf5a6c84SAndroid Build Coastguard Worker     (*list)->next = new;
188*cf5a6c84SAndroid Build Coastguard Worker   } else *head = *list = new->next = new->prev = new;
189*cf5a6c84SAndroid Build Coastguard Worker   return new;
190*cf5a6c84SAndroid Build Coastguard Worker }
191*cf5a6c84SAndroid Build Coastguard Worker 
192*cf5a6c84SAndroid Build Coastguard Worker // str must be already allocated
193*cf5a6c84SAndroid Build Coastguard Worker // ownership of allocated data is moved
194*cf5a6c84SAndroid Build Coastguard Worker // data, pre allocated data
195*cf5a6c84SAndroid Build Coastguard Worker // offset, offset in whole text
196*cf5a6c84SAndroid Build Coastguard Worker // size, data allocation size of given data
197*cf5a6c84SAndroid Build Coastguard Worker // len, length of the string
198*cf5a6c84SAndroid Build Coastguard Worker // type, define allocation type for cleanup purposes at app exit
insert_str(const char * data,size_t offset,size_t size,size_t len,enum alloc_flag type)199*cf5a6c84SAndroid Build Coastguard Worker static int insert_str(const char *data, size_t offset, size_t size, size_t len,
200*cf5a6c84SAndroid Build Coastguard Worker   enum alloc_flag type)
201*cf5a6c84SAndroid Build Coastguard Worker {
202*cf5a6c84SAndroid Build Coastguard Worker   struct mem_block *b = xmalloc(sizeof(struct mem_block));
203*cf5a6c84SAndroid Build Coastguard Worker   struct slice *next = xmalloc(sizeof(struct slice));
204*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
205*cf5a6c84SAndroid Build Coastguard Worker 
206*cf5a6c84SAndroid Build Coastguard Worker   b->size = size;
207*cf5a6c84SAndroid Build Coastguard Worker   b->len = len;
208*cf5a6c84SAndroid Build Coastguard Worker   b->alloc = type;
209*cf5a6c84SAndroid Build Coastguard Worker   b->data = data;
210*cf5a6c84SAndroid Build Coastguard Worker   next->len = len;
211*cf5a6c84SAndroid Build Coastguard Worker   next->data = data;
212*cf5a6c84SAndroid Build Coastguard Worker 
213*cf5a6c84SAndroid Build Coastguard Worker   //mem blocks can be just added unordered
214*cf5a6c84SAndroid Build Coastguard Worker   TT.text = (struct block_list *)dlist_add((struct double_list **)&TT.text,
215*cf5a6c84SAndroid Build Coastguard Worker     (char *)b);
216*cf5a6c84SAndroid Build Coastguard Worker 
217*cf5a6c84SAndroid Build Coastguard Worker   if (!s) {
218*cf5a6c84SAndroid Build Coastguard Worker     TT.slices = (struct slice_list *)dlist_add(
219*cf5a6c84SAndroid Build Coastguard Worker       (struct double_list **)&TT.slices,
220*cf5a6c84SAndroid Build Coastguard Worker       (char *)next);
221*cf5a6c84SAndroid Build Coastguard Worker   } else {
222*cf5a6c84SAndroid Build Coastguard Worker     size_t pos = 0;
223*cf5a6c84SAndroid Build Coastguard Worker     //search insertation point for slice
224*cf5a6c84SAndroid Build Coastguard Worker     do {
225*cf5a6c84SAndroid Build Coastguard Worker       if (pos<=offset && pos+s->node->len>offset) break;
226*cf5a6c84SAndroid Build Coastguard Worker       pos += s->node->len;
227*cf5a6c84SAndroid Build Coastguard Worker       s = s->next;
228*cf5a6c84SAndroid Build Coastguard Worker       if (s == TT.slices) return -1; //error out of bounds
229*cf5a6c84SAndroid Build Coastguard Worker     } while (1);
230*cf5a6c84SAndroid Build Coastguard Worker     //need to cut previous slice into 2 since insert is in middle
231*cf5a6c84SAndroid Build Coastguard Worker     if (pos+s->node->len>offset && pos!=offset) {
232*cf5a6c84SAndroid Build Coastguard Worker       struct slice *tail = xmalloc(sizeof(struct slice));
233*cf5a6c84SAndroid Build Coastguard Worker       tail->len = s->node->len-(offset-pos);
234*cf5a6c84SAndroid Build Coastguard Worker       tail->data = s->node->data+(offset-pos);
235*cf5a6c84SAndroid Build Coastguard Worker       s->node->len = offset-pos;
236*cf5a6c84SAndroid Build Coastguard Worker       //pos = offset;
237*cf5a6c84SAndroid Build Coastguard Worker       s = (struct slice_list *)dlist_add_after(
238*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&TT.slices,
239*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&s,
240*cf5a6c84SAndroid Build Coastguard Worker         (char *)tail);
241*cf5a6c84SAndroid Build Coastguard Worker 
242*cf5a6c84SAndroid Build Coastguard Worker       s = (struct slice_list *)dlist_add_before(
243*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&TT.slices,
244*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&s,
245*cf5a6c84SAndroid Build Coastguard Worker         (char *)next);
246*cf5a6c84SAndroid Build Coastguard Worker     } else if (pos==offset) {
247*cf5a6c84SAndroid Build Coastguard Worker       // insert before
248*cf5a6c84SAndroid Build Coastguard Worker       s = (struct slice_list *)dlist_add_before(
249*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&TT.slices,
250*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&s,
251*cf5a6c84SAndroid Build Coastguard Worker         (char *)next);
252*cf5a6c84SAndroid Build Coastguard Worker     } else {
253*cf5a6c84SAndroid Build Coastguard Worker       // insert after
254*cf5a6c84SAndroid Build Coastguard Worker       s = (void *)dlist_add_after((void *)&TT.slices, (void *)&s, (void *)next);
255*cf5a6c84SAndroid Build Coastguard Worker     }
256*cf5a6c84SAndroid Build Coastguard Worker   }
257*cf5a6c84SAndroid Build Coastguard Worker   return 0;
258*cf5a6c84SAndroid Build Coastguard Worker }
259*cf5a6c84SAndroid Build Coastguard Worker 
260*cf5a6c84SAndroid Build Coastguard Worker // this will not free any memory
261*cf5a6c84SAndroid Build Coastguard Worker // will only create more slices depending on position
cut_str(size_t offset,size_t len)262*cf5a6c84SAndroid Build Coastguard Worker static int cut_str(size_t offset, size_t len)
263*cf5a6c84SAndroid Build Coastguard Worker {
264*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *e, *s = TT.slices;
265*cf5a6c84SAndroid Build Coastguard Worker   size_t end = offset+len;
266*cf5a6c84SAndroid Build Coastguard Worker   size_t epos, spos = 0;
267*cf5a6c84SAndroid Build Coastguard Worker 
268*cf5a6c84SAndroid Build Coastguard Worker   if (!s) return -1;
269*cf5a6c84SAndroid Build Coastguard Worker 
270*cf5a6c84SAndroid Build Coastguard Worker   //find start and end slices
271*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
272*cf5a6c84SAndroid Build Coastguard Worker     if (spos<=offset && spos+s->node->len>offset) break;
273*cf5a6c84SAndroid Build Coastguard Worker     spos += s->node->len;
274*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
275*cf5a6c84SAndroid Build Coastguard Worker 
276*cf5a6c84SAndroid Build Coastguard Worker     if (s == TT.slices) return -1; //error out of bounds
277*cf5a6c84SAndroid Build Coastguard Worker   }
278*cf5a6c84SAndroid Build Coastguard Worker 
279*cf5a6c84SAndroid Build Coastguard Worker   for (e = s, epos = spos; ; ) {
280*cf5a6c84SAndroid Build Coastguard Worker     if (epos<=end && epos+e->node->len>end) break;
281*cf5a6c84SAndroid Build Coastguard Worker     epos += e->node->len;
282*cf5a6c84SAndroid Build Coastguard Worker     e = e->next;
283*cf5a6c84SAndroid Build Coastguard Worker 
284*cf5a6c84SAndroid Build Coastguard Worker     if (e == TT.slices) return -1; //error out of bounds
285*cf5a6c84SAndroid Build Coastguard Worker   }
286*cf5a6c84SAndroid Build Coastguard Worker 
287*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
288*cf5a6c84SAndroid Build Coastguard Worker     if (spos == offset && ( end >= spos+s->node->len)) {
289*cf5a6c84SAndroid Build Coastguard Worker       //cut full
290*cf5a6c84SAndroid Build Coastguard Worker       spos += s->node->len;
291*cf5a6c84SAndroid Build Coastguard Worker       offset += s->node->len;
292*cf5a6c84SAndroid Build Coastguard Worker       s = dlist_pop(&s);
293*cf5a6c84SAndroid Build Coastguard Worker       if (s == TT.slices) TT.slices = s->next;
294*cf5a6c84SAndroid Build Coastguard Worker 
295*cf5a6c84SAndroid Build Coastguard Worker     } else if (spos < offset && ( end >= spos+s->node->len)) {
296*cf5a6c84SAndroid Build Coastguard Worker       //cut end
297*cf5a6c84SAndroid Build Coastguard Worker       size_t clip = s->node->len - (offset - spos);
298*cf5a6c84SAndroid Build Coastguard Worker       offset = spos+s->node->len;
299*cf5a6c84SAndroid Build Coastguard Worker       spos += s->node->len;
300*cf5a6c84SAndroid Build Coastguard Worker       s->node->len -= clip;
301*cf5a6c84SAndroid Build Coastguard Worker     } else if (spos == offset && s == e) {
302*cf5a6c84SAndroid Build Coastguard Worker       //cut begin
303*cf5a6c84SAndroid Build Coastguard Worker       size_t clip = end - offset;
304*cf5a6c84SAndroid Build Coastguard Worker       s->node->len -= clip;
305*cf5a6c84SAndroid Build Coastguard Worker       s->node->data += clip;
306*cf5a6c84SAndroid Build Coastguard Worker       break;
307*cf5a6c84SAndroid Build Coastguard Worker     } else {
308*cf5a6c84SAndroid Build Coastguard Worker       //cut middle
309*cf5a6c84SAndroid Build Coastguard Worker       struct slice *tail = xmalloc(sizeof(struct slice));
310*cf5a6c84SAndroid Build Coastguard Worker       size_t clip = end-offset;
311*cf5a6c84SAndroid Build Coastguard Worker       tail->len = s->node->len-(offset-spos)-clip;
312*cf5a6c84SAndroid Build Coastguard Worker       tail->data = s->node->data+(offset-spos)+clip;
313*cf5a6c84SAndroid Build Coastguard Worker       s->node->len = offset-spos; //wrong?
314*cf5a6c84SAndroid Build Coastguard Worker       s = (struct slice_list *)dlist_add_after(
315*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&TT.slices,
316*cf5a6c84SAndroid Build Coastguard Worker         (struct double_list **)&s,
317*cf5a6c84SAndroid Build Coastguard Worker         (char *)tail);
318*cf5a6c84SAndroid Build Coastguard Worker       break;
319*cf5a6c84SAndroid Build Coastguard Worker     }
320*cf5a6c84SAndroid Build Coastguard Worker     if (s == e) break;
321*cf5a6c84SAndroid Build Coastguard Worker 
322*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
323*cf5a6c84SAndroid Build Coastguard Worker   }
324*cf5a6c84SAndroid Build Coastguard Worker 
325*cf5a6c84SAndroid Build Coastguard Worker   return 0;
326*cf5a6c84SAndroid Build Coastguard Worker }
modified()327*cf5a6c84SAndroid Build Coastguard Worker static int modified()
328*cf5a6c84SAndroid Build Coastguard Worker {
329*cf5a6c84SAndroid Build Coastguard Worker   if (TT.text->next !=  TT.text->prev) return 1;
330*cf5a6c84SAndroid Build Coastguard Worker   if (TT.slices->next != TT.slices->prev) return 1;
331*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.text || !TT.slices) return 0;
332*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.text->node || !TT.slices->node) return 0;
333*cf5a6c84SAndroid Build Coastguard Worker   if (TT.text->node->alloc != MMAP) return 1;
334*cf5a6c84SAndroid Build Coastguard Worker   if (TT.text->node->len != TT.slices->node->len) return 1;
335*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.text->node->len) return 1;
336*cf5a6c84SAndroid Build Coastguard Worker   return 0;
337*cf5a6c84SAndroid Build Coastguard Worker }
338*cf5a6c84SAndroid Build Coastguard Worker 
339*cf5a6c84SAndroid Build Coastguard Worker //find offset position in slices
slice_offset(size_t * start,size_t offset)340*cf5a6c84SAndroid Build Coastguard Worker static struct slice_list *slice_offset(size_t *start, size_t offset)
341*cf5a6c84SAndroid Build Coastguard Worker {
342*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
343*cf5a6c84SAndroid Build Coastguard Worker   size_t spos = 0;
344*cf5a6c84SAndroid Build Coastguard Worker 
345*cf5a6c84SAndroid Build Coastguard Worker   //find start
346*cf5a6c84SAndroid Build Coastguard Worker   for ( ;s ; ) {
347*cf5a6c84SAndroid Build Coastguard Worker     if (spos<=offset && spos+s->node->len>offset) break;
348*cf5a6c84SAndroid Build Coastguard Worker 
349*cf5a6c84SAndroid Build Coastguard Worker     spos += s->node->len;
350*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
351*cf5a6c84SAndroid Build Coastguard Worker 
352*cf5a6c84SAndroid Build Coastguard Worker     if (s == TT.slices) s = 0; //error out of bounds
353*cf5a6c84SAndroid Build Coastguard Worker   }
354*cf5a6c84SAndroid Build Coastguard Worker   if (s) *start = spos;
355*cf5a6c84SAndroid Build Coastguard Worker   return s;
356*cf5a6c84SAndroid Build Coastguard Worker }
357*cf5a6c84SAndroid Build Coastguard Worker 
text_strchr(size_t offset,char c)358*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strchr(size_t offset, char c)
359*cf5a6c84SAndroid Build Coastguard Worker {
360*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
361*cf5a6c84SAndroid Build Coastguard Worker   size_t epos, spos = 0;
362*cf5a6c84SAndroid Build Coastguard Worker   int i = 0;
363*cf5a6c84SAndroid Build Coastguard Worker 
364*cf5a6c84SAndroid Build Coastguard Worker   //find start
365*cf5a6c84SAndroid Build Coastguard Worker   if (!(s = slice_offset(&spos, offset))) return SIZE_MAX;
366*cf5a6c84SAndroid Build Coastguard Worker 
367*cf5a6c84SAndroid Build Coastguard Worker   i = offset-spos;
368*cf5a6c84SAndroid Build Coastguard Worker   epos = spos+i;
369*cf5a6c84SAndroid Build Coastguard Worker   do {
370*cf5a6c84SAndroid Build Coastguard Worker     for (; i < s->node->len; i++, epos++)
371*cf5a6c84SAndroid Build Coastguard Worker       if (s->node->data[i] == c) return epos;
372*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
373*cf5a6c84SAndroid Build Coastguard Worker     i = 0;
374*cf5a6c84SAndroid Build Coastguard Worker   } while (s != TT.slices);
375*cf5a6c84SAndroid Build Coastguard Worker 
376*cf5a6c84SAndroid Build Coastguard Worker   return SIZE_MAX;
377*cf5a6c84SAndroid Build Coastguard Worker }
378*cf5a6c84SAndroid Build Coastguard Worker 
text_strrchr(size_t offset,char c)379*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strrchr(size_t offset, char c)
380*cf5a6c84SAndroid Build Coastguard Worker {
381*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
382*cf5a6c84SAndroid Build Coastguard Worker   size_t epos, spos = 0;
383*cf5a6c84SAndroid Build Coastguard Worker   int i = 0;
384*cf5a6c84SAndroid Build Coastguard Worker 
385*cf5a6c84SAndroid Build Coastguard Worker   //find start
386*cf5a6c84SAndroid Build Coastguard Worker   if (!(s = slice_offset(&spos, offset))) return SIZE_MAX;
387*cf5a6c84SAndroid Build Coastguard Worker 
388*cf5a6c84SAndroid Build Coastguard Worker   i = offset-spos;
389*cf5a6c84SAndroid Build Coastguard Worker   epos = spos+i;
390*cf5a6c84SAndroid Build Coastguard Worker   do {
391*cf5a6c84SAndroid Build Coastguard Worker     for (; i >= 0; i--, epos--)
392*cf5a6c84SAndroid Build Coastguard Worker       if (s->node->data[i] == c) return epos;
393*cf5a6c84SAndroid Build Coastguard Worker     s = s->prev;
394*cf5a6c84SAndroid Build Coastguard Worker     i = s->node->len-1;
395*cf5a6c84SAndroid Build Coastguard Worker   } while (s != TT.slices->prev); //tail
396*cf5a6c84SAndroid Build Coastguard Worker 
397*cf5a6c84SAndroid Build Coastguard Worker   return SIZE_MAX;
398*cf5a6c84SAndroid Build Coastguard Worker }
399*cf5a6c84SAndroid Build Coastguard Worker 
text_filesize()400*cf5a6c84SAndroid Build Coastguard Worker static size_t text_filesize()
401*cf5a6c84SAndroid Build Coastguard Worker {
402*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
403*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = 0;
404*cf5a6c84SAndroid Build Coastguard Worker 
405*cf5a6c84SAndroid Build Coastguard Worker   if (s) do {
406*cf5a6c84SAndroid Build Coastguard Worker     pos += s->node->len;
407*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
408*cf5a6c84SAndroid Build Coastguard Worker   } while (s != TT.slices);
409*cf5a6c84SAndroid Build Coastguard Worker 
410*cf5a6c84SAndroid Build Coastguard Worker   return pos;
411*cf5a6c84SAndroid Build Coastguard Worker }
412*cf5a6c84SAndroid Build Coastguard Worker 
text_count(size_t start,size_t end,char c)413*cf5a6c84SAndroid Build Coastguard Worker static int text_count(size_t start, size_t end, char c)
414*cf5a6c84SAndroid Build Coastguard Worker {
415*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
416*cf5a6c84SAndroid Build Coastguard Worker   size_t i, count = 0, spos = 0;
417*cf5a6c84SAndroid Build Coastguard Worker   if (!(s = slice_offset(&spos, start))) return 0;
418*cf5a6c84SAndroid Build Coastguard Worker   i = start-spos;
419*cf5a6c84SAndroid Build Coastguard Worker   if (s) do {
420*cf5a6c84SAndroid Build Coastguard Worker     for (; i < s->node->len && spos+i<end; i++)
421*cf5a6c84SAndroid Build Coastguard Worker       if (s->node->data[i] == c) count++;
422*cf5a6c84SAndroid Build Coastguard Worker     if (spos+i>=end) return count;
423*cf5a6c84SAndroid Build Coastguard Worker 
424*cf5a6c84SAndroid Build Coastguard Worker     spos += s->node->len;
425*cf5a6c84SAndroid Build Coastguard Worker     i = 0;
426*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
427*cf5a6c84SAndroid Build Coastguard Worker 
428*cf5a6c84SAndroid Build Coastguard Worker   } while (s != TT.slices);
429*cf5a6c84SAndroid Build Coastguard Worker 
430*cf5a6c84SAndroid Build Coastguard Worker   return count;
431*cf5a6c84SAndroid Build Coastguard Worker }
432*cf5a6c84SAndroid Build Coastguard Worker 
text_byte(size_t offset)433*cf5a6c84SAndroid Build Coastguard Worker static char text_byte(size_t offset)
434*cf5a6c84SAndroid Build Coastguard Worker {
435*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
436*cf5a6c84SAndroid Build Coastguard Worker   size_t spos = 0;
437*cf5a6c84SAndroid Build Coastguard Worker 
438*cf5a6c84SAndroid Build Coastguard Worker   //find start
439*cf5a6c84SAndroid Build Coastguard Worker   if (!(s = slice_offset(&spos, offset))) return 0;
440*cf5a6c84SAndroid Build Coastguard Worker   return s->node->data[offset-spos];
441*cf5a6c84SAndroid Build Coastguard Worker }
442*cf5a6c84SAndroid Build Coastguard Worker 
443*cf5a6c84SAndroid Build Coastguard Worker //utf-8 codepoint -1 if not valid, 0 if out_of_bounds, len if valid
444*cf5a6c84SAndroid Build Coastguard Worker //copies data to dest if dest is not 0
text_codepoint(char * dest,size_t offset)445*cf5a6c84SAndroid Build Coastguard Worker static int text_codepoint(char *dest, size_t offset)
446*cf5a6c84SAndroid Build Coastguard Worker {
447*cf5a6c84SAndroid Build Coastguard Worker   char scratch[8] = {0};
448*cf5a6c84SAndroid Build Coastguard Worker   int state = 0, finished = 0;
449*cf5a6c84SAndroid Build Coastguard Worker 
450*cf5a6c84SAndroid Build Coastguard Worker   for (;!(finished = utf8_dec(text_byte(offset), scratch, &state)); offset++)
451*cf5a6c84SAndroid Build Coastguard Worker     if (!state) return -1;
452*cf5a6c84SAndroid Build Coastguard Worker 
453*cf5a6c84SAndroid Build Coastguard Worker   if (!finished && !state) return -1;
454*cf5a6c84SAndroid Build Coastguard Worker   if (dest) memcpy(dest, scratch, 8);
455*cf5a6c84SAndroid Build Coastguard Worker 
456*cf5a6c84SAndroid Build Coastguard Worker   return strlen(scratch);
457*cf5a6c84SAndroid Build Coastguard Worker }
458*cf5a6c84SAndroid Build Coastguard Worker 
text_sol(size_t offset)459*cf5a6c84SAndroid Build Coastguard Worker static size_t text_sol(size_t offset)
460*cf5a6c84SAndroid Build Coastguard Worker {
461*cf5a6c84SAndroid Build Coastguard Worker   size_t pos;
462*cf5a6c84SAndroid Build Coastguard Worker 
463*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.filesize || !offset) return 0;
464*cf5a6c84SAndroid Build Coastguard Worker   else if (TT.filesize <= offset) return TT.filesize-1;
465*cf5a6c84SAndroid Build Coastguard Worker   else if ((pos = text_strrchr(offset-1, '\n')) == SIZE_MAX) return 0;
466*cf5a6c84SAndroid Build Coastguard Worker   else if (pos < offset) return pos+1;
467*cf5a6c84SAndroid Build Coastguard Worker   return offset;
468*cf5a6c84SAndroid Build Coastguard Worker }
469*cf5a6c84SAndroid Build Coastguard Worker 
text_eol(size_t offset)470*cf5a6c84SAndroid Build Coastguard Worker static size_t text_eol(size_t offset)
471*cf5a6c84SAndroid Build Coastguard Worker {
472*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.filesize) offset = 1;
473*cf5a6c84SAndroid Build Coastguard Worker   else if (TT.filesize <= offset) return TT.filesize-1;
474*cf5a6c84SAndroid Build Coastguard Worker   else if ((offset = text_strchr(offset, '\n')) == SIZE_MAX)
475*cf5a6c84SAndroid Build Coastguard Worker     return TT.filesize-1;
476*cf5a6c84SAndroid Build Coastguard Worker   return offset;
477*cf5a6c84SAndroid Build Coastguard Worker }
478*cf5a6c84SAndroid Build Coastguard Worker 
text_nsol(size_t offset)479*cf5a6c84SAndroid Build Coastguard Worker static size_t text_nsol(size_t offset)
480*cf5a6c84SAndroid Build Coastguard Worker {
481*cf5a6c84SAndroid Build Coastguard Worker   offset = text_eol(offset);
482*cf5a6c84SAndroid Build Coastguard Worker   if (text_byte(offset) == '\n') offset++;
483*cf5a6c84SAndroid Build Coastguard Worker   if (offset >= TT.filesize) offset--;
484*cf5a6c84SAndroid Build Coastguard Worker   return offset;
485*cf5a6c84SAndroid Build Coastguard Worker }
486*cf5a6c84SAndroid Build Coastguard Worker 
text_psol(size_t offset)487*cf5a6c84SAndroid Build Coastguard Worker static size_t text_psol(size_t offset)
488*cf5a6c84SAndroid Build Coastguard Worker {
489*cf5a6c84SAndroid Build Coastguard Worker   offset = text_sol(offset);
490*cf5a6c84SAndroid Build Coastguard Worker   if (offset) offset--;
491*cf5a6c84SAndroid Build Coastguard Worker   if (offset && text_byte(offset-1) != '\n') offset = text_sol(offset-1);
492*cf5a6c84SAndroid Build Coastguard Worker   return offset;
493*cf5a6c84SAndroid Build Coastguard Worker }
494*cf5a6c84SAndroid Build Coastguard Worker 
text_getline(char * dest,size_t offset,size_t max_len)495*cf5a6c84SAndroid Build Coastguard Worker static size_t text_getline(char *dest, size_t offset, size_t max_len)
496*cf5a6c84SAndroid Build Coastguard Worker {
497*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
498*cf5a6c84SAndroid Build Coastguard Worker   size_t end, spos = 0;
499*cf5a6c84SAndroid Build Coastguard Worker   int i, j = 0;
500*cf5a6c84SAndroid Build Coastguard Worker 
501*cf5a6c84SAndroid Build Coastguard Worker   if (dest) *dest = 0;
502*cf5a6c84SAndroid Build Coastguard Worker 
503*cf5a6c84SAndroid Build Coastguard Worker   if (!s) return 0;
504*cf5a6c84SAndroid Build Coastguard Worker   if ((end = text_strchr(offset, '\n')) == SIZE_MAX)
505*cf5a6c84SAndroid Build Coastguard Worker     if ((end = TT.filesize)  > offset+max_len) return 0;
506*cf5a6c84SAndroid Build Coastguard Worker 
507*cf5a6c84SAndroid Build Coastguard Worker   //find start
508*cf5a6c84SAndroid Build Coastguard Worker   if (!(s = slice_offset(&spos, offset))) return 0;
509*cf5a6c84SAndroid Build Coastguard Worker 
510*cf5a6c84SAndroid Build Coastguard Worker   i = offset-spos;
511*cf5a6c84SAndroid Build Coastguard Worker   j = end-offset+1;
512*cf5a6c84SAndroid Build Coastguard Worker   if (dest) do {
513*cf5a6c84SAndroid Build Coastguard Worker     for (; i < s->node->len && j; i++, j--, dest++)
514*cf5a6c84SAndroid Build Coastguard Worker       *dest = s->node->data[i];
515*cf5a6c84SAndroid Build Coastguard Worker     s = s->next;
516*cf5a6c84SAndroid Build Coastguard Worker     i = 0;
517*cf5a6c84SAndroid Build Coastguard Worker   } while (s != TT.slices && j);
518*cf5a6c84SAndroid Build Coastguard Worker 
519*cf5a6c84SAndroid Build Coastguard Worker   if (dest) *dest = 0;
520*cf5a6c84SAndroid Build Coastguard Worker 
521*cf5a6c84SAndroid Build Coastguard Worker   return end-offset;
522*cf5a6c84SAndroid Build Coastguard Worker }
523*cf5a6c84SAndroid Build Coastguard Worker 
524*cf5a6c84SAndroid Build Coastguard Worker // copying is needed when file has lot of inserts that are
525*cf5a6c84SAndroid Build Coastguard Worker // just few char long, but not always. Advanced search should
526*cf5a6c84SAndroid Build Coastguard Worker // check big slices directly and just copy edge cases.
527*cf5a6c84SAndroid Build Coastguard Worker // Also this is only line based search multiline
528*cf5a6c84SAndroid Build Coastguard Worker // and regexec should be done instead.
text_strstr(size_t offset,char * str,int dir)529*cf5a6c84SAndroid Build Coastguard Worker static size_t text_strstr(size_t offset, char *str, int dir)
530*cf5a6c84SAndroid Build Coastguard Worker {
531*cf5a6c84SAndroid Build Coastguard Worker   size_t bytes, pos = offset;
532*cf5a6c84SAndroid Build Coastguard Worker   char *s = 0;
533*cf5a6c84SAndroid Build Coastguard Worker 
534*cf5a6c84SAndroid Build Coastguard Worker   do {
535*cf5a6c84SAndroid Build Coastguard Worker     bytes = text_getline(toybuf, pos, ARRAY_LEN(toybuf));
536*cf5a6c84SAndroid Build Coastguard Worker     if (!bytes) pos += (dir ? 1 : -1); //empty line
537*cf5a6c84SAndroid Build Coastguard Worker     else if ((s = strstr(toybuf, str))) return pos+(s-toybuf);
538*cf5a6c84SAndroid Build Coastguard Worker     else {
539*cf5a6c84SAndroid Build Coastguard Worker       if (!dir) pos -= bytes;
540*cf5a6c84SAndroid Build Coastguard Worker       else pos += bytes;
541*cf5a6c84SAndroid Build Coastguard Worker     }
542*cf5a6c84SAndroid Build Coastguard Worker   } while (pos < (dir ? 0 : TT.filesize));
543*cf5a6c84SAndroid Build Coastguard Worker 
544*cf5a6c84SAndroid Build Coastguard Worker   return SIZE_MAX;
545*cf5a6c84SAndroid Build Coastguard Worker }
546*cf5a6c84SAndroid Build Coastguard Worker 
block_list_free(void * node)547*cf5a6c84SAndroid Build Coastguard Worker static void block_list_free(void *node)
548*cf5a6c84SAndroid Build Coastguard Worker {
549*cf5a6c84SAndroid Build Coastguard Worker   struct block_list *d = node;
550*cf5a6c84SAndroid Build Coastguard Worker 
551*cf5a6c84SAndroid Build Coastguard Worker   if (d->node->alloc == HEAP) free((void *)d->node->data);
552*cf5a6c84SAndroid Build Coastguard Worker   else if (d->node->alloc == MMAP) munmap((void *)d->node->data, d->node->size);
553*cf5a6c84SAndroid Build Coastguard Worker 
554*cf5a6c84SAndroid Build Coastguard Worker   free(d->node);
555*cf5a6c84SAndroid Build Coastguard Worker   free(d);
556*cf5a6c84SAndroid Build Coastguard Worker }
557*cf5a6c84SAndroid Build Coastguard Worker 
show_error(char * fmt,...)558*cf5a6c84SAndroid Build Coastguard Worker static void show_error(char *fmt, ...)
559*cf5a6c84SAndroid Build Coastguard Worker {
560*cf5a6c84SAndroid Build Coastguard Worker   va_list va;
561*cf5a6c84SAndroid Build Coastguard Worker 
562*cf5a6c84SAndroid Build Coastguard Worker   printf("\a\e[%dH\e[41m\e[37m\e[K\e[1m", TT.screen_height+1);
563*cf5a6c84SAndroid Build Coastguard Worker   va_start(va, fmt);
564*cf5a6c84SAndroid Build Coastguard Worker   vprintf(fmt, va);
565*cf5a6c84SAndroid Build Coastguard Worker   va_end(va);
566*cf5a6c84SAndroid Build Coastguard Worker   printf("\e[0m");
567*cf5a6c84SAndroid Build Coastguard Worker   fflush(0);
568*cf5a6c84SAndroid Build Coastguard Worker   xferror(stdout);
569*cf5a6c84SAndroid Build Coastguard Worker 
570*cf5a6c84SAndroid Build Coastguard Worker   // TODO: better integration with status line: keep
571*cf5a6c84SAndroid Build Coastguard Worker   // message until next operation.
572*cf5a6c84SAndroid Build Coastguard Worker   (void)getchar();
573*cf5a6c84SAndroid Build Coastguard Worker }
574*cf5a6c84SAndroid Build Coastguard Worker 
linelist_unload()575*cf5a6c84SAndroid Build Coastguard Worker static void linelist_unload()
576*cf5a6c84SAndroid Build Coastguard Worker {
577*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse((void *)TT.slices, llist_free_double);
578*cf5a6c84SAndroid Build Coastguard Worker   llist_traverse((void *)TT.text, block_list_free);
579*cf5a6c84SAndroid Build Coastguard Worker   TT.slices = 0, TT.text = 0;
580*cf5a6c84SAndroid Build Coastguard Worker }
581*cf5a6c84SAndroid Build Coastguard Worker 
linelist_load(char * filename,int ignore_missing)582*cf5a6c84SAndroid Build Coastguard Worker static void linelist_load(char *filename, int ignore_missing)
583*cf5a6c84SAndroid Build Coastguard Worker {
584*cf5a6c84SAndroid Build Coastguard Worker   int fd;
585*cf5a6c84SAndroid Build Coastguard Worker   long long size;
586*cf5a6c84SAndroid Build Coastguard Worker 
587*cf5a6c84SAndroid Build Coastguard Worker   if (!filename) filename = TT.filename;
588*cf5a6c84SAndroid Build Coastguard Worker   if (!filename) {
589*cf5a6c84SAndroid Build Coastguard Worker     // `vi` with no arguments creates a new unnamed file.
590*cf5a6c84SAndroid Build Coastguard Worker     insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
591*cf5a6c84SAndroid Build Coastguard Worker     return;
592*cf5a6c84SAndroid Build Coastguard Worker   }
593*cf5a6c84SAndroid Build Coastguard Worker 
594*cf5a6c84SAndroid Build Coastguard Worker   fd = open(filename, O_RDONLY);
595*cf5a6c84SAndroid Build Coastguard Worker   if (fd == -1) {
596*cf5a6c84SAndroid Build Coastguard Worker     if (!ignore_missing)
597*cf5a6c84SAndroid Build Coastguard Worker       show_error("Couldn't open \"%s\" for reading: %s", filename,
598*cf5a6c84SAndroid Build Coastguard Worker           strerror(errno));
599*cf5a6c84SAndroid Build Coastguard Worker     insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
600*cf5a6c84SAndroid Build Coastguard Worker     return;
601*cf5a6c84SAndroid Build Coastguard Worker   }
602*cf5a6c84SAndroid Build Coastguard Worker 
603*cf5a6c84SAndroid Build Coastguard Worker   size = fdlength(fd);
604*cf5a6c84SAndroid Build Coastguard Worker   if (size > 0) {
605*cf5a6c84SAndroid Build Coastguard Worker     insert_str(xmmap(0,size,PROT_READ,MAP_SHARED,fd,0), 0, size, size, MMAP);
606*cf5a6c84SAndroid Build Coastguard Worker     TT.filesize = text_filesize();
607*cf5a6c84SAndroid Build Coastguard Worker   } else if (!size) insert_str(xstrdup("\n"), 0, 1, 1, HEAP);
608*cf5a6c84SAndroid Build Coastguard Worker   xclose(fd);
609*cf5a6c84SAndroid Build Coastguard Worker }
610*cf5a6c84SAndroid Build Coastguard Worker 
write_file(char * filename)611*cf5a6c84SAndroid Build Coastguard Worker static int write_file(char *filename)
612*cf5a6c84SAndroid Build Coastguard Worker {
613*cf5a6c84SAndroid Build Coastguard Worker   struct slice_list *s = TT.slices;
614*cf5a6c84SAndroid Build Coastguard Worker   struct stat st;
615*cf5a6c84SAndroid Build Coastguard Worker   int fd = 0;
616*cf5a6c84SAndroid Build Coastguard Worker 
617*cf5a6c84SAndroid Build Coastguard Worker   if (!modified()) show_error("Not modified");
618*cf5a6c84SAndroid Build Coastguard Worker   if (!filename) filename = TT.filename;
619*cf5a6c84SAndroid Build Coastguard Worker   if (!filename) {
620*cf5a6c84SAndroid Build Coastguard Worker     show_error("No file name");
621*cf5a6c84SAndroid Build Coastguard Worker     return -1;
622*cf5a6c84SAndroid Build Coastguard Worker   }
623*cf5a6c84SAndroid Build Coastguard Worker 
624*cf5a6c84SAndroid Build Coastguard Worker   if (stat(filename, &st) == -1) st.st_mode = 0644;
625*cf5a6c84SAndroid Build Coastguard Worker 
626*cf5a6c84SAndroid Build Coastguard Worker   sprintf(toybuf, "%s.swp", filename);
627*cf5a6c84SAndroid Build Coastguard Worker 
628*cf5a6c84SAndroid Build Coastguard Worker   if ((fd = open(toybuf, O_WRONLY | O_CREAT | O_TRUNC, st.st_mode)) == -1) {
629*cf5a6c84SAndroid Build Coastguard Worker     show_error("Couldn't open \"%s\" for writing: %s", toybuf, strerror(errno));
630*cf5a6c84SAndroid Build Coastguard Worker     return -1;
631*cf5a6c84SAndroid Build Coastguard Worker   }
632*cf5a6c84SAndroid Build Coastguard Worker 
633*cf5a6c84SAndroid Build Coastguard Worker   if (s) {
634*cf5a6c84SAndroid Build Coastguard Worker     do {
635*cf5a6c84SAndroid Build Coastguard Worker       xwrite(fd, (void *)s->node->data, s->node->len);
636*cf5a6c84SAndroid Build Coastguard Worker       s = s->next;
637*cf5a6c84SAndroid Build Coastguard Worker     } while (s != TT.slices);
638*cf5a6c84SAndroid Build Coastguard Worker   }
639*cf5a6c84SAndroid Build Coastguard Worker 
640*cf5a6c84SAndroid Build Coastguard Worker   linelist_unload();
641*cf5a6c84SAndroid Build Coastguard Worker 
642*cf5a6c84SAndroid Build Coastguard Worker   xclose(fd);
643*cf5a6c84SAndroid Build Coastguard Worker   if (!rename(toybuf, filename)) return 1;
644*cf5a6c84SAndroid Build Coastguard Worker   linelist_load(filename, 0);
645*cf5a6c84SAndroid Build Coastguard Worker   return 0;
646*cf5a6c84SAndroid Build Coastguard Worker }
647*cf5a6c84SAndroid Build Coastguard Worker 
648*cf5a6c84SAndroid Build Coastguard Worker // jump into valid offset index
649*cf5a6c84SAndroid Build Coastguard Worker // and valid utf8 codepoint
check_cursor_bounds()650*cf5a6c84SAndroid Build Coastguard Worker static void check_cursor_bounds()
651*cf5a6c84SAndroid Build Coastguard Worker {
652*cf5a6c84SAndroid Build Coastguard Worker   char buf[8] = {0};
653*cf5a6c84SAndroid Build Coastguard Worker   int len, width = 0;
654*cf5a6c84SAndroid Build Coastguard Worker 
655*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.filesize) TT.cursor = 0;
656*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
657*cf5a6c84SAndroid Build Coastguard Worker     if (TT.cursor < 1) {
658*cf5a6c84SAndroid Build Coastguard Worker       TT.cursor = 0;
659*cf5a6c84SAndroid Build Coastguard Worker       return;
660*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.cursor >= TT.filesize-1) {
661*cf5a6c84SAndroid Build Coastguard Worker       TT.cursor = TT.filesize-1;
662*cf5a6c84SAndroid Build Coastguard Worker       return;
663*cf5a6c84SAndroid Build Coastguard Worker     }
664*cf5a6c84SAndroid Build Coastguard Worker     // if we are not in valid data try jump over
665*cf5a6c84SAndroid Build Coastguard Worker     if ((len = text_codepoint(buf, TT.cursor)) < 1) TT.cursor--;
666*cf5a6c84SAndroid Build Coastguard Worker     else if (utf8_lnw(&width, buf, len) && width) break;
667*cf5a6c84SAndroid Build Coastguard Worker     else TT.cursor--; //combine char jump over
668*cf5a6c84SAndroid Build Coastguard Worker   }
669*cf5a6c84SAndroid Build Coastguard Worker }
670*cf5a6c84SAndroid Build Coastguard Worker 
671*cf5a6c84SAndroid Build Coastguard Worker // TT.vi_mov_flag is used for special cases when certain move
672*cf5a6c84SAndroid Build Coastguard Worker // acts differently depending is there DELETE/YANK or NOP
673*cf5a6c84SAndroid Build Coastguard Worker // Also commands such as G does not default to count0=1
674*cf5a6c84SAndroid Build Coastguard Worker // 0x1 = Command needs argument (f,F,r...)
675*cf5a6c84SAndroid Build Coastguard Worker // 0x2 = Move 1 right on yank/delete/insert (e, $...)
676*cf5a6c84SAndroid Build Coastguard Worker // 0x4 = yank/delete last line fully
677*cf5a6c84SAndroid Build Coastguard Worker // 0x10000000 = redraw after cursor needed
678*cf5a6c84SAndroid Build Coastguard Worker // 0x20000000 = full redraw needed
679*cf5a6c84SAndroid Build Coastguard Worker // 0x40000000 = count0 not given
680*cf5a6c84SAndroid Build Coastguard Worker // 0x80000000 = move was reverse
681*cf5a6c84SAndroid Build Coastguard Worker 
682*cf5a6c84SAndroid Build Coastguard Worker // TODO rewrite the logic, difficulties counting lines
683*cf5a6c84SAndroid Build Coastguard Worker // and with big files scroll should not rely in knowing
684*cf5a6c84SAndroid Build Coastguard Worker // absoluteline numbers
adjust_screen_buffer()685*cf5a6c84SAndroid Build Coastguard Worker static void adjust_screen_buffer()
686*cf5a6c84SAndroid Build Coastguard Worker {
687*cf5a6c84SAndroid Build Coastguard Worker   size_t c, s;
688*cf5a6c84SAndroid Build Coastguard Worker   TT.cur_row = 0, TT.scr_row = 0;
689*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.cursor) {
690*cf5a6c84SAndroid Build Coastguard Worker     TT.screen = 0;
691*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_mov_flag = 0x20000000;
692*cf5a6c84SAndroid Build Coastguard Worker     return;
693*cf5a6c84SAndroid Build Coastguard Worker   } else if (TT.screen > (1<<18) || TT.cursor > (1<<18)) {
694*cf5a6c84SAndroid Build Coastguard Worker     //give up, file is big, do full redraw
695*cf5a6c84SAndroid Build Coastguard Worker 
696*cf5a6c84SAndroid Build Coastguard Worker     TT.screen = text_strrchr(TT.cursor-1, '\n')+1;
697*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_mov_flag = 0x20000000;
698*cf5a6c84SAndroid Build Coastguard Worker     return;
699*cf5a6c84SAndroid Build Coastguard Worker   }
700*cf5a6c84SAndroid Build Coastguard Worker 
701*cf5a6c84SAndroid Build Coastguard Worker   s = text_count(0, TT.screen, '\n');
702*cf5a6c84SAndroid Build Coastguard Worker   c = text_count(0, TT.cursor, '\n');
703*cf5a6c84SAndroid Build Coastguard Worker   if (s >= c) {
704*cf5a6c84SAndroid Build Coastguard Worker     TT.screen = text_strrchr(TT.cursor-1, '\n')+1;
705*cf5a6c84SAndroid Build Coastguard Worker     s = c;
706*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll
707*cf5a6c84SAndroid Build Coastguard Worker   } else {
708*cf5a6c84SAndroid Build Coastguard Worker     int distance = c-s+1;
709*cf5a6c84SAndroid Build Coastguard Worker     if (distance > (int)TT.screen_height) {
710*cf5a6c84SAndroid Build Coastguard Worker       int n, adj = distance-TT.screen_height;
711*cf5a6c84SAndroid Build Coastguard Worker       TT.vi_mov_flag = 0x20000000; //TODO I disabled scroll
712*cf5a6c84SAndroid Build Coastguard Worker       for (;adj; adj--, s++)
713*cf5a6c84SAndroid Build Coastguard Worker         if ((n = text_strchr(TT.screen, '\n'))+1 > TT.screen)
714*cf5a6c84SAndroid Build Coastguard Worker           TT.screen = n+1;
715*cf5a6c84SAndroid Build Coastguard Worker     }
716*cf5a6c84SAndroid Build Coastguard Worker   }
717*cf5a6c84SAndroid Build Coastguard Worker 
718*cf5a6c84SAndroid Build Coastguard Worker   TT.scr_row = s;
719*cf5a6c84SAndroid Build Coastguard Worker   TT.cur_row = c;
720*cf5a6c84SAndroid Build Coastguard Worker }
721*cf5a6c84SAndroid Build Coastguard Worker 
722*cf5a6c84SAndroid Build Coastguard Worker // TODO search yank buffer by register
723*cf5a6c84SAndroid Build Coastguard Worker // TODO yanks could be separate slices so no need to copy data
724*cf5a6c84SAndroid Build Coastguard Worker // now only supports default register
vi_yank(char reg,size_t from,int flags)725*cf5a6c84SAndroid Build Coastguard Worker static int vi_yank(char reg, size_t from, int flags)
726*cf5a6c84SAndroid Build Coastguard Worker {
727*cf5a6c84SAndroid Build Coastguard Worker   size_t start = from, end = TT.cursor;
728*cf5a6c84SAndroid Build Coastguard Worker   char *str;
729*cf5a6c84SAndroid Build Coastguard Worker 
730*cf5a6c84SAndroid Build Coastguard Worker   memset(TT.yank.data, 0, TT.yank.alloc);
731*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mov_flag&0x80000000) start = TT.cursor, end = from;
732*cf5a6c84SAndroid Build Coastguard Worker   else TT.cursor = start; //yank moves cursor to left pos always?
733*cf5a6c84SAndroid Build Coastguard Worker 
734*cf5a6c84SAndroid Build Coastguard Worker   if (TT.yank.alloc < end-from) {
735*cf5a6c84SAndroid Build Coastguard Worker     size_t new_bounds = (1+end-from)/1024;
736*cf5a6c84SAndroid Build Coastguard Worker     new_bounds += ((1+end-from)%1024) ? 1 : 0;
737*cf5a6c84SAndroid Build Coastguard Worker     new_bounds *= 1024;
738*cf5a6c84SAndroid Build Coastguard Worker     TT.yank.data = xrealloc(TT.yank.data, new_bounds);
739*cf5a6c84SAndroid Build Coastguard Worker     TT.yank.alloc = new_bounds;
740*cf5a6c84SAndroid Build Coastguard Worker   }
741*cf5a6c84SAndroid Build Coastguard Worker 
742*cf5a6c84SAndroid Build Coastguard Worker   //this is naive copy
743*cf5a6c84SAndroid Build Coastguard Worker   for (str = TT.yank.data ; start<end; start++, str++) *str = text_byte(start);
744*cf5a6c84SAndroid Build Coastguard Worker 
745*cf5a6c84SAndroid Build Coastguard Worker   *str = 0;
746*cf5a6c84SAndroid Build Coastguard Worker 
747*cf5a6c84SAndroid Build Coastguard Worker   return 1;
748*cf5a6c84SAndroid Build Coastguard Worker }
749*cf5a6c84SAndroid Build Coastguard Worker 
vi_delete(char reg,size_t from,int flags)750*cf5a6c84SAndroid Build Coastguard Worker static int vi_delete(char reg, size_t from, int flags)
751*cf5a6c84SAndroid Build Coastguard Worker {
752*cf5a6c84SAndroid Build Coastguard Worker   size_t start = from, end = TT.cursor;
753*cf5a6c84SAndroid Build Coastguard Worker 
754*cf5a6c84SAndroid Build Coastguard Worker   vi_yank(reg, from, flags);
755*cf5a6c84SAndroid Build Coastguard Worker 
756*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mov_flag&0x80000000) start = TT.cursor, end = from;
757*cf5a6c84SAndroid Build Coastguard Worker 
758*cf5a6c84SAndroid Build Coastguard Worker   //pre adjust cursor move one right until at next valid rune
759*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mov_flag&2) {
760*cf5a6c84SAndroid Build Coastguard Worker     //TODO
761*cf5a6c84SAndroid Build Coastguard Worker   }
762*cf5a6c84SAndroid Build Coastguard Worker   //do slice cut
763*cf5a6c84SAndroid Build Coastguard Worker   cut_str(start, end-start);
764*cf5a6c84SAndroid Build Coastguard Worker 
765*cf5a6c84SAndroid Build Coastguard Worker   //cursor is at start at after delete
766*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = start;
767*cf5a6c84SAndroid Build Coastguard Worker   TT.filesize = text_filesize();
768*cf5a6c84SAndroid Build Coastguard Worker   //find line start by strrchr(/n) ++
769*cf5a6c84SAndroid Build Coastguard Worker   //set cur_col with crunch_n_str maybe?
770*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x30000000;
771*cf5a6c84SAndroid Build Coastguard Worker 
772*cf5a6c84SAndroid Build Coastguard Worker   return 1;
773*cf5a6c84SAndroid Build Coastguard Worker }
774*cf5a6c84SAndroid Build Coastguard Worker 
vi_change(char reg,size_t to,int flags)775*cf5a6c84SAndroid Build Coastguard Worker static int vi_change(char reg, size_t to, int flags)
776*cf5a6c84SAndroid Build Coastguard Worker {
777*cf5a6c84SAndroid Build Coastguard Worker   vi_delete(reg, to, flags);
778*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mode = 2;
779*cf5a6c84SAndroid Build Coastguard Worker   return 1;
780*cf5a6c84SAndroid Build Coastguard Worker }
781*cf5a6c84SAndroid Build Coastguard Worker 
cur_left(int count0,int count1,char * unused)782*cf5a6c84SAndroid Build Coastguard Worker static int cur_left(int count0, int count1, char *unused)
783*cf5a6c84SAndroid Build Coastguard Worker {
784*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
785*cf5a6c84SAndroid Build Coastguard Worker 
786*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x80000000;
787*cf5a6c84SAndroid Build Coastguard Worker   for (;count && TT.cursor; count--) {
788*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor--;
789*cf5a6c84SAndroid Build Coastguard Worker     if (text_byte(TT.cursor) == '\n') TT.cursor++;
790*cf5a6c84SAndroid Build Coastguard Worker     check_cursor_bounds();
791*cf5a6c84SAndroid Build Coastguard Worker   }
792*cf5a6c84SAndroid Build Coastguard Worker   return 1;
793*cf5a6c84SAndroid Build Coastguard Worker }
794*cf5a6c84SAndroid Build Coastguard Worker 
cur_right(int count0,int count1,char * unused)795*cf5a6c84SAndroid Build Coastguard Worker static int cur_right(int count0, int count1, char *unused)
796*cf5a6c84SAndroid Build Coastguard Worker {
797*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1, len, width = 0;
798*cf5a6c84SAndroid Build Coastguard Worker   char buf[8] = {0};
799*cf5a6c84SAndroid Build Coastguard Worker 
800*cf5a6c84SAndroid Build Coastguard Worker   for (;count; count--) {
801*cf5a6c84SAndroid Build Coastguard Worker     len = text_codepoint(buf, TT.cursor);
802*cf5a6c84SAndroid Build Coastguard Worker 
803*cf5a6c84SAndroid Build Coastguard Worker     if (*buf == '\n') break;
804*cf5a6c84SAndroid Build Coastguard Worker     else if (len > 0) TT.cursor += len;
805*cf5a6c84SAndroid Build Coastguard Worker     else TT.cursor++;
806*cf5a6c84SAndroid Build Coastguard Worker 
807*cf5a6c84SAndroid Build Coastguard Worker     for (;TT.cursor < TT.filesize;) {
808*cf5a6c84SAndroid Build Coastguard Worker       if ((len = text_codepoint(buf, TT.cursor)) < 1) {
809*cf5a6c84SAndroid Build Coastguard Worker         TT.cursor++; //we are not in valid data try jump over
810*cf5a6c84SAndroid Build Coastguard Worker         continue;
811*cf5a6c84SAndroid Build Coastguard Worker       }
812*cf5a6c84SAndroid Build Coastguard Worker 
813*cf5a6c84SAndroid Build Coastguard Worker       if (utf8_lnw(&width, buf, len) && width) break;
814*cf5a6c84SAndroid Build Coastguard Worker       else TT.cursor += len;
815*cf5a6c84SAndroid Build Coastguard Worker     }
816*cf5a6c84SAndroid Build Coastguard Worker   }
817*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
818*cf5a6c84SAndroid Build Coastguard Worker   return 1;
819*cf5a6c84SAndroid Build Coastguard Worker }
820*cf5a6c84SAndroid Build Coastguard Worker 
821*cf5a6c84SAndroid Build Coastguard Worker //TODO column shift
cur_up(int count0,int count1,char * unused)822*cf5a6c84SAndroid Build Coastguard Worker static int cur_up(int count0, int count1, char *unused)
823*cf5a6c84SAndroid Build Coastguard Worker {
824*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
825*cf5a6c84SAndroid Build Coastguard Worker 
826*cf5a6c84SAndroid Build Coastguard Worker   for (;count--;) TT.cursor = text_psol(TT.cursor);
827*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x80000000;
828*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
829*cf5a6c84SAndroid Build Coastguard Worker   return 1;
830*cf5a6c84SAndroid Build Coastguard Worker }
831*cf5a6c84SAndroid Build Coastguard Worker 
832*cf5a6c84SAndroid Build Coastguard Worker //TODO column shift
cur_down(int count0,int count1,char * unused)833*cf5a6c84SAndroid Build Coastguard Worker static int cur_down(int count0, int count1, char *unused)
834*cf5a6c84SAndroid Build Coastguard Worker {
835*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
836*cf5a6c84SAndroid Build Coastguard Worker 
837*cf5a6c84SAndroid Build Coastguard Worker   for (;count--;) TT.cursor = text_nsol(TT.cursor);
838*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
839*cf5a6c84SAndroid Build Coastguard Worker   return 1;
840*cf5a6c84SAndroid Build Coastguard Worker }
841*cf5a6c84SAndroid Build Coastguard Worker 
vi_H(int count0,int count1,char * unused)842*cf5a6c84SAndroid Build Coastguard Worker static int vi_H(int count0, int count1, char *unused)
843*cf5a6c84SAndroid Build Coastguard Worker {
844*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_sol(TT.screen);
845*cf5a6c84SAndroid Build Coastguard Worker   return 1;
846*cf5a6c84SAndroid Build Coastguard Worker }
847*cf5a6c84SAndroid Build Coastguard Worker 
vi_L(int count0,int count1,char * unused)848*cf5a6c84SAndroid Build Coastguard Worker static int vi_L(int count0, int count1, char *unused)
849*cf5a6c84SAndroid Build Coastguard Worker {
850*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_sol(TT.screen);
851*cf5a6c84SAndroid Build Coastguard Worker   cur_down(TT.screen_height-1, 1, 0);
852*cf5a6c84SAndroid Build Coastguard Worker   return 1;
853*cf5a6c84SAndroid Build Coastguard Worker }
854*cf5a6c84SAndroid Build Coastguard Worker 
vi_M(int count0,int count1,char * unused)855*cf5a6c84SAndroid Build Coastguard Worker static int vi_M(int count0, int count1, char *unused)
856*cf5a6c84SAndroid Build Coastguard Worker {
857*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_sol(TT.screen);
858*cf5a6c84SAndroid Build Coastguard Worker   cur_down(TT.screen_height/2, 1, 0);
859*cf5a6c84SAndroid Build Coastguard Worker   return 1;
860*cf5a6c84SAndroid Build Coastguard Worker }
861*cf5a6c84SAndroid Build Coastguard Worker 
search_str(char * s,int direction)862*cf5a6c84SAndroid Build Coastguard Worker static int search_str(char *s, int direction)
863*cf5a6c84SAndroid Build Coastguard Worker {
864*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = text_strstr(TT.cursor+1, s, direction);
865*cf5a6c84SAndroid Build Coastguard Worker 
866*cf5a6c84SAndroid Build Coastguard Worker   if (TT.last_search != s) {
867*cf5a6c84SAndroid Build Coastguard Worker     free(TT.last_search);
868*cf5a6c84SAndroid Build Coastguard Worker     TT.last_search = xstrdup(s);
869*cf5a6c84SAndroid Build Coastguard Worker   }
870*cf5a6c84SAndroid Build Coastguard Worker 
871*cf5a6c84SAndroid Build Coastguard Worker   if (pos != SIZE_MAX) TT.cursor = pos;
872*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
873*cf5a6c84SAndroid Build Coastguard Worker   return 0;
874*cf5a6c84SAndroid Build Coastguard Worker }
875*cf5a6c84SAndroid Build Coastguard Worker 
vi_yy(char reg,int count0,int count1)876*cf5a6c84SAndroid Build Coastguard Worker static int vi_yy(char reg, int count0, int count1)
877*cf5a6c84SAndroid Build Coastguard Worker {
878*cf5a6c84SAndroid Build Coastguard Worker   size_t history = TT.cursor;
879*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = text_sol(TT.cursor); //go left to first char on line
880*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 4;
881*cf5a6c84SAndroid Build Coastguard Worker 
882*cf5a6c84SAndroid Build Coastguard Worker   for (;count0; count0--) TT.cursor = text_nsol(TT.cursor);
883*cf5a6c84SAndroid Build Coastguard Worker 
884*cf5a6c84SAndroid Build Coastguard Worker   vi_yank(reg, pos, 0);
885*cf5a6c84SAndroid Build Coastguard Worker 
886*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = history;
887*cf5a6c84SAndroid Build Coastguard Worker   return 1;
888*cf5a6c84SAndroid Build Coastguard Worker }
889*cf5a6c84SAndroid Build Coastguard Worker 
vi_dd(char reg,int count0,int count1)890*cf5a6c84SAndroid Build Coastguard Worker static int vi_dd(char reg, int count0, int count1)
891*cf5a6c84SAndroid Build Coastguard Worker {
892*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = text_sol(TT.cursor); //go left to first char on line
893*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x30000000;
894*cf5a6c84SAndroid Build Coastguard Worker 
895*cf5a6c84SAndroid Build Coastguard Worker   for (;count0; count0--) TT.cursor = text_nsol(TT.cursor);
896*cf5a6c84SAndroid Build Coastguard Worker 
897*cf5a6c84SAndroid Build Coastguard Worker   if (pos == TT.cursor && TT.filesize) pos--;
898*cf5a6c84SAndroid Build Coastguard Worker   vi_delete(reg, pos, 0);
899*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
900*cf5a6c84SAndroid Build Coastguard Worker   return 1;
901*cf5a6c84SAndroid Build Coastguard Worker }
902*cf5a6c84SAndroid Build Coastguard Worker 
vi_x(char reg,int count0,int count1)903*cf5a6c84SAndroid Build Coastguard Worker static int vi_x(char reg, int count0, int count1)
904*cf5a6c84SAndroid Build Coastguard Worker {
905*cf5a6c84SAndroid Build Coastguard Worker   size_t from = TT.cursor;
906*cf5a6c84SAndroid Build Coastguard Worker 
907*cf5a6c84SAndroid Build Coastguard Worker   if (text_byte(TT.cursor) == '\n') {
908*cf5a6c84SAndroid Build Coastguard Worker     cur_left(count0-1, 1, 0);
909*cf5a6c84SAndroid Build Coastguard Worker   }
910*cf5a6c84SAndroid Build Coastguard Worker   else {
911*cf5a6c84SAndroid Build Coastguard Worker     cur_right(count0-1, 1, 0);
912*cf5a6c84SAndroid Build Coastguard Worker     if (text_byte(TT.cursor) == '\n') TT.vi_mov_flag |= 2;
913*cf5a6c84SAndroid Build Coastguard Worker     else cur_right(1, 1, 0);
914*cf5a6c84SAndroid Build Coastguard Worker   }
915*cf5a6c84SAndroid Build Coastguard Worker 
916*cf5a6c84SAndroid Build Coastguard Worker   vi_delete(reg, from, 0);
917*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
918*cf5a6c84SAndroid Build Coastguard Worker   return 1;
919*cf5a6c84SAndroid Build Coastguard Worker }
920*cf5a6c84SAndroid Build Coastguard Worker 
backspace(char reg,int count0,int count1)921*cf5a6c84SAndroid Build Coastguard Worker static int backspace(char reg, int count0, int count1)
922*cf5a6c84SAndroid Build Coastguard Worker {
923*cf5a6c84SAndroid Build Coastguard Worker   size_t from = 0;
924*cf5a6c84SAndroid Build Coastguard Worker   size_t to = TT.cursor;
925*cf5a6c84SAndroid Build Coastguard Worker   cur_left(1, 1, 0);
926*cf5a6c84SAndroid Build Coastguard Worker   from = TT.cursor;
927*cf5a6c84SAndroid Build Coastguard Worker   if (from != to)
928*cf5a6c84SAndroid Build Coastguard Worker     vi_delete(reg, to, 0);
929*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
930*cf5a6c84SAndroid Build Coastguard Worker   return 1;
931*cf5a6c84SAndroid Build Coastguard Worker }
932*cf5a6c84SAndroid Build Coastguard Worker 
vi_movw(int count0,int count1,char * unused)933*cf5a6c84SAndroid Build Coastguard Worker static int vi_movw(int count0, int count1, char *unused)
934*cf5a6c84SAndroid Build Coastguard Worker {
935*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
936*cf5a6c84SAndroid Build Coastguard Worker   while (count--) {
937*cf5a6c84SAndroid Build Coastguard Worker     char c = text_byte(TT.cursor);
938*cf5a6c84SAndroid Build Coastguard Worker     do {
939*cf5a6c84SAndroid Build Coastguard Worker       if (TT.cursor > TT.filesize-1) break;
940*cf5a6c84SAndroid Build Coastguard Worker       //if at empty jump to non empty
941*cf5a6c84SAndroid Build Coastguard Worker       if (c == '\n') {
942*cf5a6c84SAndroid Build Coastguard Worker         if (++TT.cursor > TT.filesize-1) break;
943*cf5a6c84SAndroid Build Coastguard Worker         if ((c = text_byte(TT.cursor)) == '\n') break;
944*cf5a6c84SAndroid Build Coastguard Worker         continue;
945*cf5a6c84SAndroid Build Coastguard Worker       } else if (strchr(blank, c)) do {
946*cf5a6c84SAndroid Build Coastguard Worker         if (++TT.cursor > TT.filesize-1) break;
947*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
948*cf5a6c84SAndroid Build Coastguard Worker       } while (strchr(blank, c));
949*cf5a6c84SAndroid Build Coastguard Worker       //if at special jump to non special
950*cf5a6c84SAndroid Build Coastguard Worker       else if (strchr(specials, c)) do {
951*cf5a6c84SAndroid Build Coastguard Worker         if (++TT.cursor > TT.filesize-1) break;
952*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
953*cf5a6c84SAndroid Build Coastguard Worker       } while (strchr(specials, c));
954*cf5a6c84SAndroid Build Coastguard Worker       //else jump to empty or spesial
955*cf5a6c84SAndroid Build Coastguard Worker       else do {
956*cf5a6c84SAndroid Build Coastguard Worker         if (++TT.cursor > TT.filesize-1) break;
957*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
958*cf5a6c84SAndroid Build Coastguard Worker       } while (c && !strchr(blank, c) && !strchr(specials, c));
959*cf5a6c84SAndroid Build Coastguard Worker 
960*cf5a6c84SAndroid Build Coastguard Worker     } while (strchr(blank, c) && c != '\n'); //never stop at empty
961*cf5a6c84SAndroid Build Coastguard Worker   }
962*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
963*cf5a6c84SAndroid Build Coastguard Worker   return 1;
964*cf5a6c84SAndroid Build Coastguard Worker }
965*cf5a6c84SAndroid Build Coastguard Worker 
vi_movb(int count0,int count1,char * unused)966*cf5a6c84SAndroid Build Coastguard Worker static int vi_movb(int count0, int count1, char *unused)
967*cf5a6c84SAndroid Build Coastguard Worker {
968*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
969*cf5a6c84SAndroid Build Coastguard Worker   int type = 0;
970*cf5a6c84SAndroid Build Coastguard Worker   char c;
971*cf5a6c84SAndroid Build Coastguard Worker   while (count--) {
972*cf5a6c84SAndroid Build Coastguard Worker     c = text_byte(TT.cursor);
973*cf5a6c84SAndroid Build Coastguard Worker     do {
974*cf5a6c84SAndroid Build Coastguard Worker       if (!TT.cursor) break;
975*cf5a6c84SAndroid Build Coastguard Worker       //if at empty jump to non empty
976*cf5a6c84SAndroid Build Coastguard Worker       if (strchr(blank, c)) do {
977*cf5a6c84SAndroid Build Coastguard Worker         if (!--TT.cursor) break;
978*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
979*cf5a6c84SAndroid Build Coastguard Worker       } while (strchr(blank, c));
980*cf5a6c84SAndroid Build Coastguard Worker       //if at special jump to non special
981*cf5a6c84SAndroid Build Coastguard Worker       else if (strchr(specials, c)) do {
982*cf5a6c84SAndroid Build Coastguard Worker         if (!--TT.cursor) break;
983*cf5a6c84SAndroid Build Coastguard Worker         type = 0;
984*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
985*cf5a6c84SAndroid Build Coastguard Worker       } while (strchr(specials, c));
986*cf5a6c84SAndroid Build Coastguard Worker       //else jump to empty or spesial
987*cf5a6c84SAndroid Build Coastguard Worker       else do {
988*cf5a6c84SAndroid Build Coastguard Worker         if (!--TT.cursor) break;
989*cf5a6c84SAndroid Build Coastguard Worker         type = 1;
990*cf5a6c84SAndroid Build Coastguard Worker         c = text_byte(TT.cursor);
991*cf5a6c84SAndroid Build Coastguard Worker       } while (!strchr(blank, c) && !strchr(specials, c));
992*cf5a6c84SAndroid Build Coastguard Worker 
993*cf5a6c84SAndroid Build Coastguard Worker     } while (strchr(blank, c)); //never stop at empty
994*cf5a6c84SAndroid Build Coastguard Worker   }
995*cf5a6c84SAndroid Build Coastguard Worker   //find first
996*cf5a6c84SAndroid Build Coastguard Worker   for (;TT.cursor; TT.cursor--) {
997*cf5a6c84SAndroid Build Coastguard Worker     c = text_byte(TT.cursor-1);
998*cf5a6c84SAndroid Build Coastguard Worker     if (type && !strchr(blank, c) && !strchr(specials, c)) break;
999*cf5a6c84SAndroid Build Coastguard Worker     else if (!type && !strchr(specials, c)) break;
1000*cf5a6c84SAndroid Build Coastguard Worker   }
1001*cf5a6c84SAndroid Build Coastguard Worker 
1002*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x80000000;
1003*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
1004*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1005*cf5a6c84SAndroid Build Coastguard Worker }
1006*cf5a6c84SAndroid Build Coastguard Worker 
vi_move(int count0,int count1,char * unused)1007*cf5a6c84SAndroid Build Coastguard Worker static int vi_move(int count0, int count1, char *unused)
1008*cf5a6c84SAndroid Build Coastguard Worker {
1009*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1;
1010*cf5a6c84SAndroid Build Coastguard Worker   int type = 0;
1011*cf5a6c84SAndroid Build Coastguard Worker   char c;
1012*cf5a6c84SAndroid Build Coastguard Worker 
1013*cf5a6c84SAndroid Build Coastguard Worker   if (count>1) vi_movw(count-1, 1, unused);
1014*cf5a6c84SAndroid Build Coastguard Worker 
1015*cf5a6c84SAndroid Build Coastguard Worker   c = text_byte(TT.cursor);
1016*cf5a6c84SAndroid Build Coastguard Worker   if (strchr(specials, c)) type = 1;
1017*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor++;
1018*cf5a6c84SAndroid Build Coastguard Worker   for (;TT.cursor < TT.filesize-1; TT.cursor++) {
1019*cf5a6c84SAndroid Build Coastguard Worker     c = text_byte(TT.cursor+1);
1020*cf5a6c84SAndroid Build Coastguard Worker     if (!type && (strchr(blank, c) || strchr(specials, c))) break;
1021*cf5a6c84SAndroid Build Coastguard Worker     else if (type && !strchr(specials, c)) break;
1022*cf5a6c84SAndroid Build Coastguard Worker   }
1023*cf5a6c84SAndroid Build Coastguard Worker 
1024*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 2;
1025*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
1026*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1027*cf5a6c84SAndroid Build Coastguard Worker }
1028*cf5a6c84SAndroid Build Coastguard Worker 
1029*cf5a6c84SAndroid Build Coastguard Worker 
i_insert(char * str,int len)1030*cf5a6c84SAndroid Build Coastguard Worker static void i_insert(char *str, int len)
1031*cf5a6c84SAndroid Build Coastguard Worker {
1032*cf5a6c84SAndroid Build Coastguard Worker   if (!str || !len) return;
1033*cf5a6c84SAndroid Build Coastguard Worker 
1034*cf5a6c84SAndroid Build Coastguard Worker   insert_str(xstrdup(str), TT.cursor, len, len, HEAP);
1035*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor += len;
1036*cf5a6c84SAndroid Build Coastguard Worker   TT.filesize = text_filesize();
1037*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x30000000;
1038*cf5a6c84SAndroid Build Coastguard Worker }
1039*cf5a6c84SAndroid Build Coastguard Worker 
vi_zero(int count0,int count1,char * unused)1040*cf5a6c84SAndroid Build Coastguard Worker static int vi_zero(int count0, int count1, char *unused)
1041*cf5a6c84SAndroid Build Coastguard Worker {
1042*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_sol(TT.cursor);
1043*cf5a6c84SAndroid Build Coastguard Worker   TT.cur_col = 0;
1044*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x80000000;
1045*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1046*cf5a6c84SAndroid Build Coastguard Worker }
1047*cf5a6c84SAndroid Build Coastguard Worker 
vi_dollar(int count0,int count1,char * unused)1048*cf5a6c84SAndroid Build Coastguard Worker static int vi_dollar(int count0, int count1, char *unused)
1049*cf5a6c84SAndroid Build Coastguard Worker {
1050*cf5a6c84SAndroid Build Coastguard Worker   size_t new = text_strchr(TT.cursor, '\n');
1051*cf5a6c84SAndroid Build Coastguard Worker 
1052*cf5a6c84SAndroid Build Coastguard Worker   if (new != TT.cursor) {
1053*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor = new - 1;
1054*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_mov_flag |= 2;
1055*cf5a6c84SAndroid Build Coastguard Worker     check_cursor_bounds();
1056*cf5a6c84SAndroid Build Coastguard Worker   }
1057*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1058*cf5a6c84SAndroid Build Coastguard Worker }
1059*cf5a6c84SAndroid Build Coastguard Worker 
vi_eol()1060*cf5a6c84SAndroid Build Coastguard Worker static void vi_eol()
1061*cf5a6c84SAndroid Build Coastguard Worker {
1062*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_strchr(TT.cursor, '\n');
1063*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
1064*cf5a6c84SAndroid Build Coastguard Worker }
1065*cf5a6c84SAndroid Build Coastguard Worker 
ctrl_b()1066*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_b()
1067*cf5a6c84SAndroid Build Coastguard Worker {
1068*cf5a6c84SAndroid Build Coastguard Worker   int i;
1069*cf5a6c84SAndroid Build Coastguard Worker 
1070*cf5a6c84SAndroid Build Coastguard Worker   for (i=0; i<TT.screen_height-2; ++i) {
1071*cf5a6c84SAndroid Build Coastguard Worker     TT.screen = text_psol(TT.screen);
1072*cf5a6c84SAndroid Build Coastguard Worker     // TODO: retain x offset.
1073*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor = text_psol(TT.screen);
1074*cf5a6c84SAndroid Build Coastguard Worker   }
1075*cf5a6c84SAndroid Build Coastguard Worker }
1076*cf5a6c84SAndroid Build Coastguard Worker 
ctrl_d()1077*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_d()
1078*cf5a6c84SAndroid Build Coastguard Worker {
1079*cf5a6c84SAndroid Build Coastguard Worker   int i;
1080*cf5a6c84SAndroid Build Coastguard Worker 
1081*cf5a6c84SAndroid Build Coastguard Worker   for (i=0; i<(TT.screen_height-2)/2; ++i) TT.screen = text_nsol(TT.screen);
1082*cf5a6c84SAndroid Build Coastguard Worker   // TODO: real vi keeps the x position.
1083*cf5a6c84SAndroid Build Coastguard Worker   if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1084*cf5a6c84SAndroid Build Coastguard Worker }
1085*cf5a6c84SAndroid Build Coastguard Worker 
ctrl_f()1086*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_f()
1087*cf5a6c84SAndroid Build Coastguard Worker {
1088*cf5a6c84SAndroid Build Coastguard Worker   int i;
1089*cf5a6c84SAndroid Build Coastguard Worker 
1090*cf5a6c84SAndroid Build Coastguard Worker   for (i=0; i<TT.screen_height-2; ++i) TT.screen = text_nsol(TT.screen);
1091*cf5a6c84SAndroid Build Coastguard Worker   // TODO: real vi keeps the x position.
1092*cf5a6c84SAndroid Build Coastguard Worker   if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1093*cf5a6c84SAndroid Build Coastguard Worker }
1094*cf5a6c84SAndroid Build Coastguard Worker 
ctrl_e()1095*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_e()
1096*cf5a6c84SAndroid Build Coastguard Worker {
1097*cf5a6c84SAndroid Build Coastguard Worker   TT.screen = text_nsol(TT.screen);
1098*cf5a6c84SAndroid Build Coastguard Worker   // TODO: real vi keeps the x position.
1099*cf5a6c84SAndroid Build Coastguard Worker   if (TT.screen > TT.cursor) TT.cursor = TT.screen;
1100*cf5a6c84SAndroid Build Coastguard Worker }
1101*cf5a6c84SAndroid Build Coastguard Worker 
ctrl_y()1102*cf5a6c84SAndroid Build Coastguard Worker static void ctrl_y()
1103*cf5a6c84SAndroid Build Coastguard Worker {
1104*cf5a6c84SAndroid Build Coastguard Worker   TT.screen = text_psol(TT.screen);
1105*cf5a6c84SAndroid Build Coastguard Worker   // TODO: only if we're on the bottom line
1106*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_psol(TT.cursor);
1107*cf5a6c84SAndroid Build Coastguard Worker   // TODO: real vi keeps the x position.
1108*cf5a6c84SAndroid Build Coastguard Worker }
1109*cf5a6c84SAndroid Build Coastguard Worker 
1110*cf5a6c84SAndroid Build Coastguard Worker //TODO check register where to push from
vi_push(char reg,int count0,int count1)1111*cf5a6c84SAndroid Build Coastguard Worker static int vi_push(char reg, int count0, int count1)
1112*cf5a6c84SAndroid Build Coastguard Worker {
1113*cf5a6c84SAndroid Build Coastguard Worker   //if row changes during push original cursor position is kept
1114*cf5a6c84SAndroid Build Coastguard Worker   //vi inconsistancy
1115*cf5a6c84SAndroid Build Coastguard Worker   //if yank ends with \n push is linemode else push in place+1
1116*cf5a6c84SAndroid Build Coastguard Worker   size_t history = TT.cursor;
1117*cf5a6c84SAndroid Build Coastguard Worker   char *start = TT.yank.data, *eol = strchr(start, '\n');
1118*cf5a6c84SAndroid Build Coastguard Worker   if (strlen(start) == 0) return 1;
1119*cf5a6c84SAndroid Build Coastguard Worker 
1120*cf5a6c84SAndroid Build Coastguard Worker   if (start[strlen(start)-1] == '\n') {
1121*cf5a6c84SAndroid Build Coastguard Worker     if ((TT.cursor = text_strchr(TT.cursor, '\n')) == SIZE_MAX)
1122*cf5a6c84SAndroid Build Coastguard Worker       TT.cursor = TT.filesize;
1123*cf5a6c84SAndroid Build Coastguard Worker     else TT.cursor = text_nsol(TT.cursor);
1124*cf5a6c84SAndroid Build Coastguard Worker   } else cur_right(1, 1, 0);
1125*cf5a6c84SAndroid Build Coastguard Worker 
1126*cf5a6c84SAndroid Build Coastguard Worker   i_insert(start, strlen(start));
1127*cf5a6c84SAndroid Build Coastguard Worker   if (eol) {
1128*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_mov_flag |= 0x10000000;
1129*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor = history;
1130*cf5a6c84SAndroid Build Coastguard Worker   }
1131*cf5a6c84SAndroid Build Coastguard Worker 
1132*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1133*cf5a6c84SAndroid Build Coastguard Worker }
1134*cf5a6c84SAndroid Build Coastguard Worker 
vi_find_c(int count0,int count1,char * symbol)1135*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_c(int count0, int count1, char *symbol)
1136*cf5a6c84SAndroid Build Coastguard Worker {
1137*cf5a6c84SAndroid Build Coastguard Worker ////  int count = count0*count1;
1138*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = text_strchr(TT.cursor, *symbol);
1139*cf5a6c84SAndroid Build Coastguard Worker   if (pos != SIZE_MAX) TT.cursor = pos;
1140*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1141*cf5a6c84SAndroid Build Coastguard Worker }
1142*cf5a6c84SAndroid Build Coastguard Worker 
vi_find_cb(int count0,int count1,char * symbol)1143*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_cb(int count0, int count1, char *symbol)
1144*cf5a6c84SAndroid Build Coastguard Worker {
1145*cf5a6c84SAndroid Build Coastguard Worker   // do backward search
1146*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = text_strrchr(TT.cursor, *symbol);
1147*cf5a6c84SAndroid Build Coastguard Worker   if (pos != SIZE_MAX) TT.cursor = pos;
1148*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1149*cf5a6c84SAndroid Build Coastguard Worker }
1150*cf5a6c84SAndroid Build Coastguard Worker 
1151*cf5a6c84SAndroid Build Coastguard Worker //if count is not spesified should go to last line
vi_go(int count0,int count1,char * symbol)1152*cf5a6c84SAndroid Build Coastguard Worker static int vi_go(int count0, int count1, char *symbol)
1153*cf5a6c84SAndroid Build Coastguard Worker {
1154*cf5a6c84SAndroid Build Coastguard Worker   size_t prev_cursor = TT.cursor;
1155*cf5a6c84SAndroid Build Coastguard Worker   int count = count0*count1-1;
1156*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = 0;
1157*cf5a6c84SAndroid Build Coastguard Worker 
1158*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mov_flag&0x40000000 && (TT.cursor = TT.filesize) > 0)
1159*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor = text_sol(TT.cursor-1);
1160*cf5a6c84SAndroid Build Coastguard Worker   else if (count) {
1161*cf5a6c84SAndroid Build Coastguard Worker     size_t next = 0;
1162*cf5a6c84SAndroid Build Coastguard Worker     for ( ;count && (next = text_strchr(next+1, '\n')) != SIZE_MAX; count--)
1163*cf5a6c84SAndroid Build Coastguard Worker       TT.cursor = next;
1164*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor++;
1165*cf5a6c84SAndroid Build Coastguard Worker   }
1166*cf5a6c84SAndroid Build Coastguard Worker 
1167*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();  //adjusts cursor column
1168*cf5a6c84SAndroid Build Coastguard Worker   if (prev_cursor > TT.cursor) TT.vi_mov_flag |= 0x80000000;
1169*cf5a6c84SAndroid Build Coastguard Worker 
1170*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1171*cf5a6c84SAndroid Build Coastguard Worker }
1172*cf5a6c84SAndroid Build Coastguard Worker 
vi_o(char reg,int count0,int count1)1173*cf5a6c84SAndroid Build Coastguard Worker static int vi_o(char reg, int count0, int count1)
1174*cf5a6c84SAndroid Build Coastguard Worker {
1175*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_eol(TT.cursor);
1176*cf5a6c84SAndroid Build Coastguard Worker   insert_str(xstrdup("\n"), TT.cursor++, 1, 1, HEAP);
1177*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag |= 0x30000000;
1178*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mode = 2;
1179*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1180*cf5a6c84SAndroid Build Coastguard Worker }
1181*cf5a6c84SAndroid Build Coastguard Worker 
vi_O(char reg,int count0,int count1)1182*cf5a6c84SAndroid Build Coastguard Worker static int vi_O(char reg, int count0, int count1)
1183*cf5a6c84SAndroid Build Coastguard Worker {
1184*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_psol(TT.cursor);
1185*cf5a6c84SAndroid Build Coastguard Worker   return vi_o(reg, count0, count1);
1186*cf5a6c84SAndroid Build Coastguard Worker }
1187*cf5a6c84SAndroid Build Coastguard Worker 
vi_D(char reg,int count0,int count1)1188*cf5a6c84SAndroid Build Coastguard Worker static int vi_D(char reg, int count0, int count1)
1189*cf5a6c84SAndroid Build Coastguard Worker {
1190*cf5a6c84SAndroid Build Coastguard Worker   size_t pos = TT.cursor;
1191*cf5a6c84SAndroid Build Coastguard Worker   if (!count0) return 1;
1192*cf5a6c84SAndroid Build Coastguard Worker   vi_eol();
1193*cf5a6c84SAndroid Build Coastguard Worker   vi_delete(reg, pos, 0);
1194*cf5a6c84SAndroid Build Coastguard Worker   if (--count0) vi_dd(reg, count0, 1);
1195*cf5a6c84SAndroid Build Coastguard Worker 
1196*cf5a6c84SAndroid Build Coastguard Worker   check_cursor_bounds();
1197*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1198*cf5a6c84SAndroid Build Coastguard Worker }
1199*cf5a6c84SAndroid Build Coastguard Worker 
vi_I(char reg,int count0,int count1)1200*cf5a6c84SAndroid Build Coastguard Worker static int vi_I(char reg, int count0, int count1)
1201*cf5a6c84SAndroid Build Coastguard Worker {
1202*cf5a6c84SAndroid Build Coastguard Worker   TT.cursor = text_sol(TT.cursor);
1203*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mode = 2;
1204*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1205*cf5a6c84SAndroid Build Coastguard Worker }
1206*cf5a6c84SAndroid Build Coastguard Worker 
vi_join(char reg,int count0,int count1)1207*cf5a6c84SAndroid Build Coastguard Worker static int vi_join(char reg, int count0, int count1)
1208*cf5a6c84SAndroid Build Coastguard Worker {
1209*cf5a6c84SAndroid Build Coastguard Worker   size_t next;
1210*cf5a6c84SAndroid Build Coastguard Worker   while (count0--) {
1211*cf5a6c84SAndroid Build Coastguard Worker     //just strchr(/n) and cut_str(pos, 1);
1212*cf5a6c84SAndroid Build Coastguard Worker     if ((next = text_strchr(TT.cursor, '\n')) == SIZE_MAX) break;
1213*cf5a6c84SAndroid Build Coastguard Worker     TT.cursor = next+1;
1214*cf5a6c84SAndroid Build Coastguard Worker     vi_delete(reg, TT.cursor-1, 0);
1215*cf5a6c84SAndroid Build Coastguard Worker   }
1216*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1217*cf5a6c84SAndroid Build Coastguard Worker }
1218*cf5a6c84SAndroid Build Coastguard Worker 
vi_find_next(char reg,int count0,int count1)1219*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_next(char reg, int count0, int count1)
1220*cf5a6c84SAndroid Build Coastguard Worker {
1221*cf5a6c84SAndroid Build Coastguard Worker   if (TT.last_search) search_str(TT.last_search, 1);
1222*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1223*cf5a6c84SAndroid Build Coastguard Worker }
1224*cf5a6c84SAndroid Build Coastguard Worker 
vi_find_prev(char reg,int count0,int count1)1225*cf5a6c84SAndroid Build Coastguard Worker static int vi_find_prev(char reg, int count0, int count1)
1226*cf5a6c84SAndroid Build Coastguard Worker {
1227*cf5a6c84SAndroid Build Coastguard Worker   if (TT.last_search) search_str(TT.last_search, 0);
1228*cf5a6c84SAndroid Build Coastguard Worker   return 1;
1229*cf5a6c84SAndroid Build Coastguard Worker }
1230*cf5a6c84SAndroid Build Coastguard Worker 
1231*cf5a6c84SAndroid Build Coastguard Worker //NOTES
1232*cf5a6c84SAndroid Build Coastguard Worker //vi-mode cmd syntax is
1233*cf5a6c84SAndroid Build Coastguard Worker //("[REG])[COUNT0]CMD[COUNT1](MOV)
1234*cf5a6c84SAndroid Build Coastguard Worker //where:
1235*cf5a6c84SAndroid Build Coastguard Worker //-------------------------------------------------------------
1236*cf5a6c84SAndroid Build Coastguard Worker //"[REG] is optional buffer where deleted/yanked text goes REG can be
1237*cf5a6c84SAndroid Build Coastguard Worker //  atleast 0-9, a-z or default "
1238*cf5a6c84SAndroid Build Coastguard Worker //[COUNT] is optional multiplier for cmd execution if there is 2 COUNT
1239*cf5a6c84SAndroid Build Coastguard Worker //  operations they are multiplied together
1240*cf5a6c84SAndroid Build Coastguard Worker //CMD is operation to be executed
1241*cf5a6c84SAndroid Build Coastguard Worker //(MOV) is movement operation, some CMD does not require MOV and some
1242*cf5a6c84SAndroid Build Coastguard Worker //  have special cases such as dd, yy, also movements can work without
1243*cf5a6c84SAndroid Build Coastguard Worker //  CMD
1244*cf5a6c84SAndroid Build Coastguard Worker //ex commands can be even more complicated than this....
1245*cf5a6c84SAndroid Build Coastguard Worker 
1246*cf5a6c84SAndroid Build Coastguard Worker //special cases without MOV and such
1247*cf5a6c84SAndroid Build Coastguard Worker struct vi_special_param {
1248*cf5a6c84SAndroid Build Coastguard Worker   const char *cmd;
1249*cf5a6c84SAndroid Build Coastguard Worker   int (*vi_special)(char, int, int);//REG,COUNT0,COUNT1
1250*cf5a6c84SAndroid Build Coastguard Worker } vi_special[] = {
1251*cf5a6c84SAndroid Build Coastguard Worker   {"D", &vi_D},
1252*cf5a6c84SAndroid Build Coastguard Worker   {"I", &vi_I},
1253*cf5a6c84SAndroid Build Coastguard Worker   {"J", &vi_join},
1254*cf5a6c84SAndroid Build Coastguard Worker   {"O", &vi_O},
1255*cf5a6c84SAndroid Build Coastguard Worker   {"N", &vi_find_prev},
1256*cf5a6c84SAndroid Build Coastguard Worker   {"n", &vi_find_next},
1257*cf5a6c84SAndroid Build Coastguard Worker   {"o", &vi_o},
1258*cf5a6c84SAndroid Build Coastguard Worker   {"p", &vi_push},
1259*cf5a6c84SAndroid Build Coastguard Worker   {"x", &vi_x},
1260*cf5a6c84SAndroid Build Coastguard Worker   {"dd", &vi_dd},
1261*cf5a6c84SAndroid Build Coastguard Worker   {"yy", &vi_yy},
1262*cf5a6c84SAndroid Build Coastguard Worker };
1263*cf5a6c84SAndroid Build Coastguard Worker //there is around ~47 vi moves, some of them need extra params such as f and '
1264*cf5a6c84SAndroid Build Coastguard Worker struct vi_mov_param {
1265*cf5a6c84SAndroid Build Coastguard Worker   const char* mov;
1266*cf5a6c84SAndroid Build Coastguard Worker   unsigned flags;
1267*cf5a6c84SAndroid Build Coastguard Worker   int (*vi_mov)(int, int, char*);//COUNT0,COUNT1,params
1268*cf5a6c84SAndroid Build Coastguard Worker } vi_movs[] = {
1269*cf5a6c84SAndroid Build Coastguard Worker   {"0", 0, &vi_zero},
1270*cf5a6c84SAndroid Build Coastguard Worker   {"b", 0, &vi_movb},
1271*cf5a6c84SAndroid Build Coastguard Worker   {"e", 0, &vi_move},
1272*cf5a6c84SAndroid Build Coastguard Worker   {"G", 0, &vi_go},
1273*cf5a6c84SAndroid Build Coastguard Worker   {"H", 0, &vi_H},
1274*cf5a6c84SAndroid Build Coastguard Worker   {"h", 0, &cur_left},
1275*cf5a6c84SAndroid Build Coastguard Worker   {"j", 0, &cur_down},
1276*cf5a6c84SAndroid Build Coastguard Worker   {"k", 0, &cur_up},
1277*cf5a6c84SAndroid Build Coastguard Worker   {"L", 0, &vi_L},
1278*cf5a6c84SAndroid Build Coastguard Worker   {"l", 0, &cur_right},
1279*cf5a6c84SAndroid Build Coastguard Worker   {"M", 0, &vi_M},
1280*cf5a6c84SAndroid Build Coastguard Worker   {"w", 0, &vi_movw},
1281*cf5a6c84SAndroid Build Coastguard Worker   {"$", 0, &vi_dollar},
1282*cf5a6c84SAndroid Build Coastguard Worker   {"f", 1, &vi_find_c},
1283*cf5a6c84SAndroid Build Coastguard Worker   {"F", 1, &vi_find_cb},
1284*cf5a6c84SAndroid Build Coastguard Worker };
1285*cf5a6c84SAndroid Build Coastguard Worker // change and delete unfortunately behave different depending on move command,
1286*cf5a6c84SAndroid Build Coastguard Worker // such as ce cw are same, but dw and de are not...
1287*cf5a6c84SAndroid Build Coastguard Worker // also dw stops at w position and cw seem to stop at e pos+1...
1288*cf5a6c84SAndroid Build Coastguard Worker // so after movement we need to possibly set up some flags before executing
1289*cf5a6c84SAndroid Build Coastguard Worker // command, and command needs to adjust...
1290*cf5a6c84SAndroid Build Coastguard Worker struct vi_cmd_param {
1291*cf5a6c84SAndroid Build Coastguard Worker   const char* cmd;
1292*cf5a6c84SAndroid Build Coastguard Worker   unsigned flags;
1293*cf5a6c84SAndroid Build Coastguard Worker   int (*vi_cmd)(char, size_t, int);//REG,from,FLAGS
1294*cf5a6c84SAndroid Build Coastguard Worker } vi_cmds[] = {
1295*cf5a6c84SAndroid Build Coastguard Worker   {"c", 1, &vi_change},
1296*cf5a6c84SAndroid Build Coastguard Worker   {"d", 1, &vi_delete},
1297*cf5a6c84SAndroid Build Coastguard Worker   {"y", 1, &vi_yank},
1298*cf5a6c84SAndroid Build Coastguard Worker };
1299*cf5a6c84SAndroid Build Coastguard Worker 
run_vi_cmd(char * cmd)1300*cf5a6c84SAndroid Build Coastguard Worker static int run_vi_cmd(char *cmd)
1301*cf5a6c84SAndroid Build Coastguard Worker {
1302*cf5a6c84SAndroid Build Coastguard Worker   int i = 0, val = 0;
1303*cf5a6c84SAndroid Build Coastguard Worker   char *cmd_e;
1304*cf5a6c84SAndroid Build Coastguard Worker   int (*vi_cmd)(char, size_t, int) = 0, (*vi_mov)(int, int, char*) = 0;
1305*cf5a6c84SAndroid Build Coastguard Worker 
1306*cf5a6c84SAndroid Build Coastguard Worker   TT.count0 = 0, TT.count1 = 0, TT.vi_mov_flag = 0;
1307*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_reg = '"';
1308*cf5a6c84SAndroid Build Coastguard Worker 
1309*cf5a6c84SAndroid Build Coastguard Worker   if (*cmd == '"') {
1310*cf5a6c84SAndroid Build Coastguard Worker     cmd++;
1311*cf5a6c84SAndroid Build Coastguard Worker     TT.vi_reg = *cmd++; //TODO check validity
1312*cf5a6c84SAndroid Build Coastguard Worker   }
1313*cf5a6c84SAndroid Build Coastguard Worker   errno = 0;
1314*cf5a6c84SAndroid Build Coastguard Worker   val = strtol(cmd, &cmd_e, 10);
1315*cf5a6c84SAndroid Build Coastguard Worker   if (errno || val == 0) val = 1, TT.vi_mov_flag |= 0x40000000;
1316*cf5a6c84SAndroid Build Coastguard Worker   else cmd = cmd_e;
1317*cf5a6c84SAndroid Build Coastguard Worker   TT.count0 = val;
1318*cf5a6c84SAndroid Build Coastguard Worker 
1319*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i < ARRAY_LEN(vi_special); i++)
1320*cf5a6c84SAndroid Build Coastguard Worker     if (strstr(cmd, vi_special[i].cmd))
1321*cf5a6c84SAndroid Build Coastguard Worker       return vi_special[i].vi_special(TT.vi_reg, TT.count0, TT.count1);
1322*cf5a6c84SAndroid Build Coastguard Worker 
1323*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i < ARRAY_LEN(vi_cmds); i++) {
1324*cf5a6c84SAndroid Build Coastguard Worker     if (!strncmp(cmd, vi_cmds[i].cmd, strlen(vi_cmds[i].cmd))) {
1325*cf5a6c84SAndroid Build Coastguard Worker       vi_cmd = vi_cmds[i].vi_cmd;
1326*cf5a6c84SAndroid Build Coastguard Worker       cmd += strlen(vi_cmds[i].cmd);
1327*cf5a6c84SAndroid Build Coastguard Worker       break;
1328*cf5a6c84SAndroid Build Coastguard Worker     }
1329*cf5a6c84SAndroid Build Coastguard Worker   }
1330*cf5a6c84SAndroid Build Coastguard Worker   errno = 0;
1331*cf5a6c84SAndroid Build Coastguard Worker   val = strtol(cmd, &cmd_e, 10);
1332*cf5a6c84SAndroid Build Coastguard Worker   if (errno || val == 0) val = 1;
1333*cf5a6c84SAndroid Build Coastguard Worker   else cmd = cmd_e;
1334*cf5a6c84SAndroid Build Coastguard Worker   TT.count1 = val;
1335*cf5a6c84SAndroid Build Coastguard Worker 
1336*cf5a6c84SAndroid Build Coastguard Worker   for (i = 0; i < ARRAY_LEN(vi_movs); i++) {
1337*cf5a6c84SAndroid Build Coastguard Worker     if (!strncmp(cmd, vi_movs[i].mov, strlen(vi_movs[i].mov))) {
1338*cf5a6c84SAndroid Build Coastguard Worker       vi_mov = vi_movs[i].vi_mov;
1339*cf5a6c84SAndroid Build Coastguard Worker       TT.vi_mov_flag |= vi_movs[i].flags;
1340*cf5a6c84SAndroid Build Coastguard Worker       cmd++;
1341*cf5a6c84SAndroid Build Coastguard Worker       if (TT.vi_mov_flag&1 && !(*cmd)) return 0;
1342*cf5a6c84SAndroid Build Coastguard Worker       break;
1343*cf5a6c84SAndroid Build Coastguard Worker     }
1344*cf5a6c84SAndroid Build Coastguard Worker   }
1345*cf5a6c84SAndroid Build Coastguard Worker   if (vi_mov) {
1346*cf5a6c84SAndroid Build Coastguard Worker     int prev_cursor = TT.cursor;
1347*cf5a6c84SAndroid Build Coastguard Worker     if (vi_mov(TT.count0, TT.count1, cmd)) {
1348*cf5a6c84SAndroid Build Coastguard Worker       if (vi_cmd) return (vi_cmd(TT.vi_reg, prev_cursor, TT.vi_mov_flag));
1349*cf5a6c84SAndroid Build Coastguard Worker       else return 1;
1350*cf5a6c84SAndroid Build Coastguard Worker     } else return 0; //return some error
1351*cf5a6c84SAndroid Build Coastguard Worker   }
1352*cf5a6c84SAndroid Build Coastguard Worker   return 0;
1353*cf5a6c84SAndroid Build Coastguard Worker }
1354*cf5a6c84SAndroid Build Coastguard Worker 
1355*cf5a6c84SAndroid Build Coastguard Worker 
1356*cf5a6c84SAndroid Build Coastguard Worker static void draw_page();
1357*cf5a6c84SAndroid Build Coastguard Worker 
get_endline(void)1358*cf5a6c84SAndroid Build Coastguard Worker static int get_endline(void)
1359*cf5a6c84SAndroid Build Coastguard Worker {
1360*cf5a6c84SAndroid Build Coastguard Worker   int cln, rln;
1361*cf5a6c84SAndroid Build Coastguard Worker 
1362*cf5a6c84SAndroid Build Coastguard Worker   draw_page();
1363*cf5a6c84SAndroid Build Coastguard Worker   cln = TT.cur_row+1;
1364*cf5a6c84SAndroid Build Coastguard Worker   run_vi_cmd("G");
1365*cf5a6c84SAndroid Build Coastguard Worker   draw_page();
1366*cf5a6c84SAndroid Build Coastguard Worker   rln =  TT.cur_row+1;
1367*cf5a6c84SAndroid Build Coastguard Worker   run_vi_cmd(xmprintf("%dG", cln));
1368*cf5a6c84SAndroid Build Coastguard Worker 
1369*cf5a6c84SAndroid Build Coastguard Worker   return rln+1;
1370*cf5a6c84SAndroid Build Coastguard Worker }
1371*cf5a6c84SAndroid Build Coastguard Worker 
1372*cf5a6c84SAndroid Build Coastguard Worker // Return non-zero to exit.
run_ex_cmd(char * cmd)1373*cf5a6c84SAndroid Build Coastguard Worker static int run_ex_cmd(char *cmd)
1374*cf5a6c84SAndroid Build Coastguard Worker {
1375*cf5a6c84SAndroid Build Coastguard Worker   int startline = 1, ofst = 0, endline;
1376*cf5a6c84SAndroid Build Coastguard Worker 
1377*cf5a6c84SAndroid Build Coastguard Worker   if (*cmd == '/' || *cmd == '\?') search_str(cmd+1, *cmd == '/' ? 0 : 1);
1378*cf5a6c84SAndroid Build Coastguard Worker   else if (*cmd == ':') {
1379*cf5a6c84SAndroid Build Coastguard Worker     if (cmd[1] == 'q') {
1380*cf5a6c84SAndroid Build Coastguard Worker       if (cmd[2] != '!' && modified())
1381*cf5a6c84SAndroid Build Coastguard Worker         show_error("Unsaved changes (\"q!\" to ignore)");
1382*cf5a6c84SAndroid Build Coastguard Worker       else return 1;
1383*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strncmp(cmd+1, "w ", 2)) write_file(&cmd[3]);
1384*cf5a6c84SAndroid Build Coastguard Worker     else if (!strncmp(cmd+1, "wq", 2)) {
1385*cf5a6c84SAndroid Build Coastguard Worker       if (write_file(0)) return 1;
1386*cf5a6c84SAndroid Build Coastguard Worker       show_error("Unsaved changes (\"q!\" to ignore)");
1387*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strncmp(cmd+1, "w", 1)) write_file(0);
1388*cf5a6c84SAndroid Build Coastguard Worker 
1389*cf5a6c84SAndroid Build Coastguard Worker     else if (!strncmp(cmd+1, "set list", sizeof("set list"))) {
1390*cf5a6c84SAndroid Build Coastguard Worker       TT.list = 1;
1391*cf5a6c84SAndroid Build Coastguard Worker       TT.vi_mov_flag |= 0x30000000;
1392*cf5a6c84SAndroid Build Coastguard Worker     } else if (!strncmp(cmd+1, "set nolist", sizeof("set nolist"))) {
1393*cf5a6c84SAndroid Build Coastguard Worker       TT.list = 0;
1394*cf5a6c84SAndroid Build Coastguard Worker       TT.vi_mov_flag |= 0x30000000;
1395*cf5a6c84SAndroid Build Coastguard Worker     }
1396*cf5a6c84SAndroid Build Coastguard Worker 
1397*cf5a6c84SAndroid Build Coastguard Worker     else if (cmd[1] == 'd') {
1398*cf5a6c84SAndroid Build Coastguard Worker       run_vi_cmd("dd");
1399*cf5a6c84SAndroid Build Coastguard Worker       cur_up(1, 1, 0);
1400*cf5a6c84SAndroid Build Coastguard Worker     } else if (cmd[1] == 'j') run_vi_cmd("J");
1401*cf5a6c84SAndroid Build Coastguard Worker     else if (cmd[1] == 'g' || cmd[1] == 'v') {
1402*cf5a6c84SAndroid Build Coastguard Worker       char *rgx = xmalloc(strlen(cmd));
1403*cf5a6c84SAndroid Build Coastguard Worker       int el = get_endline(), ln = 0, vorg = (cmd[1] == 'v' ? REG_NOMATCH : 0);
1404*cf5a6c84SAndroid Build Coastguard Worker       if (sscanf(cmd+2, "/%[^/]/%[^\ng]", rgx, cmd+1) == 2) {
1405*cf5a6c84SAndroid Build Coastguard Worker         regex_t rgxc;
1406*cf5a6c84SAndroid Build Coastguard Worker         if (!regcomp(&rgxc, rgx, 0)) {
1407*cf5a6c84SAndroid Build Coastguard Worker           cmd[0] = ':';
1408*cf5a6c84SAndroid Build Coastguard Worker 
1409*cf5a6c84SAndroid Build Coastguard Worker           for (; ln < el; ln++) {
1410*cf5a6c84SAndroid Build Coastguard Worker             run_vi_cmd("yy");
1411*cf5a6c84SAndroid Build Coastguard Worker             if (regexec(&rgxc, TT.yank.data, 0, 0, 0) == vorg) run_ex_cmd(cmd);
1412*cf5a6c84SAndroid Build Coastguard Worker             cur_down(1, 1, 0);
1413*cf5a6c84SAndroid Build Coastguard Worker           }
1414*cf5a6c84SAndroid Build Coastguard Worker 
1415*cf5a6c84SAndroid Build Coastguard Worker           // Reset Frame
1416*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mov_flag |= 0x30000000;
1417*cf5a6c84SAndroid Build Coastguard Worker         }
1418*cf5a6c84SAndroid Build Coastguard Worker         regfree(&rgxc);
1419*cf5a6c84SAndroid Build Coastguard Worker       }
1420*cf5a6c84SAndroid Build Coastguard Worker       free(rgx);
1421*cf5a6c84SAndroid Build Coastguard Worker     }
1422*cf5a6c84SAndroid Build Coastguard Worker 
1423*cf5a6c84SAndroid Build Coastguard Worker     // Line Ranges
1424*cf5a6c84SAndroid Build Coastguard Worker     else if (cmd[1] >= '0' && cmd[1] <= '9') {
1425*cf5a6c84SAndroid Build Coastguard Worker       if (strstr(cmd, ",")) {
1426*cf5a6c84SAndroid Build Coastguard Worker         sscanf(cmd, ":%d,%d%[^\n]", &startline, &endline, cmd+2);
1427*cf5a6c84SAndroid Build Coastguard Worker         ofst = 1;
1428*cf5a6c84SAndroid Build Coastguard Worker       } else run_vi_cmd(xmprintf("%dG", atoi(cmd+1)));
1429*cf5a6c84SAndroid Build Coastguard Worker     } else if (cmd[1] == '$') run_vi_cmd("G");
1430*cf5a6c84SAndroid Build Coastguard Worker     else if (cmd[1] == '%') {
1431*cf5a6c84SAndroid Build Coastguard Worker       endline = get_endline();
1432*cf5a6c84SAndroid Build Coastguard Worker       ofst = 1;
1433*cf5a6c84SAndroid Build Coastguard Worker     } else show_error("unknown command '%s'",cmd+1);
1434*cf5a6c84SAndroid Build Coastguard Worker 
1435*cf5a6c84SAndroid Build Coastguard Worker     if (ofst) {
1436*cf5a6c84SAndroid Build Coastguard Worker       int cline = TT.cur_row+1;
1437*cf5a6c84SAndroid Build Coastguard Worker 
1438*cf5a6c84SAndroid Build Coastguard Worker       cmd[ofst] = ':';
1439*cf5a6c84SAndroid Build Coastguard Worker       for (; startline <= endline; startline++) {
1440*cf5a6c84SAndroid Build Coastguard Worker         run_ex_cmd(cmd+ofst);
1441*cf5a6c84SAndroid Build Coastguard Worker         cur_down(1, 1, 0);
1442*cf5a6c84SAndroid Build Coastguard Worker       }
1443*cf5a6c84SAndroid Build Coastguard Worker       run_vi_cmd(xmprintf("%dG", cline));
1444*cf5a6c84SAndroid Build Coastguard Worker       // Screen Reset
1445*cf5a6c84SAndroid Build Coastguard Worker       TT.vi_mov_flag |= 0x30000000;
1446*cf5a6c84SAndroid Build Coastguard Worker     }
1447*cf5a6c84SAndroid Build Coastguard Worker   }
1448*cf5a6c84SAndroid Build Coastguard Worker   return 0;
1449*cf5a6c84SAndroid Build Coastguard Worker }
1450*cf5a6c84SAndroid Build Coastguard Worker 
vi_crunch(FILE * out,int cols,int wc)1451*cf5a6c84SAndroid Build Coastguard Worker static int vi_crunch(FILE *out, int cols, int wc)
1452*cf5a6c84SAndroid Build Coastguard Worker {
1453*cf5a6c84SAndroid Build Coastguard Worker   int ret = 0;
1454*cf5a6c84SAndroid Build Coastguard Worker   if (wc < 32 && TT.list) {
1455*cf5a6c84SAndroid Build Coastguard Worker     xputsn("\e[1m");
1456*cf5a6c84SAndroid Build Coastguard Worker     ret = crunch_escape(out,cols,wc);
1457*cf5a6c84SAndroid Build Coastguard Worker     xputsn("\e[m");
1458*cf5a6c84SAndroid Build Coastguard Worker   } else if (wc == '\t') {
1459*cf5a6c84SAndroid Build Coastguard Worker     if (out) {
1460*cf5a6c84SAndroid Build Coastguard Worker       int i = TT.tabstop;
1461*cf5a6c84SAndroid Build Coastguard Worker       for (;i--;) fputs(" ", out);
1462*cf5a6c84SAndroid Build Coastguard Worker     }
1463*cf5a6c84SAndroid Build Coastguard Worker     ret = TT.tabstop;
1464*cf5a6c84SAndroid Build Coastguard Worker   } else if (wc == '\n') return 0;
1465*cf5a6c84SAndroid Build Coastguard Worker   return ret;
1466*cf5a6c84SAndroid Build Coastguard Worker }
1467*cf5a6c84SAndroid Build Coastguard Worker 
1468*cf5a6c84SAndroid Build Coastguard Worker //crunch_str with n bytes restriction for printing substrings or
1469*cf5a6c84SAndroid Build Coastguard Worker //non null terminated strings
crunch_nstr(char ** str,int width,int n,FILE * out,char * escmore,int (* escout)(FILE * out,int cols,int wc))1470*cf5a6c84SAndroid Build Coastguard Worker static int crunch_nstr(char **str, int width, int n, FILE *out, char *escmore,
1471*cf5a6c84SAndroid Build Coastguard Worker   int (*escout)(FILE *out, int cols, int wc))
1472*cf5a6c84SAndroid Build Coastguard Worker {
1473*cf5a6c84SAndroid Build Coastguard Worker   int columns = 0, col, bytes;
1474*cf5a6c84SAndroid Build Coastguard Worker   char *start, *end;
1475*cf5a6c84SAndroid Build Coastguard Worker   unsigned wc;
1476*cf5a6c84SAndroid Build Coastguard Worker 
1477*cf5a6c84SAndroid Build Coastguard Worker   for (end = start = *str; *end && n>0; columns += col, end += bytes, n -= bytes) {
1478*cf5a6c84SAndroid Build Coastguard Worker     if ((bytes = utf8towc(&wc, end, 4))>0 && (col = wcwidth(wc))>=0) {
1479*cf5a6c84SAndroid Build Coastguard Worker       if (!escmore || wc>255 || !strchr(escmore, wc)) {
1480*cf5a6c84SAndroid Build Coastguard Worker         if (width-columns<col) break;
1481*cf5a6c84SAndroid Build Coastguard Worker         if (out) fwrite(end, bytes, 1, out);
1482*cf5a6c84SAndroid Build Coastguard Worker 
1483*cf5a6c84SAndroid Build Coastguard Worker         continue;
1484*cf5a6c84SAndroid Build Coastguard Worker       }
1485*cf5a6c84SAndroid Build Coastguard Worker     }
1486*cf5a6c84SAndroid Build Coastguard Worker 
1487*cf5a6c84SAndroid Build Coastguard Worker     if (bytes<1) {
1488*cf5a6c84SAndroid Build Coastguard Worker       bytes = 1;
1489*cf5a6c84SAndroid Build Coastguard Worker       wc = *end;
1490*cf5a6c84SAndroid Build Coastguard Worker     }
1491*cf5a6c84SAndroid Build Coastguard Worker     col = width-columns;
1492*cf5a6c84SAndroid Build Coastguard Worker     if (col<1) break;
1493*cf5a6c84SAndroid Build Coastguard Worker     if (escout) {
1494*cf5a6c84SAndroid Build Coastguard Worker       if ((col = escout(out, col, wc))<0) break;
1495*cf5a6c84SAndroid Build Coastguard Worker     } else if (out) fwrite(end, 1, bytes, out);
1496*cf5a6c84SAndroid Build Coastguard Worker   }
1497*cf5a6c84SAndroid Build Coastguard Worker   *str = end;
1498*cf5a6c84SAndroid Build Coastguard Worker 
1499*cf5a6c84SAndroid Build Coastguard Worker   return columns;
1500*cf5a6c84SAndroid Build Coastguard Worker }
1501*cf5a6c84SAndroid Build Coastguard Worker 
draw_page()1502*cf5a6c84SAndroid Build Coastguard Worker static void draw_page()
1503*cf5a6c84SAndroid Build Coastguard Worker {
1504*cf5a6c84SAndroid Build Coastguard Worker   unsigned y = 0;
1505*cf5a6c84SAndroid Build Coastguard Worker   int x = 0, bytes = 0;
1506*cf5a6c84SAndroid Build Coastguard Worker   char *line = 0, *end = 0;
1507*cf5a6c84SAndroid Build Coastguard Worker   //screen coordinates for cursor
1508*cf5a6c84SAndroid Build Coastguard Worker   int cy_scr = 0, cx_scr = 0;
1509*cf5a6c84SAndroid Build Coastguard Worker   //variables used only for cursor handling
1510*cf5a6c84SAndroid Build Coastguard Worker   int aw = 0, iw = 0, clip = 0, margin = 8, scroll = 0, redraw = 0, SSOL, SOL;
1511*cf5a6c84SAndroid Build Coastguard Worker 
1512*cf5a6c84SAndroid Build Coastguard Worker   adjust_screen_buffer();
1513*cf5a6c84SAndroid Build Coastguard Worker   //redraw = 3; //force full redraw
1514*cf5a6c84SAndroid Build Coastguard Worker   redraw = (TT.vi_mov_flag & 0x30000000)>>28;
1515*cf5a6c84SAndroid Build Coastguard Worker 
1516*cf5a6c84SAndroid Build Coastguard Worker   scroll = TT.drawn_row-TT.scr_row;
1517*cf5a6c84SAndroid Build Coastguard Worker   if (TT.drawn_row<0 || TT.cur_row<0 || TT.scr_row<0) redraw = 3;
1518*cf5a6c84SAndroid Build Coastguard Worker   else if (abs(scroll)>TT.screen_height/2) redraw = 3;
1519*cf5a6c84SAndroid Build Coastguard Worker 
1520*cf5a6c84SAndroid Build Coastguard Worker   xputsn("\e[H"); // jump to top left
1521*cf5a6c84SAndroid Build Coastguard Worker   if (redraw&2) xputsn("\e[2J\e[H");   //clear screen
1522*cf5a6c84SAndroid Build Coastguard Worker   else if (scroll>0) printf("\e[%dL", scroll);  //scroll up
1523*cf5a6c84SAndroid Build Coastguard Worker   else if (scroll<0) printf("\e[%dM", -scroll); //scroll down
1524*cf5a6c84SAndroid Build Coastguard Worker 
1525*cf5a6c84SAndroid Build Coastguard Worker   SOL = text_sol(TT.cursor);
1526*cf5a6c84SAndroid Build Coastguard Worker   bytes = text_getline(toybuf, SOL, ARRAY_LEN(toybuf));
1527*cf5a6c84SAndroid Build Coastguard Worker   line = toybuf;
1528*cf5a6c84SAndroid Build Coastguard Worker 
1529*cf5a6c84SAndroid Build Coastguard Worker   for (SSOL = TT.screen, y = 0; SSOL < SOL; y++) SSOL = text_nsol(SSOL);
1530*cf5a6c84SAndroid Build Coastguard Worker 
1531*cf5a6c84SAndroid Build Coastguard Worker   cy_scr = y;
1532*cf5a6c84SAndroid Build Coastguard Worker 
1533*cf5a6c84SAndroid Build Coastguard Worker   // draw cursor row
1534*cf5a6c84SAndroid Build Coastguard Worker   /////////////////////////////////////////////////////////////
1535*cf5a6c84SAndroid Build Coastguard Worker   // for long lines line starts to scroll when cursor hits margin
1536*cf5a6c84SAndroid Build Coastguard Worker   bytes = TT.cursor-SOL; // TT.cur_col;
1537*cf5a6c84SAndroid Build Coastguard Worker   end = line;
1538*cf5a6c84SAndroid Build Coastguard Worker 
1539*cf5a6c84SAndroid Build Coastguard Worker 
1540*cf5a6c84SAndroid Build Coastguard Worker   printf("\e[%u;0H\e[2K", y+1);
1541*cf5a6c84SAndroid Build Coastguard Worker   // find cursor position
1542*cf5a6c84SAndroid Build Coastguard Worker   aw = crunch_nstr(&end, INT_MAX, bytes, 0, "\t\n", vi_crunch);
1543*cf5a6c84SAndroid Build Coastguard Worker 
1544*cf5a6c84SAndroid Build Coastguard Worker   // if we need to render text that is not inserted to buffer yet
1545*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mode == 2 && TT.il->len) {
1546*cf5a6c84SAndroid Build Coastguard Worker     char* iend = TT.il->data; //input end
1547*cf5a6c84SAndroid Build Coastguard Worker     x = 0;
1548*cf5a6c84SAndroid Build Coastguard Worker     // find insert end position
1549*cf5a6c84SAndroid Build Coastguard Worker     iw = crunch_str(&iend, INT_MAX, 0, "\t\n", vi_crunch);
1550*cf5a6c84SAndroid Build Coastguard Worker     clip = (aw+iw) - TT.screen_width+margin;
1551*cf5a6c84SAndroid Build Coastguard Worker 
1552*cf5a6c84SAndroid Build Coastguard Worker     // if clipped area is bigger than text before insert
1553*cf5a6c84SAndroid Build Coastguard Worker     if (clip > aw) {
1554*cf5a6c84SAndroid Build Coastguard Worker       clip -= aw;
1555*cf5a6c84SAndroid Build Coastguard Worker       iend = TT.il->data;
1556*cf5a6c84SAndroid Build Coastguard Worker 
1557*cf5a6c84SAndroid Build Coastguard Worker       iw -= crunch_str(&iend, clip, 0, "\t\n", vi_crunch);
1558*cf5a6c84SAndroid Build Coastguard Worker       x = crunch_str(&iend, iw, stdout, "\t\n", vi_crunch);
1559*cf5a6c84SAndroid Build Coastguard Worker     } else {
1560*cf5a6c84SAndroid Build Coastguard Worker       iend = TT.il->data;
1561*cf5a6c84SAndroid Build Coastguard Worker       end = line;
1562*cf5a6c84SAndroid Build Coastguard Worker 
1563*cf5a6c84SAndroid Build Coastguard Worker       //if clipped area is substring from cursor row start
1564*cf5a6c84SAndroid Build Coastguard Worker       aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch);
1565*cf5a6c84SAndroid Build Coastguard Worker       x = crunch_str(&end, aw,  stdout, "\t\n", vi_crunch);
1566*cf5a6c84SAndroid Build Coastguard Worker       x += crunch_str(&iend, iw, stdout, "\t\n", vi_crunch);
1567*cf5a6c84SAndroid Build Coastguard Worker     }
1568*cf5a6c84SAndroid Build Coastguard Worker   }
1569*cf5a6c84SAndroid Build Coastguard Worker   // when not inserting but still need to keep cursor inside screen
1570*cf5a6c84SAndroid Build Coastguard Worker   // margin area
1571*cf5a6c84SAndroid Build Coastguard Worker   else if ( aw+margin > TT.screen_width) {
1572*cf5a6c84SAndroid Build Coastguard Worker     clip = aw-TT.screen_width+margin;
1573*cf5a6c84SAndroid Build Coastguard Worker     end = line;
1574*cf5a6c84SAndroid Build Coastguard Worker     aw -= crunch_nstr(&end, clip, bytes, 0, "\t\n", vi_crunch);
1575*cf5a6c84SAndroid Build Coastguard Worker     x = crunch_str(&end, aw,  stdout, "\t\n", vi_crunch);
1576*cf5a6c84SAndroid Build Coastguard Worker   }
1577*cf5a6c84SAndroid Build Coastguard Worker   else {
1578*cf5a6c84SAndroid Build Coastguard Worker     end = line;
1579*cf5a6c84SAndroid Build Coastguard Worker     x = crunch_nstr(&end, aw, bytes, stdout, "\t\n", vi_crunch);
1580*cf5a6c84SAndroid Build Coastguard Worker   }
1581*cf5a6c84SAndroid Build Coastguard Worker   cx_scr = x;
1582*cf5a6c84SAndroid Build Coastguard Worker   cy_scr = y;
1583*cf5a6c84SAndroid Build Coastguard Worker   x += crunch_str(&end, TT.screen_width-x,  stdout, "\t\n", vi_crunch);
1584*cf5a6c84SAndroid Build Coastguard Worker 
1585*cf5a6c84SAndroid Build Coastguard Worker   // start drawing all other rows that needs update
1586*cf5a6c84SAndroid Build Coastguard Worker   ///////////////////////////////////////////////////////////////////
1587*cf5a6c84SAndroid Build Coastguard Worker   y = 0, SSOL = TT.screen, line = toybuf;
1588*cf5a6c84SAndroid Build Coastguard Worker   bytes = text_getline(toybuf, SSOL, ARRAY_LEN(toybuf));
1589*cf5a6c84SAndroid Build Coastguard Worker 
1590*cf5a6c84SAndroid Build Coastguard Worker   // if we moved around in long line might need to redraw everything
1591*cf5a6c84SAndroid Build Coastguard Worker   if (clip != TT.drawn_col) redraw = 3;
1592*cf5a6c84SAndroid Build Coastguard Worker 
1593*cf5a6c84SAndroid Build Coastguard Worker   for (; y < TT.screen_height; y++ ) {
1594*cf5a6c84SAndroid Build Coastguard Worker     int draw_line = 0;
1595*cf5a6c84SAndroid Build Coastguard Worker     if (SSOL == SOL) {
1596*cf5a6c84SAndroid Build Coastguard Worker       line = toybuf;
1597*cf5a6c84SAndroid Build Coastguard Worker       SSOL += bytes+1;
1598*cf5a6c84SAndroid Build Coastguard Worker       bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf));
1599*cf5a6c84SAndroid Build Coastguard Worker       continue;
1600*cf5a6c84SAndroid Build Coastguard Worker     } else if (redraw) draw_line++;
1601*cf5a6c84SAndroid Build Coastguard Worker     else if (scroll<0 && TT.screen_height-y-1<-scroll)
1602*cf5a6c84SAndroid Build Coastguard Worker       scroll++, draw_line++;
1603*cf5a6c84SAndroid Build Coastguard Worker     else if (scroll>0) scroll--, draw_line++;
1604*cf5a6c84SAndroid Build Coastguard Worker 
1605*cf5a6c84SAndroid Build Coastguard Worker     printf("\e[%u;0H", y+1);
1606*cf5a6c84SAndroid Build Coastguard Worker     if (draw_line) {
1607*cf5a6c84SAndroid Build Coastguard Worker       printf("\e[2K");
1608*cf5a6c84SAndroid Build Coastguard Worker       if (line && strlen(line)) {
1609*cf5a6c84SAndroid Build Coastguard Worker         aw = crunch_nstr(&line, clip, bytes, 0, "\t\n", vi_crunch);
1610*cf5a6c84SAndroid Build Coastguard Worker         crunch_str(&line, TT.screen_width-1, stdout, "\t\n", vi_crunch);
1611*cf5a6c84SAndroid Build Coastguard Worker         if ( *line ) printf("@");
1612*cf5a6c84SAndroid Build Coastguard Worker       } else printf("\e[2m~\e[m");
1613*cf5a6c84SAndroid Build Coastguard Worker     }
1614*cf5a6c84SAndroid Build Coastguard Worker     if (SSOL+bytes < TT.filesize)  {
1615*cf5a6c84SAndroid Build Coastguard Worker       line = toybuf;
1616*cf5a6c84SAndroid Build Coastguard Worker       SSOL += bytes+1;
1617*cf5a6c84SAndroid Build Coastguard Worker       bytes = text_getline(line, SSOL, ARRAY_LEN(toybuf));
1618*cf5a6c84SAndroid Build Coastguard Worker     } else line = 0;
1619*cf5a6c84SAndroid Build Coastguard Worker   }
1620*cf5a6c84SAndroid Build Coastguard Worker 
1621*cf5a6c84SAndroid Build Coastguard Worker   TT.drawn_row = TT.scr_row, TT.drawn_col = clip;
1622*cf5a6c84SAndroid Build Coastguard Worker 
1623*cf5a6c84SAndroid Build Coastguard Worker   // Finished updating visual area, show status line.
1624*cf5a6c84SAndroid Build Coastguard Worker   printf("\e[%u;0H\e[2K", TT.screen_height+1);
1625*cf5a6c84SAndroid Build Coastguard Worker   if (TT.vi_mode == 2) printf("\e[1m-- INSERT --\e[m");
1626*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.vi_mode) {
1627*cf5a6c84SAndroid Build Coastguard Worker     cx_scr = printf("%s", TT.il->data);
1628*cf5a6c84SAndroid Build Coastguard Worker     cy_scr = TT.screen_height;
1629*cf5a6c84SAndroid Build Coastguard Worker     *toybuf = 0;
1630*cf5a6c84SAndroid Build Coastguard Worker   } else {
1631*cf5a6c84SAndroid Build Coastguard Worker     // TODO: the row,col display doesn't show the cursor column
1632*cf5a6c84SAndroid Build Coastguard Worker     // TODO: real vi shows the percentage by lines, not bytes
1633*cf5a6c84SAndroid Build Coastguard Worker     sprintf(toybuf, "%zu/%zuC  %zu%%  %d,%d", TT.cursor, TT.filesize,
1634*cf5a6c84SAndroid Build Coastguard Worker       (100*TT.cursor)/(TT.filesize ? : 1), TT.cur_row+1, TT.cur_col+1);
1635*cf5a6c84SAndroid Build Coastguard Worker     if (TT.cur_col != cx_scr) sprintf(toybuf+strlen(toybuf),"-%d", cx_scr+1);
1636*cf5a6c84SAndroid Build Coastguard Worker   }
1637*cf5a6c84SAndroid Build Coastguard Worker   printf("\e[%u;%uH%s\e[%u;%uH", TT.screen_height+1,
1638*cf5a6c84SAndroid Build Coastguard Worker     (int) (1+TT.screen_width-strlen(toybuf)),
1639*cf5a6c84SAndroid Build Coastguard Worker     toybuf, cy_scr+1, cx_scr+1);
1640*cf5a6c84SAndroid Build Coastguard Worker   fflush(0);
1641*cf5a6c84SAndroid Build Coastguard Worker   xferror(stdout);
1642*cf5a6c84SAndroid Build Coastguard Worker }
1643*cf5a6c84SAndroid Build Coastguard Worker 
vi_main(void)1644*cf5a6c84SAndroid Build Coastguard Worker void vi_main(void)
1645*cf5a6c84SAndroid Build Coastguard Worker {
1646*cf5a6c84SAndroid Build Coastguard Worker   char keybuf[16] = {0}, vi_buf[16] = {0}, utf8_code[8] = {0};
1647*cf5a6c84SAndroid Build Coastguard Worker   int utf8_dec_p = 0, vi_buf_pos = 0;
1648*cf5a6c84SAndroid Build Coastguard Worker   FILE *script = TT.s ? xfopen(TT.s, "r") : 0;
1649*cf5a6c84SAndroid Build Coastguard Worker 
1650*cf5a6c84SAndroid Build Coastguard Worker   TT.il = xzalloc(sizeof(struct str_line));
1651*cf5a6c84SAndroid Build Coastguard Worker   TT.il->data = xzalloc(TT.il->alloc = 80);
1652*cf5a6c84SAndroid Build Coastguard Worker   TT.yank.data = xzalloc(TT.yank.alloc = 128);
1653*cf5a6c84SAndroid Build Coastguard Worker 
1654*cf5a6c84SAndroid Build Coastguard Worker   TT.filename = *toys.optargs;
1655*cf5a6c84SAndroid Build Coastguard Worker   linelist_load(0, 1);
1656*cf5a6c84SAndroid Build Coastguard Worker 
1657*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mov_flag = 0x20000000;
1658*cf5a6c84SAndroid Build Coastguard Worker   TT.vi_mode = 1, TT.tabstop = 8;
1659*cf5a6c84SAndroid Build Coastguard Worker 
1660*cf5a6c84SAndroid Build Coastguard Worker   TT.screen_width = 80, TT.screen_height = 24;
1661*cf5a6c84SAndroid Build Coastguard Worker   terminal_size(&TT.screen_width, &TT.screen_height);
1662*cf5a6c84SAndroid Build Coastguard Worker   TT.screen_height -= 1;
1663*cf5a6c84SAndroid Build Coastguard Worker 
1664*cf5a6c84SAndroid Build Coastguard Worker   xsignal(SIGWINCH, generic_signal);
1665*cf5a6c84SAndroid Build Coastguard Worker   set_terminal(0, 1, 0, 0);
1666*cf5a6c84SAndroid Build Coastguard Worker   //writes stdout into different xterm buffer so when we exit
1667*cf5a6c84SAndroid Build Coastguard Worker   //we dont get scroll log full of junk
1668*cf5a6c84SAndroid Build Coastguard Worker   xputsn("\e[?1049h");
1669*cf5a6c84SAndroid Build Coastguard Worker 
1670*cf5a6c84SAndroid Build Coastguard Worker   if (TT.c) {
1671*cf5a6c84SAndroid Build Coastguard Worker     FILE *cc = xfopen(TT.c, "r");
1672*cf5a6c84SAndroid Build Coastguard Worker     char *line;
1673*cf5a6c84SAndroid Build Coastguard Worker 
1674*cf5a6c84SAndroid Build Coastguard Worker     while ((line = xgetline(cc))) if (run_ex_cmd(TT.il->data)) goto cleanup_vi;
1675*cf5a6c84SAndroid Build Coastguard Worker     fclose(cc);
1676*cf5a6c84SAndroid Build Coastguard Worker   }
1677*cf5a6c84SAndroid Build Coastguard Worker 
1678*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
1679*cf5a6c84SAndroid Build Coastguard Worker     int key = 0;
1680*cf5a6c84SAndroid Build Coastguard Worker 
1681*cf5a6c84SAndroid Build Coastguard Worker     draw_page();
1682*cf5a6c84SAndroid Build Coastguard Worker     // TODO script should handle cursor keys
1683*cf5a6c84SAndroid Build Coastguard Worker     if (script && EOF==(key = fgetc(script))) {
1684*cf5a6c84SAndroid Build Coastguard Worker       fclose(script);
1685*cf5a6c84SAndroid Build Coastguard Worker       script = 0;
1686*cf5a6c84SAndroid Build Coastguard Worker     }
1687*cf5a6c84SAndroid Build Coastguard Worker     if (!script) key = scan_key(keybuf, -1);
1688*cf5a6c84SAndroid Build Coastguard Worker 
1689*cf5a6c84SAndroid Build Coastguard Worker     if (key == -1) goto cleanup_vi;
1690*cf5a6c84SAndroid Build Coastguard Worker     else if (key == -3) {
1691*cf5a6c84SAndroid Build Coastguard Worker       toys.signal = 0;
1692*cf5a6c84SAndroid Build Coastguard Worker       terminal_size(&TT.screen_width, &TT.screen_height);
1693*cf5a6c84SAndroid Build Coastguard Worker       TT.screen_height -= 1; //TODO this is hack fix visual alignment
1694*cf5a6c84SAndroid Build Coastguard Worker       continue;
1695*cf5a6c84SAndroid Build Coastguard Worker     }
1696*cf5a6c84SAndroid Build Coastguard Worker 
1697*cf5a6c84SAndroid Build Coastguard Worker     // TODO: support cursor keys in ex mode too.
1698*cf5a6c84SAndroid Build Coastguard Worker     if (TT.vi_mode && key>=256) {
1699*cf5a6c84SAndroid Build Coastguard Worker       key -= 256;
1700*cf5a6c84SAndroid Build Coastguard Worker       //if handling arrow keys insert what ever is in input buffer before moving
1701*cf5a6c84SAndroid Build Coastguard Worker       if (TT.il->len) {
1702*cf5a6c84SAndroid Build Coastguard Worker         i_insert(TT.il->data, TT.il->len);
1703*cf5a6c84SAndroid Build Coastguard Worker         TT.il->len = 0;
1704*cf5a6c84SAndroid Build Coastguard Worker         memset(TT.il->data, 0, TT.il->alloc);
1705*cf5a6c84SAndroid Build Coastguard Worker       }
1706*cf5a6c84SAndroid Build Coastguard Worker       if (key==KEY_UP) cur_up(1, 1, 0);
1707*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_DOWN) cur_down(1, 1, 0);
1708*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_LEFT) cur_left(1, 1, 0);
1709*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_RIGHT) cur_right(1, 1, 0);
1710*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_HOME) vi_zero(1, 1, 0);
1711*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_END) vi_dollar(1, 1, 0);
1712*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_PGDN) ctrl_f();
1713*cf5a6c84SAndroid Build Coastguard Worker       else if (key==KEY_PGUP) ctrl_b();
1714*cf5a6c84SAndroid Build Coastguard Worker 
1715*cf5a6c84SAndroid Build Coastguard Worker       continue;
1716*cf5a6c84SAndroid Build Coastguard Worker     }
1717*cf5a6c84SAndroid Build Coastguard Worker 
1718*cf5a6c84SAndroid Build Coastguard Worker     if (TT.vi_mode == 1) { //NORMAL
1719*cf5a6c84SAndroid Build Coastguard Worker       switch (key) {
1720*cf5a6c84SAndroid Build Coastguard Worker         case '/':
1721*cf5a6c84SAndroid Build Coastguard Worker         case '?':
1722*cf5a6c84SAndroid Build Coastguard Worker         case ':':
1723*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 0;
1724*cf5a6c84SAndroid Build Coastguard Worker           TT.il->data[0]=key;
1725*cf5a6c84SAndroid Build Coastguard Worker           TT.il->len++;
1726*cf5a6c84SAndroid Build Coastguard Worker           break;
1727*cf5a6c84SAndroid Build Coastguard Worker         case 'A':
1728*cf5a6c84SAndroid Build Coastguard Worker           vi_eol();
1729*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 2;
1730*cf5a6c84SAndroid Build Coastguard Worker           break;
1731*cf5a6c84SAndroid Build Coastguard Worker         case 'a':
1732*cf5a6c84SAndroid Build Coastguard Worker           cur_right(1, 1, 0);
1733*cf5a6c84SAndroid Build Coastguard Worker           // FALLTHROUGH
1734*cf5a6c84SAndroid Build Coastguard Worker         case 'i':
1735*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 2;
1736*cf5a6c84SAndroid Build Coastguard Worker           break;
1737*cf5a6c84SAndroid Build Coastguard Worker         case CTL('D'):
1738*cf5a6c84SAndroid Build Coastguard Worker           ctrl_d();
1739*cf5a6c84SAndroid Build Coastguard Worker           break;
1740*cf5a6c84SAndroid Build Coastguard Worker         case CTL('B'):
1741*cf5a6c84SAndroid Build Coastguard Worker           ctrl_b();
1742*cf5a6c84SAndroid Build Coastguard Worker           break;
1743*cf5a6c84SAndroid Build Coastguard Worker         case CTL('E'):
1744*cf5a6c84SAndroid Build Coastguard Worker           ctrl_e();
1745*cf5a6c84SAndroid Build Coastguard Worker           break;
1746*cf5a6c84SAndroid Build Coastguard Worker         case CTL('F'):
1747*cf5a6c84SAndroid Build Coastguard Worker           ctrl_f();
1748*cf5a6c84SAndroid Build Coastguard Worker           break;
1749*cf5a6c84SAndroid Build Coastguard Worker         case CTL('Y'):
1750*cf5a6c84SAndroid Build Coastguard Worker           ctrl_y();
1751*cf5a6c84SAndroid Build Coastguard Worker           break;
1752*cf5a6c84SAndroid Build Coastguard Worker         case '\e':
1753*cf5a6c84SAndroid Build Coastguard Worker           vi_buf[0] = 0;
1754*cf5a6c84SAndroid Build Coastguard Worker           vi_buf_pos = 0;
1755*cf5a6c84SAndroid Build Coastguard Worker           break;
1756*cf5a6c84SAndroid Build Coastguard Worker         case 0x7F: //FALLTHROUGH
1757*cf5a6c84SAndroid Build Coastguard Worker         case '\b':
1758*cf5a6c84SAndroid Build Coastguard Worker           backspace(TT.vi_reg, 1, 1);
1759*cf5a6c84SAndroid Build Coastguard Worker           break;
1760*cf5a6c84SAndroid Build Coastguard Worker         default:
1761*cf5a6c84SAndroid Build Coastguard Worker           if (key > ' ' && key < '{') {
1762*cf5a6c84SAndroid Build Coastguard Worker             vi_buf[vi_buf_pos] = key;//TODO handle input better
1763*cf5a6c84SAndroid Build Coastguard Worker             vi_buf_pos++;
1764*cf5a6c84SAndroid Build Coastguard Worker             if (run_vi_cmd(vi_buf)) {
1765*cf5a6c84SAndroid Build Coastguard Worker               memset(vi_buf, 0, 16);
1766*cf5a6c84SAndroid Build Coastguard Worker               vi_buf_pos = 0;
1767*cf5a6c84SAndroid Build Coastguard Worker             }
1768*cf5a6c84SAndroid Build Coastguard Worker             else if (vi_buf_pos == 15) {
1769*cf5a6c84SAndroid Build Coastguard Worker               vi_buf_pos = 0;
1770*cf5a6c84SAndroid Build Coastguard Worker               memset(vi_buf, 0, 16);
1771*cf5a6c84SAndroid Build Coastguard Worker             }
1772*cf5a6c84SAndroid Build Coastguard Worker 
1773*cf5a6c84SAndroid Build Coastguard Worker           }
1774*cf5a6c84SAndroid Build Coastguard Worker 
1775*cf5a6c84SAndroid Build Coastguard Worker           break;
1776*cf5a6c84SAndroid Build Coastguard Worker       }
1777*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.vi_mode == 0) { //EX MODE
1778*cf5a6c84SAndroid Build Coastguard Worker       switch (key) {
1779*cf5a6c84SAndroid Build Coastguard Worker         case '\x7f':
1780*cf5a6c84SAndroid Build Coastguard Worker         case '\b':
1781*cf5a6c84SAndroid Build Coastguard Worker           if (TT.il->len > 1) {
1782*cf5a6c84SAndroid Build Coastguard Worker             TT.il->data[--TT.il->len] = 0;
1783*cf5a6c84SAndroid Build Coastguard Worker             break;
1784*cf5a6c84SAndroid Build Coastguard Worker           }
1785*cf5a6c84SAndroid Build Coastguard Worker           // FALLTHROUGH
1786*cf5a6c84SAndroid Build Coastguard Worker         case '\e':
1787*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 1;
1788*cf5a6c84SAndroid Build Coastguard Worker           TT.il->len = 0;
1789*cf5a6c84SAndroid Build Coastguard Worker           memset(TT.il->data, 0, TT.il->alloc);
1790*cf5a6c84SAndroid Build Coastguard Worker           break;
1791*cf5a6c84SAndroid Build Coastguard Worker         case '\n':
1792*cf5a6c84SAndroid Build Coastguard Worker         case '\r':
1793*cf5a6c84SAndroid Build Coastguard Worker           if (run_ex_cmd(TT.il->data)) goto cleanup_vi;
1794*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 1;
1795*cf5a6c84SAndroid Build Coastguard Worker           TT.il->len = 0;
1796*cf5a6c84SAndroid Build Coastguard Worker           memset(TT.il->data, 0, TT.il->alloc);
1797*cf5a6c84SAndroid Build Coastguard Worker           break;
1798*cf5a6c84SAndroid Build Coastguard Worker         default: //add chars to ex command until ENTER
1799*cf5a6c84SAndroid Build Coastguard Worker           if (key >= ' ' && key < 0x7F) { //might be utf?
1800*cf5a6c84SAndroid Build Coastguard Worker             if (TT.il->len == TT.il->alloc) {
1801*cf5a6c84SAndroid Build Coastguard Worker               TT.il->data = realloc(TT.il->data, TT.il->alloc*2);
1802*cf5a6c84SAndroid Build Coastguard Worker               TT.il->alloc *= 2;
1803*cf5a6c84SAndroid Build Coastguard Worker             }
1804*cf5a6c84SAndroid Build Coastguard Worker             TT.il->data[TT.il->len] = key;
1805*cf5a6c84SAndroid Build Coastguard Worker             TT.il->len++;
1806*cf5a6c84SAndroid Build Coastguard Worker           }
1807*cf5a6c84SAndroid Build Coastguard Worker           break;
1808*cf5a6c84SAndroid Build Coastguard Worker       }
1809*cf5a6c84SAndroid Build Coastguard Worker     } else if (TT.vi_mode == 2) {//INSERT MODE
1810*cf5a6c84SAndroid Build Coastguard Worker       switch (key) {
1811*cf5a6c84SAndroid Build Coastguard Worker         case '\e':
1812*cf5a6c84SAndroid Build Coastguard Worker           i_insert(TT.il->data, TT.il->len);
1813*cf5a6c84SAndroid Build Coastguard Worker           cur_left(1, 1, 0);
1814*cf5a6c84SAndroid Build Coastguard Worker           TT.vi_mode = 1;
1815*cf5a6c84SAndroid Build Coastguard Worker           TT.il->len = 0;
1816*cf5a6c84SAndroid Build Coastguard Worker           memset(TT.il->data, 0, TT.il->alloc);
1817*cf5a6c84SAndroid Build Coastguard Worker           break;
1818*cf5a6c84SAndroid Build Coastguard Worker         case 0x7F:
1819*cf5a6c84SAndroid Build Coastguard Worker         case '\b':
1820*cf5a6c84SAndroid Build Coastguard Worker           if (TT.il->len) {
1821*cf5a6c84SAndroid Build Coastguard Worker             char *last = utf8_last(TT.il->data, TT.il->len);
1822*cf5a6c84SAndroid Build Coastguard Worker             int shrink = strlen(last);
1823*cf5a6c84SAndroid Build Coastguard Worker             memset(last, 0, shrink);
1824*cf5a6c84SAndroid Build Coastguard Worker             TT.il->len -= shrink;
1825*cf5a6c84SAndroid Build Coastguard Worker           } else backspace(TT.vi_reg, 1, 1);
1826*cf5a6c84SAndroid Build Coastguard Worker           break;
1827*cf5a6c84SAndroid Build Coastguard Worker         case '\n':
1828*cf5a6c84SAndroid Build Coastguard Worker         case '\r':
1829*cf5a6c84SAndroid Build Coastguard Worker           //insert newline
1830*cf5a6c84SAndroid Build Coastguard Worker           TT.il->data[TT.il->len++] = '\n';
1831*cf5a6c84SAndroid Build Coastguard Worker           i_insert(TT.il->data, TT.il->len);
1832*cf5a6c84SAndroid Build Coastguard Worker           TT.il->len = 0;
1833*cf5a6c84SAndroid Build Coastguard Worker           memset(TT.il->data, 0, TT.il->alloc);
1834*cf5a6c84SAndroid Build Coastguard Worker           break;
1835*cf5a6c84SAndroid Build Coastguard Worker         default:
1836*cf5a6c84SAndroid Build Coastguard Worker           if ((key >= ' ' || key == '\t') &&
1837*cf5a6c84SAndroid Build Coastguard Worker               utf8_dec(key, utf8_code, &utf8_dec_p))
1838*cf5a6c84SAndroid Build Coastguard Worker           {
1839*cf5a6c84SAndroid Build Coastguard Worker             if (TT.il->len+utf8_dec_p+1 >= TT.il->alloc) {
1840*cf5a6c84SAndroid Build Coastguard Worker               TT.il->data = realloc(TT.il->data, TT.il->alloc*2);
1841*cf5a6c84SAndroid Build Coastguard Worker               TT.il->alloc *= 2;
1842*cf5a6c84SAndroid Build Coastguard Worker             }
1843*cf5a6c84SAndroid Build Coastguard Worker             strcpy(TT.il->data+TT.il->len, utf8_code);
1844*cf5a6c84SAndroid Build Coastguard Worker             TT.il->len += utf8_dec_p;
1845*cf5a6c84SAndroid Build Coastguard Worker             utf8_dec_p = 0;
1846*cf5a6c84SAndroid Build Coastguard Worker             *utf8_code = 0;
1847*cf5a6c84SAndroid Build Coastguard Worker           }
1848*cf5a6c84SAndroid Build Coastguard Worker           break;
1849*cf5a6c84SAndroid Build Coastguard Worker       }
1850*cf5a6c84SAndroid Build Coastguard Worker     }
1851*cf5a6c84SAndroid Build Coastguard Worker   }
1852*cf5a6c84SAndroid Build Coastguard Worker cleanup_vi:
1853*cf5a6c84SAndroid Build Coastguard Worker   linelist_unload();
1854*cf5a6c84SAndroid Build Coastguard Worker   free(TT.il->data), free(TT.il), free(TT.yank.data);
1855*cf5a6c84SAndroid Build Coastguard Worker   tty_reset();
1856*cf5a6c84SAndroid Build Coastguard Worker   xputsn("\e[?1049l");
1857*cf5a6c84SAndroid Build Coastguard Worker }
1858