cfi new: fix new disabling buffer support
[barebox-mini2440.git] / commands / edit.c
blob8d3df6fa5227cdfb272e8c9daa9552806f22dd88
1 /*
2 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
4 * See file CREDITS for list of people who contributed to this
5 * project.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /**
22 * @file
23 * @brief A tiny editor implementation
26 #include <common.h>
27 #include <command.h>
28 #include <malloc.h>
29 #include <fs.h>
30 #include <linux/ctype.h>
31 #include <fcntl.h>
32 #include <readkey.h>
33 #include <errno.h>
34 #include <xfuncs.h>
35 #include <linux/stat.h>
37 #define TABSPACE 8
39 struct line {
40 int length;
41 struct line *next;
42 struct line *prev;
43 char *data;
46 static struct line *buffer;
48 static struct line *lastscrline;
50 static int screenwidth = 80;
51 static int screenheight = 25;
53 static int cursx = 0; /* position on screen */
54 static int cursy = 0;
56 static int textx = 0; /* position in text */
58 static struct line *curline; /* line where the cursor is */
60 static struct line *scrline; /* the first line on screen */
61 int scrcol = 0; /* the first column on screen */
63 static void pos(int x, int y)
65 printf("%c[%d;%dH", 27, y + 1, x + 1);
68 static char *screenline(char *line, int *pos)
70 int i, outpos = 0;
71 static char lbuf[1024];
73 memset(lbuf, 0, 1024);
75 if (!line) {
76 lbuf[0] = '~';
77 return lbuf;
80 for (i = 0; outpos < 1024; i++) {
81 if (i == textx && pos)
82 *pos = outpos;
83 if (!line[i])
84 break;
85 if (line[i] == '\t') {
86 lbuf[outpos++] = ' ';
87 while (outpos % TABSPACE)
88 lbuf[outpos++] = ' ';
89 continue;
91 lbuf[outpos++] = line[i];
94 return lbuf;
97 static int setpos(char *line, int position)
99 int i = 0;
100 int linepos = 0;
102 while(line[linepos]) {
103 if (line[linepos] == '\t')
104 while ((i + 1) % TABSPACE)
105 i++;
106 if (i >= position)
107 return linepos;
108 linepos++;
109 i++;
112 return linepos;
115 static void refresh_line(struct line *line, int ypos)
117 char *str = screenline(line->data, NULL) + scrcol;
118 pos(0, ypos);
119 str[screenwidth] = 0;
120 printf("%s%c[K", str, 27);
121 pos(cursx, cursy);
125 * Most sane terminal programs can do ansi screen scrolling.
126 * Unfortunately one of the most popular programs cannot:
127 * minicom.
128 * Grmpf!
130 static int smartscroll = 0;
132 static void refresh(int full)
134 int i;
135 struct line *l = scrline;
137 if (!full) {
138 if (smartscroll) {
139 if (scrline->next == lastscrline) {
140 printf("%c[1T", 27);
141 refresh_line(scrline, 0);
142 pos(0, screenheight);
143 printf("%*s", screenwidth, "");
144 return;
147 if (scrline->prev == lastscrline) {
148 printf("%c[1S", 27);
149 for (i = 0; i < screenheight - 1; i++) {
150 l = l->next;
151 if (!l)
152 return;
154 refresh_line(l, screenheight - 1);
155 return;
157 } else {
158 refresh(1);
159 return;
163 for (i = 0; i < screenheight; i++) {
164 refresh_line(l, i);
165 l = l->next;
166 if (!l)
167 break;
170 i++;
171 while (i < screenheight) {
172 pos(0, i++);
173 printf("~");
177 static void line_free(struct line *line)
179 free(line->data);
180 free(line);
183 static struct line *line_realloc(int len, struct line *line)
185 int size = 32;
187 if (!line) {
188 line = xzalloc(sizeof(struct line));
189 line->data = malloc(32);
192 while (size < len)
193 size <<= 1;
195 line->data = xrealloc(line->data, size);
196 return line;
199 static int edit_read_file(const char *path)
201 struct line *line;
202 struct line *lastline = NULL;
203 char *filebuffer;
204 char *linestr, *lineend;
205 struct stat s;
207 if (!stat(path, &s)) {
208 filebuffer = read_file(path, NULL);
209 if (!filebuffer) {
210 printf("could not read %s: %s\n", path, errno_str());
211 return -1;
214 linestr = filebuffer;
215 while (1) {
216 if (!*linestr)
217 break;
219 lineend = strchr(linestr, '\n');
221 if (!lineend && !*linestr)
222 break;
224 if (lineend)
225 *lineend = 0;
227 line = line_realloc(strlen(linestr) + 1, NULL);
228 if (!buffer)
229 buffer = line;
230 memcpy(line->data, linestr, strlen(linestr) + 1);
231 line->prev = lastline;
232 if (lastline)
233 lastline->next = line;
234 line->next = 0;
235 lastline = line;
237 if (!lineend)
238 break;
240 linestr = lineend + 1;
242 free(filebuffer);
245 if (!buffer) {
246 buffer = line_realloc(0, NULL);
247 buffer->data[0] = 0;
250 return 0;
253 static void free_buffer(void)
255 struct line *line, *tmp;
257 line = buffer;
259 while(line) {
260 tmp = line->next;
261 line_free(line);
262 line = tmp;
266 static int save_file(const char *path)
268 struct line *line, *tmp;
269 int fd;
271 fd = open(path, O_WRONLY | O_TRUNC | O_CREAT);
272 if (fd < 0) {
273 printf("could not open file for writing: %s\n", errno_str());
274 return -1;
277 line = buffer;
279 while(line) {
280 tmp = line->next;
281 write(fd, line->data, strlen(line->data));
282 write(fd, "\n", 1);
283 line = tmp;
285 close(fd);
286 return 0;
289 static void insert_char(char c)
291 int pos = textx;
292 char *line;
293 int end = strlen(curline->data);
295 line_realloc(strlen(curline->data) + 2, curline);
296 line = curline->data;
298 while (end >= pos) {
299 line[end + 1] = line[end];
300 end--;
302 line[pos] = c;
303 textx++;
304 refresh_line(curline, cursy);
307 static void delete_char(int pos)
309 char *line = curline->data;
310 int end = strlen(line);
312 while (pos < end) {
313 line[pos] = line[pos + 1];
314 pos++;
316 refresh_line(curline, cursy);
319 static void split_line(void)
321 int length = strlen(curline->data + textx);
322 struct line *newline = line_realloc(length + 1, NULL);
323 struct line *tmp;
325 memcpy(newline->data, curline->data + textx, length + 1);
327 curline->data[textx] = 0;
329 tmp = curline->next;
330 curline->next = newline;
331 newline->prev = curline;
332 newline->next = tmp;
333 if (tmp)
334 tmp->prev = newline;
336 textx = 0;
337 cursy++;
338 curline = curline->next;
339 refresh(1);
342 static void merge_line(struct line *line)
344 struct line *tmp;
346 line_realloc(strlen(line->data) + strlen(line->next->data) + 1, line);
348 tmp = line->next;
350 line->next = line->next->next;
351 if (line->next)
352 line->next->prev = line;
353 strcat(line->data, tmp->data);
355 line_free(tmp);
357 refresh(1);
360 /* not a good idea on slow serial lines */
361 /* #define GETWINSIZE */
363 #ifdef GETWINSIZE
364 static void getwinsize(void) {
365 int y, yy = 25, xx = 80, i, n, r;
366 char buf[100];
367 char *endp;
369 for (y = 25; y < 320; y++) {
370 pos(y, y);
371 printf("%c[6n", 27);
372 i = 0;
373 while ((r = getc()) != 'R') {
374 buf[i] = r;
375 i++;
377 n = simple_strtoul(buf + 2, &endp, 10);
378 if (n == y + 1)
379 yy = y + 1;
380 n = simple_strtoul(endp + 1, NULL, 10);
381 if (n == y + 1)
382 xx = y + 1;
384 pos(0,0);
385 screenheight = yy;
386 screenwidth = xx;
387 printf("%d %d\n", xx, yy);
388 mdelay(1000);
390 #endif
392 static int do_edit(cmd_tbl_t * cmdtp, int argc, char *argv[])
394 int lastscrcol;
395 int i;
396 int linepos;
397 char c;
399 if (argc != 2)
400 return COMMAND_ERROR_USAGE;
402 /* check if we are called as "sedit" insted of "edit" */
403 if (*argv[0] == 's')
404 smartscroll = 1;
406 buffer = NULL;
407 if(edit_read_file(argv[1]))
408 return 1;
410 #ifdef GETWINSIZE
411 getwinsize();
412 #endif
414 cursx = 0;
415 cursy = 0;
416 textx = 0;
417 scrcol = 0;
418 curline = buffer;
419 scrline = curline;
420 lastscrline = scrline;
421 lastscrcol = 0;
423 printf("%c[2J", 27);
424 refresh(1);
426 while (1) {
427 int curlen = strlen(curline->data);
429 if (textx > curlen)
430 textx = curlen;
431 if (textx < 0)
432 textx = 0;
434 screenline(curline->data, &linepos);
436 if (linepos > scrcol + screenwidth)
437 scrcol = linepos - screenwidth;
439 if (scrcol > linepos)
440 scrcol = linepos;
442 cursx = linepos - scrcol;
444 while (cursy >= screenheight) {
445 cursy--;
446 scrline = scrline->next;
449 while (cursy < 0) {
450 cursy++;
451 scrline = scrline->prev;
454 if (scrline != lastscrline || scrcol != lastscrcol)
455 refresh(0);
457 lastscrcol = scrcol;
458 lastscrline = scrline;
459 pos(cursx, cursy);
461 c = read_key();
462 switch (c) {
463 case KEY_UP:
464 if (!curline->prev)
465 continue;
467 curline = curline->prev;
468 cursy--;
469 textx = setpos(curline->data, linepos);
470 break;
471 case KEY_DOWN:
472 if (!curline->next)
473 continue;
475 curline = curline->next;
476 cursy++;
477 textx = setpos(curline->data, linepos);
478 break;
479 case KEY_RIGHT:
480 textx++;
481 break;
482 case KEY_LEFT:
483 textx--;
484 break;
485 case KEY_HOME:
486 textx = 0;
487 break;
488 case KEY_END:
489 textx = curlen;
490 break;
491 case KEY_PAGEUP:
492 for (i = 0; i < screenheight - 1; i++) {
493 if (!curline->prev)
494 break;
495 cursy--;
496 curline = curline->prev;
498 textx = setpos(curline->data, linepos);
499 break;
500 case KEY_PAGEDOWN:
501 for (i = 0; i < screenheight - 1; i++) {
502 if (!curline->next)
503 break;
504 cursy++;
505 curline = curline->next;
507 textx = setpos(curline->data, linepos);
508 break;
509 case KEY_DEL:
510 if (textx == curlen) {
511 if (curline->next)
512 merge_line(curline);
513 } else
514 delete_char(textx);
515 break;
516 case 13:
517 case 10:
518 split_line();
519 break;
520 case 127:
521 case 8:
522 if (textx > 0) {
523 textx--;
524 delete_char(textx);
525 } else {
526 if (!curline->prev)
527 break;
528 curline = curline->prev;
529 cursy--;
530 textx = strlen(curline->data);
531 merge_line(curline);
533 break;
534 case 4:
535 save_file(argv[1]);
536 goto out;
537 case 3:
538 goto out;
539 default:
540 if ((signed char)c != -1)
541 insert_char(c);
544 out:
545 free_buffer();
546 printf("%c[2J", 27);
547 printf("\n");
548 return 0;
551 static const char *edit_aliases[] = { "sedit", NULL};
553 static const __maybe_unused char cmd_edit_help[] =
554 "Usage: (s)edit <file>\n"
555 "This is a very small editor. Its only features are moving the cursor with\n"
556 "the usual keys and typing characters.\n"
557 "<ctrl-c> quits the editor without saving,\n"
558 "<ctrl-d> quits the editor with saving the current file.\n"
559 "\n"
560 "If called as sedit the editor uses ansi codes to scroll the screen.\n";
562 static const __maybe_unused char cmd_edit_usage[] = "edit a file";
564 U_BOOT_CMD_START(edit)
565 .cmd = do_edit,
566 .aliases = edit_aliases,
567 .usage = cmd_edit_usage,
568 U_BOOT_CMD_HELP(cmd_edit_help)
569 U_BOOT_CMD_END
573 * @page edit_command edit (editor)
575 * Usage is: [s]edit \<file\>
577 * This is a very small editor. It's only features are moving the cursor with
578 * the usual keys and typing characters.
580 * \b \<ctrl-c\> quits the editor without saving,\n
581 * \b \<ctrl-d\> quits the editor with saving the current file.
583 * If called as \c sedit the editor uses ansi codes to scroll the screen.