1
2 /*
3 edx/emx (EDitor for X), (C) 2002, Terry Loveall
4 released into the public domain.
5 Based upon the original work ee.c of Yijun Ding, copyright 1991 which is
6 in the public domain.
7 This program comes with no warranties or binaries. Use at your own risk.
8 */
9
10 /* This is the core editor engine */
11
12 /*
13 void prrec(U_REC* undp, char indicator)
14 {
15 char str[256];
16
17 if(undp == NULL) return;
18
19 memset(str,0,256);
20 memcpy(str, undp->str, undp->length >= 0 ? undp->length: 0 - undp->length);
21 printf("%c:p=%x, l=%x, pos=%x, ln=%x, str=%s.\n",
22 indicator,
23 (unsigned int)undp,
24 (unsigned int)undp->link + unbuf,
25 (unsigned int)(undp->pos + edbuf),
26 undp->length,
27 str);
28 }
29 */
30
31 /* get true x co-ord for char at 'pos' */
get_tru(char * pos)32 int get_tru(char* pos)
33 {
34 char* tmpp;
35 int i = 1;
36
37 tmpp = line_start + strlen(line_start+1)+1;
38 if(line_start > pos || tmpp < pos) {
39 #ifdef DEBUG
40 printf("Pos=%x, ls=%x, le=%x.\n",
41 (unsigned int)pos,
42 (unsigned int)line_start,
43 (unsigned int)tmpp);
44 #else
45 printf("get_tru\n");
46 bell();
47 #endif /* DEBUG */
48 return 0;
49 }
50 for(tmpp = line_start+1; tmpp < pos; tmpp++){
51 if(*tmpp != '\t') {i++;}
52 else {
53 i = i + ((tabsize) - ((i-1)%tabsize));
54 }
55 }
56 return(i);
57 }
58
get_cur()59 char* get_cur()
60 {
61 return(line_start+x_offset);
62 }
63
realloc_buffer(int mode)64 char * realloc_buffer(int mode)
65 {
66 char *ptr;
67 int i;
68 switch(mode) {
69
70 case 0: {
71 i = amax+AMAX+tabsize+1;
72 if (i<0) return NULL;
73 ptr = realloc(edbuf, (size_t)i);
74 if (ptr) {
75 amax += AMAX;
76 i = ptr - edbuf;
77 edbuf += i;
78 file_end += i;
79 cur_pos += i;
80 line_start += i;
81 last_pos += i;
82 old_pos += i;
83 screen_start += i;
84 mk += i;
85 bstart += i;
86 bend += i;
87 if (last_mk) last_mk += i;
88 }
89 return ptr;
90 }
91
92 case 1: {
93 i = bmax+BMAX+tabsize+1;
94 if (i<0) return NULL;
95 ptr = realloc(bb, (size_t)i);
96 if (ptr) {
97 bmax += BMAX;
98 bb = ptr;
99 }
100 return ptr;
101 }
102
103 case 2: {
104 i = umax+UMAX+1;
105 if (i<0) return NULL;
106 ptr = realloc(unbuf, (size_t)i);
107 if (ptr) {
108 umax += UMAX;
109 i = (int)ptr - (int)unbuf;
110 unbuf = ptr;
111 undop = (void*)undop+i;
112 undosp = (void*)undosp+i;
113 }
114 return ptr;
115 }
116 }
117 return NULL;
118 }
119
init_undo()120 void init_undo()
121 {
122 undosp = undop = unbuf;
123 undop->link = VOID_LINK;
124 undop->pos = cur_pos - edbuf -1;
125 undop->length = 0;
126 }
127
new_undo(char * pos,int len)128 U_REC* new_undo(char *pos, int len)
129 {
130 U_REC *tmp;
131 int tlen = abs(undosp->length);
132
133 retry:
134 /* wrap undo pointer if no space for requested len in undo buffer */
135 if ((void *)undosp->str + tlen + sizeof(U_REC) + len < unbuf + umax) {
136 tmp = (void *) undosp->str + tlen;
137 } else {
138 if (realloc_buffer(2)) goto retry;
139 tmp = (void *) unbuf;
140 }
141
142 tmp->link = (unsigned int)undosp - (unsigned int)unbuf;
143 tmp->pos = pos - edbuf;
144 tmp->length = 0;
145 return tmp;
146 }
147
u_del(char * pos,int len)148 void u_del(char *pos, int len)
149 {
150 if(!undosp) init_undo();
151
152 if(!undosp->length) undosp->pos = pos - edbuf;
153 /* get new_undo if top rec is u_ins, or different pos or no space */
154 if((undosp->length > 0) ||
155 ( undosp->pos + edbuf - undosp->length != pos) || /* stack only del not bs */
156 ( (void*)undosp->str - undosp->length + abs(len) >= unbuf + umax )) {
157 undosp = new_undo(pos, abs(len));
158 if(undosp == unbuf) undo_wrap--; /* say undo wrapped */
159 }
160
161 if(len) memcpy(undosp->str + abs(undosp->length), pos, len);
162 undosp->length = undosp->length - len;
163
164 if(!in_undo) { undop = undosp; undone = 0;}
165 }
166
u_ins(char * pos,int len)167 void u_ins(char *pos, int len)
168 {
169 int tlen;
170 if(!undosp) init_undo();
171
172 if(!undosp->length) undosp->pos = pos - edbuf;
173 /* get new_undo if top rec is u_del, or different pos or no space */
174 if((undosp->length < 0) ||
175 /* stack only left to right insertions */
176 ( undosp->pos + edbuf + undosp->length != pos ) ||
177 ( (void *)undosp->str + undosp->length + abs(len) >= unbuf + umax )) {
178 undosp = new_undo(pos, abs(len));
179 if(undosp == unbuf) undo_wrap--; /* say undo wrapped */
180 }
181 tlen = abs(undosp->length);
182 if(len) memcpy(undosp->str + tlen, pos, len);
183 undosp->length = tlen + len;
184 if(!in_undo) { undop = undosp; undone = 0;}
185 }
186
ytot_ins()187 void ytot_ins()
188 {
189 char* e;
190 for(e=undop->pos+edbuf; e<undop->pos+edbuf + abs(undop->length); e++)
191 if(*e == EOL) ytot++;
192 }
193
undo()194 void undo()
195 {
196 /* dont undo nothing, but say nothing is unchanged */
197 if(undone) { bell(); return; }
198 if(undop != undosp) {
199 if (undop->link == VOID_LINK)
200 undop = unbuf;
201 else
202 undop = undop->link + unbuf;
203 }
204 in_undo++;
205 goto_ptr(undop->pos + edbuf);
206 if(undop->length < 0) { /* is delete so insert */
207 /* delete flag is negative length */
208 file_resize(undop->pos + edbuf, undop->pos + edbuf - undop->length);
209 memcpy(undop->pos + edbuf, undop->str, - undop->length);
210 u_ins(undop->pos + edbuf, - undop->length);
211 ytot_ins(); /* adjust ytot when inserting */
212 }
213 else { /* is insert so delete */
214 file_resize(undop->pos + edbuf + undop->length, undop->pos + edbuf);
215 }
216 goto_ptr(undop->pos + edbuf);
217 if(undop->link==VOID_LINK) {
218 undone = -1;
219 flag[CHG] = 0;
220 show_top();
221 }
222 in_undo--;
223 flag[SHW] = 1;
224 }
225
redo()226 void redo()
227 {
228 /* dont redo nothing */
229 if(undop == undosp) { bell(); return; }
230 in_undo++;
231 goto_ptr(undop->pos + edbuf);
232
233 if(undop->length > 0) { /* is insert so insert */
234 file_resize(undop->pos + edbuf, undop->pos + edbuf + undop->length);
235 memcpy(undop->pos + edbuf, undop->str, undop->length);
236 u_ins(undop->pos + edbuf, undop->length);
237 ytot_ins(); /* adjust ytot when inserting */
238 }
239 else { /* is delete< so delete */
240 file_resize(undop->pos + edbuf - undop->length, undop->pos + edbuf);
241 }
242 goto_ptr(undop->pos + edbuf);
243
244 undop = (void*)undop->str + abs(undosp->length);
245 undone = 0;
246 in_undo--;
247 flag[SHW] = 1;
248 }
249
sys_exit(int code)250 void sys_exit(int code)
251 {
252 if(!(flag[CHG]) || code==2) {
253 /* watch where you're goin', clean up where you been */
254 #ifdef X11
255 if(selection_text) free(selection_text);
256 #endif
257 if(cfdpath) free(cfdpath);
258 #ifdef X11
259 exit(code&1);
260 #else
261 gotoxy(0,0);
262 ttclose();
263 exitf = 0;
264 /* printf("\033c"); */ /* reset terminal */
265 /* printf("\033[2J"); */ /* clear screen */
266 clrscr();
267 return;
268 #endif
269 }
270 bell();
271 }
272
goto_xpos()273 void goto_xpos()
274 {
275 goto_x(x_offset < strlen(line_start+1)+1 ?
276 x_offset :
277 strlen(line_start+1)+1);
278 }
279
280 /* cursor movement */
cursor_up()281 void cursor_up()
282 {
283 if(flag[BLK]) flag[SHW] = 1;
284 if(ytru == 0) return;
285 ytru--;
286 while(*--line_start != EOL) ;
287 y--;
288 goto_xpos();
289 }
290
cursor_down()291 void cursor_down()
292 {
293 if(flag[BLK]) flag[SHW] = 1;
294 if(ytru == ytot) return;
295 ytru++;
296 while(*++line_start != EOL) ;
297 y++;
298 goto_xpos();
299 }
300
move_to(int newx,int newy)301 void move_to(int newx, int newy)
302 {
303 int old;
304 if (newy < 0) return;
305 if (file_end==edbuf+1) return;
306 if((y == newy && x == newx) || (executive != MAIN)) return;
307
308 while((y < newy) && (ytru < ytot)) cursor_down();
309 while((y > newy) && (ytru > 0)) cursor_up();
310
311 if(line_start[x_offset] == EOL) cursor_left();
312
313 /* detect impossible to achieve x pos within tabs */
314 old = xtru - newx;
315 while((old > 0 ? xtru > newx : xtru < newx) && (*cur_pos != EOL)){
316 xtru < newx ? cursor_right() : cursor_left();
317 }
318 }
319
getx()320 void getx()
321 {
322 xtru = get_tru(cur_pos);
323 x_offset = cur_pos - line_start;
324 x = xtru - xlo;
325 }
326
327 /* cursor left & right */
cursor_left()328 void cursor_left()
329 {
330 if (cur_pos == edbuf+1) return;
331 if(xtru == 1) {
332 cursor_up();
333 goto_x(strlen(line_start+1)+1);
334 return;
335 }
336 if(flag[BLK]) flag[SHW] = 1;
337 if( x == 1 && xlo != 0){
338 xlo -= XINC;
339 flag[SHW] = 1;
340 }
341 --cur_pos;
342 getx();
343 }
344
cursor_right()345 void cursor_right()
346 {
347 if (cur_pos == file_end) return;
348 if(flag[BLK]) flag[SHW] = 1;
349 if(*cur_pos == EOL || xtru >= LMAX) {
350 goto_x(1);
351 cursor_down();
352 return;
353 }
354 if(x == screen_width-1) {
355 xlo += XINC;
356 flag[SHW] = 1;
357 }
358 ++cur_pos;
359 getx();
360 }
361
cursor_pageup()362 void cursor_pageup()
363 {
364 int i,ytmp=y;
365
366 for(i=1; i<screen_height; ++i) cursor_up();
367 if(ytru < screen_height) ytmp = 0;
368 y = ytmp;
369 flag[SHW] = 1;
370 }
371
cursor_pagedown()372 void cursor_pagedown()
373 {
374 int i, ytmp=y;
375
376 for(i=1; i<screen_height; ++i) {
377 if (ytru>ytot+y-screen_height) break;
378 cursor_down();
379 }
380 y = ytmp;
381 flag[SHW] = 1;
382 }
383
word_left()384 void word_left()
385 {
386 char *d = cur_pos;
387
388 if(d[-1] == EOL) { /* at bol */
389 if(ytru == 0) return; /* don't backup past start */
390 cursor_up();
391 goto_x(strlen(line_start+1)+1); /* goto end of line */
392 cursor_right();
393 return;
394 }
395
396 /* skip white space separators */
397 while(strchr(wdelims,d[-1])) { d--; cursor_left(); }
398 /* skip real chars */
399 while(!strchr(wdelims,d[-1])) { d--; cursor_left(); }
400 }
401
word_right()402 void word_right()
403 {
404 char *d = cur_pos;
405
406 if(*d == EOL) { /* at eol */
407 if(ytru >= ytot) return; /* don't go past end */
408 cursor_down();
409 goto_x(1); /* goto start of line */
410 return;
411 }
412
413 /* skip first delimitor if any */
414 if (strchr(wdelims,*d)) { d++; cursor_right(); }
415 /* skip real chars */
416 while(!strchr(wdelims,*d)) { d++; cursor_right(); }
417 /* skip white space separators
418 JPD changed the behaviour there - avoiding in particular
419 a crash when reaching the last word.
420 */
421 #ifdef TLL
422 while(strchr(wdelims,*d)) { d++; cursor_right(); }
423 #else
424 while(isspace(*d)) { d++; cursor_right(); }
425 #endif
426 }
427
word_mark()428 void word_mark()
429 {
430 if(cur_pos[0] <= BLNK) return; /* don't mark nothing */
431 mark_off();
432 if(!strchr(wdelims,cur_pos[-1])) word_left();
433 block_mark();
434 while(!strchr(wdelims,*cur_pos)) cursor_right();
435 #ifdef X11
436 keve->state |= ShiftMask;
437 #endif
438 }
439
440 /* display --------------------------------------------------------*/
441 /* assuming cursor in correct position: show_rest(screen_width-x,line_start+x_offset) */
442
drstr(char * disp,int i)443 void drstr(char* disp, int i)
444 {
445 #ifdef X11
446 drawstring(disp,i);
447 #else
448 disp[i] = 0;
449 cputs(disp);
450 #endif
451 outxy.X += i;
452 }
453
show_rest(int len,char * s)454 void show_rest(int len, char *s)
455 {
456 char *ss;
457 char disp[MAXVLINE];
458 int i,j,k=0,xlt=xlo;
459
460 ss = s;
461 i = 0;
462 if(flag[BLK]) {
463 if(cur_pos < mk)
464 { bstart = cur_pos; bend = mk; }
465 else
466 { bstart = mk; bend = cur_pos; }
467 if ((ss >= bstart) && (ss < bend)) highvideo();
468 }
469 while(*ss != EOL && i < MAXVLINE) {
470 if(flag[BLK]) {
471 if ((ss == bstart)) { drstr(disp+xlo,i-xlo); k += i; xlo=i=0; highvideo(); }
472 if ((ss == bend)) { drstr(disp+xlo,i-xlo); k += i; xlo=i=0; lowvideo(); }
473 }
474 if(*ss == '\t') {
475 for(j = i +(tabsize - (k+i)%tabsize); i<j; disp[i++] = ' ');
476 ss++;
477 }
478 else disp[i++] = *ss++;
479 }
480 if(i) drstr(disp+xlo,i-xlo);
481 if(flag[BLK] && (ss == bend)) lowvideo();
482 clreol();
483 xlo = xlt;
484 }
485
486 /* line_start and y correct */
show_scr(int fr,int to)487 void show_scr(int fr, int to)
488 {
489 int len=screen_width-1;
490 int i=fr;
491
492 screen_start=line_start;
493
494 /* calculate screen_start */
495 for(; i<y; i++) while(screen_start > edbuf && *--screen_start != EOL) ;
496 for(; i>y; i--) while(*++screen_start != EOL) ;
497
498 /* first line */
499 screen_start++;
500 do {
501 gotoxy(0,fr+yl2);
502 if(screen_start<file_end && strlen(screen_start) > xlo) {
503 #ifndef X11
504 clreol();
505 #endif
506 show_rest(len, screen_start);
507 } else {
508 if(((flag[BLK]) &&
509 (screen_start == bend)) ||
510 (screen_start == bend+1)) lowvideo();
511 clreol();
512 }
513 /* skip EOL */
514 while(*screen_start++) ;
515 #ifdef X11
516 } while(++fr <= to);
517 #else
518 } while(++fr < to);
519 #endif
520 }
521
scroll_up()522 void scroll_up()
523 {
524 if(!y) cursor_down();
525 y--;
526 flag[SHW] = 1;
527 }
528
scroll_down()529 void scroll_down()
530 {
531 if(line_start <= edbuf) return;
532 if(ytru <= y) return;
533 if(y >= screen_height-1) cursor_up();
534 y++;
535 flag[SHW] = 1;
536 }
537
538 /* undraw, redraw status and display */
scr_update()539 void scr_update()
540 {
541
542 #ifdef X11
543 if(executive != MAIN && !expose) return;
544 undraw_cursor();
545 #else
546 if(executive != MAIN) return;
547 #endif
548 /* update text buffer display */
549 if( flag[BLK] ) flag[SHW] = 1;
550 if(y <= -1 || y >= screen_height) {
551 if(y == -1) {
552 y++; show_sdn(0);
553 }
554 else if(y == screen_height) {
555 y--; show_sdn(0);
556 }
557 else {
558 y = y < 0 ? 0 : screen_height-1;
559 show_scr(0, screen_height-1);
560 }
561 }
562 else if(flag[SHW] ) {
563 show_scr(0, screen_height-1);
564 }
565 flag[SHW] = 0;
566 #ifdef X11
567 if (help_done) return;
568 #endif
569 show_pos();
570 lowvideo();
571 gotoxy(x-1,y+yl2);
572 #ifdef X11
573 show_vbar();
574 draw_cursor();
575 #endif
576 }
577
show_sdn(int line)578 void show_sdn(int line)
579 {
580 gotoxy(0,yl2+line);
581 show_scr(0, screen_height-1);
582 }
583
show_flag(int x,int g)584 void show_flag(int x, int g)
585 {
586 gotoxy(20+x-1,yl1);
587 putch(g? fsym[x]: '.');
588 flag[x] = g;
589 }
590
591 /*
592 simple minded line input executive for status line dialogs.
593 Successful completion, indicated by a Return key, executes the
594 callback in dialogCB. Responds to 'Esc' and ^C by terminating
595 without executing the callback. Printing first char resets Col.
596 Use ^H to overwrite preset string, 'End' displays cursor to EOS.
597 All other characters input to diabuf. Set by 'show_gets'.
598 */
599
dialog(int key)600 void dialog(int key)
601 {
602 int skey;
603
604 #ifdef X11
605 undraw_cursor();
606 gotoxy(diastart+col,yl1);
607 skey = key & 0xff;
608 if(keve->state & ControlMask) skey &= 0x1f;
609 /* special controls for search&replace Y/N/Esc/! */
610 if (dialogCB == do_sar) {
611 switch(tolower(skey)) {
612 case 27: search_mode = 2; break;
613 case 'n': search_mode = 3; break;
614 case 10:
615 case 13:
616 case 'y': search_mode = 4; break;
617 case '!': search_mode = 5; break;
618 default: search_mode = 6; break;
619 }
620 do_sar();
621 first = key;
622 return;
623 }
624 if(key == XK_End) {
625 while((diabuf[col]!=0) && (col<dblen)) putch(diabuf[col++]);
626 } else {
627 switch(skey){
628 case 8: {
629 if(col < 0) col = strlen(diabuf);
630 if(col) { col--; diabuf[col] = '\0'; outxy.X--; putch(' '); outxy.X--;}
631 break;
632 }
633 case 3:
634 case 13:
635 case 27: {
636 executive = MAIN;
637 diabuf[col] = 0;
638 if(*diabuf && skey == 13)
639 dialogCB();
640 flag[SHW] = 1;
641 scr_update();
642 show_top();
643 break;
644 }
645 default: {
646 if(col < 0 || !first) {
647 col = 0;
648 gotoxy(diastart+col,yl1);
649 clreol();
650 }
651 if (col < dblen) {
652 diabuf[col++] = key;
653 diabuf[col] = '\0';
654 putch(key);
655 } else
656 bell();
657 }
658 }
659 }
660 first = key;
661 draw_cursor();
662 #else
663 skey = key & 0xff;
664
665 gotoxy(diastart+col,yl1);
666
667 /* special control for search&replace Y/N/Esc/! */
668 if (dialogCB == do_sar) {
669 switch(tolower(skey)) {
670 case 27: search_mode = 2; break;
671 case 'n': search_mode = 3; break;
672 case 10:
673 case 13:
674 case 'y': search_mode = 4; break;
675 case '!': search_mode = 5; break;
676 default: search_mode = 6; break;
677 }
678 do_sar();
679 first = key;
680 return;
681 }
682 if(key == 0x0c) { /* ^L */
683 while(diabuf[col] != 0) putch(diabuf[col++]);
684 } else {
685 switch(skey){
686 case 8: {
687 if(col < 0) col = strlen(diabuf);
688 if(col) { col--; gotoxy(--outxy.X,outxy.Y); putch(' '); gotoxy(outxy.X,outxy.Y);}
689 break;
690 }
691 case 3:
692 case 10:
693 case 13:
694 case 27: {
695 executive = MAIN;
696 diabuf[col] = 0;
697 if(*diabuf && (skey == 10 || skey == 13))
698 dialogCB();
699 flag[SHW] = 1;
700 scr_update();
701 show_top();
702 break;
703 }
704 default: {
705 if(col < 0 || !first) {
706 col = 0;
707 gotoxy(diastart+col,yl1);
708 clreol();
709 }
710 diabuf[col++] = key;
711 putch(key);
712 }
713 }
714 }
715 first = key;
716 #endif
717 }
718
719 /* display a dialog property string at fixed location in the status bar */
720
show_note(char * prp)721 void show_note(char *prp)
722 {
723 gotoxy(32,yl1);
724 clreol();
725 cputs(prp);
726 diastart = outxy.X+2;
727 }
728
729 /* setup status line interactive dialog and input data processing callback */
730
show_gets(char * prp,char * buf,int blen,void * cb)731 int show_gets(char *prp, char *buf, int blen, void *cb)
732 {
733 #ifdef X11
734 comment = prp;
735 #endif
736 diabuf = buf; /* point at the input buffer */
737 dialogCB = cb; /* setup the dialog callback */
738 first = *diabuf; /* first = 0 = True; */
739 dblen = blen;
740
741 lowvideo(); /* make dialog stand out in status line */
742 show_note(prp); /* show function */
743 cputs(": ");
744 cputs(diabuf); /* show preset, if any */
745 col=strlen(diabuf); /* point cursor at _end_ of preset string. */
746 executive = DIALOG; /* tell handle_hey() to pass keys to dialog */
747 #ifdef X11
748 draw_cursor();
749 #endif
750 return 0;
751 }
752
753 /* update line and col */
show_pos()754 void show_pos()
755 {
756 char tbuf[NLEN];
757
758 if(executive != MAIN) return;
759 highvideo();
760 gotoxy(5,yl1);
761 sprintf(tbuf,"%d %d ", ytru+1, xtru);
762 cputs(tbuf);
763 }
764
765 /* redraw the status line only in executive == MAIN mode */
766
show_top()767 void show_top()
768 {
769 int i;
770 char tbuf[NLEN];
771
772 #ifdef X11
773 if(executive != MAIN && !expose) return;
774 #else
775 if(executive != MAIN || !exitf) return;
776 #endif
777 gotoxy(0,yl1);
778 highvideo();
779 clreol();
780 show_pos();
781 for(i=0; i<=EDT; i++)
782 show_flag(i, flag[i]);
783 sprintf(tbuf," "HELP"=F1 %s", cfdpath);
784 cputs(tbuf);
785 lowvideo();
786 gotoxy(x-1,y+yl2);
787 }
788
789 /* chdir to working directory and fire up another copy of the editor */
new_edit(char * nfile)790 void new_edit(char *nfile)
791 {
792 char b[1024];
793 sprintf(b,"cd %s; "EDIT" %s &",
794 cfdpath ? cfdpath : "./", nfile ? nfile : "" );
795 SYSTEM(b);
796 }
797
798 /* display help/about page */
799
show_help(int mode)800 void show_help(int mode)
801 {
802 #ifdef EXTHELP
803 char name[NLEN];
804 #ifdef EMACS
805 sprintf(name, "%s/%s", DOCDIR, "MANUAL.emx");
806 #else
807 sprintf(name, "%s/%s", DOCDIR, "MANUAL.wordstar");
808 #endif
809 new_edit(name);
810 #else
811
812 char* prntstr;
813 int i;
814
815 flag[SHW] = 0;
816 flag[BLK] = 0;
817 last_mk = mk;
818 mk = (void*) -1;
819 clrscr();
820 show_top();
821 gotoxy(0,yl2);
822
823 #ifdef X11
824
825 #ifdef MINIMAL
826 prntstr = HELP_STR;
827 /* char at a time to process EOL char */
828 for(i=0; i < sizeof(HELP_STR); putch(prntstr[i++]));
829 #else
830 if (mode == 0) {
831 prntstr = HELP_STR;
832 /* char at a time to process EOL char */
833 for(i=0; i < sizeof(HELP_STR); putch(prntstr[i++]));
834 }
835 if (mode == 1) {
836 int j;
837 prntstr = ALT_KEY_BINDINGS;
838 for (j=0; j<strlen(prntstr); j++) putch(prntstr[j]);
839 putch(EOL); putch(EOL);
840 for(i=0; i<26; i++) if ((prntstr=binding[i])) {
841 putch('a'+i); putch(':'); putch(' ');
842 for (j=0; j<strlen(prntstr); j++) putch(prntstr[j]);
843 putch(EOL);
844 }
845 }
846
847 #endif /* MINIMAL */
848
849 #else /* TERMCAP */
850
851 #ifdef MINIMAL
852 /* line at a time to process EOL char */
853 i=0;
854 prntstr = HELP_STR;
855 while(prntstr < HELP_STR + sizeof(HELP_STR)) {
856 puts(prntstr);
857 prntstr += strlen(prntstr)+1;
858 gotoxy(0,++i);
859 }
860 #else
861 if (mode == 0) {
862 /* line at a time to process EOL char */
863 i=0;
864 prntstr = HELP_STR;
865 while (prntstr < HELP_STR + sizeof(HELP_STR)) {
866 puts(prntstr);
867 prntstr += strlen(prntstr)+1;
868 gotoxy(0,++i);
869 }
870 }
871 if (mode == 1) {
872 int j=2;
873 prntstr = ALT_KEY_BINDINGS;
874 puts(prntstr);
875 gotoxy(0, j);
876 for(i=0; i<26; i++) if ((prntstr=binding[i])) {
877 putchar('a'+i); putchar(':'); putchar(' ');
878 puts(prntstr);
879 gotoxy(0, ++j);
880 }
881 }
882 #endif /* MINIMAL */
883 #endif /* TERMCAP */
884 help_done = -1;
885 scr_update();
886 mk = last_mk;
887 #endif /* EXTHELP */
888 }
889
890 /*
891 set editor options executive.
892 Accept a single UPPER or lower case char only from the string "MFOCTBAE":
893 Modified, Fill, Overwrite, Case, Tab, Block marked, replace All, Edit.
894 */
895
options(int key)896 void options(int key)
897 {
898 char *d;
899 int k;
900
901 if ((key&255) < 0x20)
902 goto end_options;
903
904 k = toupper(key) & ~0x20;
905 if((d=strchr(fsym, k)) != 0) {
906 k = d-fsym;
907 show_flag(k, !flag[k]);
908 }
909 end_options:
910 executive = MAIN;
911 show_top();
912 scr_update();
913 }
914
915 /* setup 'executive = OPTIONS' mode */
916
show_mode()917 void show_mode()
918 {
919 highvideo();
920 show_note(fsym);
921 lowvideo();
922 putch(BLNK);
923 executive = OPTIONS;
924 }
925
926 /* file operation ---*/
927
file_read()928 void file_read()
929 {
930 int c, d;
931 char *col = file_new();
932
933 if(fi == 0) return;
934
935 /* read complete line */
936 do {
937 c = fgetc(fi);
938 if(c == EOF) {
939 fclose(fi);
940 fi = 0; /* no more read */
941 break;
942 }
943 if(c == '\t' && flag[TAB]) { /* conditionally convert tabs on input */
944 do (*file_end++ = BLNK);
945 while( ((file_end-col) % tabsize) != 0);
946 }
947 else
948 if(c == LF) {
949 *file_end++ = EOL;
950 col = file_end;
951 ytot++;
952 }
953 else *file_end++ = c;
954 if (file_end >= edbuf+amax) {
955 d = file_end - col;
956 realloc_buffer(0);
957 col = file_end - d;
958 }
959 } while(file_end < edbuf+amax);
960 for(; ewin.jump>1; ewin.jump--) cursor_down();
961 }
962
963 /* compress one line from end */
964
file_ltab(char * s)965 char *file_ltab(char *s)
966 {
967 char *d, *e;
968
969 e = d = strchr(s--, EOL);
970 while(*--e == BLNK) ; /* trailing blank */
971 while(e > s) {
972 if(e[0] == BLNK && (e-s)%tabsize == 0 && e[-1] == BLNK) {
973 *--d = 9;
974 while(*--e == BLNK && (e-s)%tabsize != 0) ;
975 }
976 else *--d = *e--;
977 }
978 return d;
979 }
980
981 /* routine used for write block file also, this makes it more complicated */
982
file_write(FILE * fp,char * s,char * e)983 int file_write(FILE *fp, char *s, char *e)
984 {
985 if(fp == 0) return 1; /* no write */
986 do {
987 if(flag[TAB] && *s != EOL)
988 s = file_ltab(s);
989 if(*s && fputs(s, fp) < 0)
990 return 1;
991 fputc(LF, fp);
992 while(*s++ != EOL) ;
993 } while(s < e);
994 return 0;
995 }
996
file_fout()997 int file_fout()
998 {
999 if(fo == 0) {
1000 strcpy(bbuf, ewin.name);
1001 strcat(bbuf, "XXXXXX");
1002 close(mkstemp(bbuf));
1003 fo=fopen(bbuf, "w");
1004 }
1005 if (!flag[NEW]) {
1006 fchmod(fileno(fo), ofstat.st_mode & 07777);
1007 }
1008 return file_write(fo, edbuf+1, file_end);
1009 }
1010
do_save()1011 void do_save()
1012 {
1013 char bakfile[NLEN+1];
1014
1015 /* prompt on empty filename */
1016 if((ewin.name[0] == 0)) {
1017 file_save(-1,0);
1018 return;
1019 }
1020
1021 executive=MAIN;
1022 if(file_fout() ) {
1023 return; /* exit if can't write output */
1024 }
1025
1026 fclose(fo);
1027 fo = 0; /* set fo to known condition */
1028 /* if editing old file then delete old file */
1029 if (flag[NEW] == 0) {
1030 strcpy(bakfile, ewin.name);
1031 strcat(bakfile, "~");
1032 unlink(bakfile);
1033 rename(ewin.name, bakfile);
1034 #ifdef MINIMAL
1035 unlink(bakfile);
1036 #endif
1037 }
1038
1039 rename(bbuf, ewin.name); /* ren new temp to old name */
1040 #ifdef X11
1041 set_title(ewin.name);
1042 #endif
1043 flag[CHG] = 0;
1044 show_top();
1045 }
1046
1047 /* go to top of file and reset to known condition */
top()1048 void top()
1049 {
1050 yl1 = YTOP;
1051 yl2 = yl1+1;
1052 line_start = edbuf;
1053 x_offset = 1;
1054 xtru = x = 1;
1055 ytru = y = 0;
1056 flag[SHW] = 1;
1057 }
1058
1059 /* new file init */
file_new()1060 char *file_new()
1061 {
1062 clrscr();
1063 top();
1064 edbuf[0] = EOL;
1065 last_pos = edbuf;
1066 file_end = edbuf+1;
1067 ytot = 0;
1068 flag[NEW] = 0;
1069 mark_off();
1070 last_mk = NULL;
1071 if((fi = fopen(ewin.name, "r")) == 0) flag[NEW]++;
1072 else fstat(fileno(fi), &ofstat);
1073 return(file_end);
1074 }
1075
1076 /* exec the forking cmd */
SYSTEM(char * cmd)1077 int SYSTEM (char *cmd)
1078 {
1079 #define SHELL "/bin/sh"
1080 pid_t pid;
1081 switch(pid=fork()) {
1082 case 0:
1083 execl(SHELL,"sh","-c",cmd,(char *) 0);
1084 printf(EXECL_FAILED"\n");
1085 _exit(127);
1086 case -1: printf(FORK_ERROR"\n");
1087 default: return(0);
1088 }
1089 }
1090
gorun()1091 void gorun()
1092 {
1093 SYSTEM(Command);
1094 }
1095
1096 #ifdef MINIMAL
1097 /* chdir to working directory and fire up rxvt */
1098
mterm()1099 void mterm()
1100 {
1101 char b[1024];
1102 sprintf(b,"cd %s;rxvt -font 8x16 -ls -sl 500 -sr +st -geometry 96x28 &",
1103 cfdpath ? cfdpath : "./");
1104 SYSTEM(b);
1105 }
1106 #else
launch_edit()1107 void launch_edit()
1108 {
1109 if (*diabuf)
1110 new_edit(diabuf);
1111 free(diabuf);
1112 }
1113
req_edit()1114 void req_edit()
1115 {
1116 diabuf = malloc(NLEN+1);
1117 *diabuf = '\0';
1118 show_gets(OPEN, diabuf, NLEN, &launch_edit);
1119 return;
1120 }
1121 #endif /* MINIMAL */
1122
do_cd()1123 void do_cd()
1124 {
1125 chdir(cfdpath);
1126 }
1127
chgdir()1128 void chgdir()
1129 {
1130 show_gets("cd", cfdpath, BUFSIZ, do_cd);
1131 }
1132
do_open()1133 void do_open()
1134 {
1135 file_read();
1136 #ifdef X11
1137 set_title(ewin.name);
1138 #endif
1139 executive=MAIN;
1140 }
1141
file_save(int f_all,int f_win)1142 void file_save(int f_all, int f_win)
1143 {
1144 if (!flag[EDT]) return;
1145 if(((flag[CHG]) | f_all) || f_win==-1) {
1146 show_gets(SAVE_AS, ewin.name, sizeof(ewin.name), &do_save);
1147 return;
1148 }
1149 /* optionally make new empty file */
1150 if(f_win==1) {
1151 show_gets(OPEN, ewin.name, sizeof(ewin.name), &do_open);
1152 }
1153 }
1154
1155 /* main editor workhorse. Inserts/deletes specified source/destination */
file_resize(char * s,char * d)1156 void file_resize(char *s, char *d)
1157 {
1158 char *e;
1159 unsigned int i;
1160 int s_rel = s - edbuf;
1161 int d_rel = d - edbuf;
1162
1163 /* immediate problem only when block buffer on disk too big */
1164
1165 i = file_end - s;
1166 file_end += d-s;
1167 retry:
1168 if(file_end>= edbuf+amax) {
1169 if (realloc_buffer(0)) {
1170 s = edbuf + s_rel;
1171 d = edbuf + d_rel;
1172 goto retry;
1173 }
1174 show_note(MAIN_BUFFER_FULL);
1175 bell();
1176 return;
1177 }
1178
1179 e = s+i;
1180 if(s < d) { /* expand */
1181 d += e - s;
1182 s = e;
1183 while(i-- > 0) *--d = *--s;
1184 }
1185 else {
1186 u_del(d, s - d); /* save undo delete string */
1187 /* adjust ytot when shrink */
1188 for(e=d; e<s; e++) if(*e == EOL) ytot--;
1189 while(i-- > 0) *d++ = *s++;
1190 }
1191 *file_end = EOL; /* last line may not complete */
1192 if(!flag[CHG] ) {
1193 show_flag(CHG, 1);
1194 gotoxy(x-1,y+yl2);
1195 clreol();
1196 }
1197 }
1198
1199 /* search and goto */
1200
1201 /* xx >= 1, yy >= 0 */
1202
goto_x(int xx)1203 void goto_x(int xx)
1204 {
1205 cur_pos = line_start + xx;
1206 if (cur_pos>file_end) cur_pos=file_end;
1207 xtru = get_tru(cur_pos);
1208 if(!xtru) cur_pos--;
1209 x_offset = cur_pos - line_start;
1210
1211 xx = xlo;
1212 if(xtru == 1) xlo = 0;
1213 if(xtru-xlo >= screen_width)
1214 xlo = ((xtru + XINC - screen_width)/XINC) * XINC;
1215 x = xtru - xlo;
1216 if (xlo!= xx)
1217 flag[SHW]=1;
1218 }
1219
goto_y(int yy)1220 void goto_y(int yy)
1221 {
1222 int i, n;
1223
1224 n = ytru;
1225
1226 for(i=n; i<yy; i++) cursor_down();
1227 for(i=yy; i<n; i++) cursor_up();
1228 if(y > screen_height || y < 0) {
1229 flag[SHW] = 1;
1230 y = screen_height/4;
1231 }
1232 }
1233
goto_ptr(char * s)1234 void goto_ptr(char *s)
1235 {
1236 /* find line_start <= s */
1237 char *s1 = s;
1238 int yo = y;
1239
1240 if(s < edbuf || s >= edbuf + amax) {
1241 bell();
1242 return;
1243 }
1244 top();
1245 while(*--s1 != EOL && s1 > edbuf) ; /* find start of target line */
1246 while(line_start+1 <= s1 && y < ytot) cursor_down();/* move to target line */
1247 while(line_start+1 > s && y > 0) cursor_up(); /* move back before target */
1248 goto_x(s-line_start); /* get x from line start */
1249 if(y > screen_height || xlo != 0) {
1250 flag[SHW] = 1;
1251 y = yo;
1252 }
1253 }
1254
goline()1255 void goline()
1256 {
1257 goto_y(atoi(lbuf)-1);
1258 }
1259
goto_last()1260 void goto_last()
1261 {
1262 goto_ptr(last_pos); cursor_down();
1263 }
1264
goto_line()1265 void goto_line()
1266 {
1267 show_gets(GOTO_LINE, lbuf, sizeof(lbuf), goline);
1268 }
1269
switch_marks()1270 void switch_marks()
1271 {
1272 char *c;
1273 if (!last_mk || last_mk>=file_end) return;
1274 c = cur_pos;
1275 goto_ptr(last_mk);
1276 last_mk = c;
1277 if (mk) mk = last_mk;
1278 }
1279
run()1280 void run()
1281 {
1282 show_gets(COMMAND, Command, sizeof(Command), gorun);
1283 }
1284
gocol()1285 void gocol()
1286 {
1287 goto_x(atoi(cbuf) );
1288 }
1289
goto_col()1290 void goto_col()
1291 {
1292 show_gets(GOTO_COLUMN, cbuf, sizeof(cbuf), gocol);
1293 }
1294
1295 /* find and set cursor to matching bracket '(,{,[,],},)' */
1296
find_match()1297 void find_match()
1298 {
1299 char *s = cur_pos;
1300 int dire, cnt;
1301 char ch, mch;
1302
1303 if (!s) return;
1304
1305 ch = *s;
1306 switch (ch) {
1307 case '(':
1308 mch = ')'; dire = 0; break;
1309 case ')':
1310 mch = '('; dire = 1; break;
1311 case '[':
1312 mch = ']'; dire = 0; break;
1313 case ']':
1314 mch = '['; dire = 1; break;
1315 case '{':
1316 mch = '}'; dire = 0; break;
1317 case '}':
1318 mch = '{'; dire = 1; break;
1319 default:
1320 return;
1321 }
1322 cnt = 0;
1323 if (dire) {
1324 while (--s >= edbuf) {
1325 if (*s == ch) cnt++;
1326 else if (*s == mch) {
1327 if (!cnt) goto match;
1328 cnt--;
1329 }
1330 }
1331 } else {
1332 while (++s < file_end) {
1333 if (*s == ch) cnt++;
1334 else if (*s == mch) {
1335 if (!cnt) goto match;
1336 cnt--;
1337 }
1338 }
1339 }
1340 return;
1341 match:
1342 goto_ptr(s);
1343 flag[SHW]=1;
1344 }
1345
1346 /* compare to sbuf. used by search */
str_cmp(char * s)1347 int str_cmp(char *s)
1348 {
1349 char *d = sbuf;
1350
1351 if(flag[CAS] )
1352 {
1353 while(*d ) if(*s++ != *d++ ) return 1;
1354 }
1355 else
1356 {
1357 while(*d ) if(tolower(*s++) != tolower(*d++)) return 1;
1358 }
1359 return 0;
1360 }
1361
1362 /* back/forward search */
goto_find(char * s,int back)1363 char *goto_find(char *s, int back)
1364 {
1365 mark_off();
1366 do
1367 {
1368 if(back) {
1369 if(--s <= edbuf) {
1370 bell();
1371 return 0;
1372 }
1373 }
1374 else {
1375 if(++s >= file_end) {
1376 bell();
1377 return 0;
1378 }
1379 }
1380 } while(str_cmp(s) );
1381 goto_ptr(s);
1382 block_mark();
1383 mk += strlen(sbuf);
1384 return s;
1385 }
1386
gofindforward()1387 void gofindforward()
1388 {
1389 goto_find(cur_pos, 0);
1390 }
1391
gofindbackward()1392 void gofindbackward()
1393 {
1394 goto_find(cur_pos, 1);
1395 }
1396
get_mk(char * dbuf)1397 void get_mk(char* dbuf)
1398 {
1399 if(strchr(sdelims,*cur_pos) && !flag[BLK]) return;
1400 memset(dbuf,0,NLEN * sizeof(char));
1401 if(!flag[BLK]) word_mark();
1402 if(flag[BLK] && (mk != cur_pos) && (abs(cur_pos - mk) < NLEN)){
1403 memcpy(dbuf, mk < cur_pos ? mk : cur_pos, abs(cur_pos - mk));
1404 }
1405 }
1406
goto_search(int back)1407 char *goto_search(int back)
1408 {
1409 if (back) --cur_pos;
1410 get_mk(sbuf);
1411 if (back) ++cur_pos;
1412 search_mode = back;
1413 show_gets(SEARCH_FOR, sbuf, sizeof(sbuf),
1414 (back)? gofindbackward:gofindforward);
1415 return NULL;
1416 }
1417
do_sar()1418 void do_sar()
1419 {
1420 int i;
1421 char *sb;
1422
1423 if (search_mode<=2) {
1424 executive = MAIN;
1425 flag[SHW] = 1;
1426 #ifdef X11
1427 free(comment);
1428 #endif
1429 scr_update();
1430 show_top();
1431 return;
1432 }
1433
1434 repl_again:
1435 if (search_mode==4 || search_mode==5) {
1436 rlen = strlen(rbuf);
1437 do {
1438 file_resize(s+slen, s); /* delete srch string&save undo data */
1439 file_resize(s, s+rlen); /* insert space for replace string */
1440 memcpy(s, rbuf, rlen);
1441 u_ins(s, rlen); /* add replace string to undo buf */
1442 s = s+rlen;
1443 }
1444 while(flag[ALL] && (s=goto_find(s, 0)) != 0) ;
1445 flag[SHW] = 1;
1446 }
1447 if (search_mode==6) return;
1448 if((s =(char*) goto_find(cur_pos,0))) {
1449 slen = strlen(sbuf);
1450 show_scr(0, screen_height-1);
1451 gotoxy(x-1,y+yl2);
1452 highvideo();
1453 i = slen;
1454 sb = s;
1455 while(i-- && !putch(*sb++));
1456 lowvideo();
1457 if (search_mode==5) goto repl_again;
1458 } else {
1459 search_mode = 2;
1460 do_sar();
1461 }
1462 }
1463
ask_replace()1464 void ask_replace()
1465 {
1466 #ifdef X11
1467 comment = malloc(2*NLEN);
1468 #else
1469 char comment[2*NLEN];
1470 #endif
1471 search_mode = 3;
1472 word_left();
1473 --cur_pos;
1474 do_sar();
1475 if (search_mode == 2) return;
1476 sprintf(comment, ASK_REPLACE, rbuf);
1477 show_gets(comment, "", 2*NLEN-1, do_sar);
1478 }
1479
replace_with()1480 void replace_with()
1481 {
1482 show_gets(REPLACE_WITH, rbuf, sizeof(rbuf), ask_replace);
1483 }
1484
goto_replace()1485 void goto_replace()
1486 {
1487 get_mk(sbuf);
1488 show_gets(SAR_FOR, sbuf, sizeof(sbuf), replace_with);
1489 }
1490
gettab()1491 void gettab()
1492 {
1493 tabsize = atoi(twbuf);
1494 }
1495
tab_size()1496 void tab_size()
1497 {
1498 show_gets(TAB_SIZE,twbuf, sizeof(twbuf), gettab);
1499 }
1500
getmarg()1501 void getmarg()
1502 {
1503 screen_width = atoi(wbuf);
1504 flag[SHW]++;
1505 }
1506
window_size()1507 void window_size()
1508 {
1509 show_gets(WRAP_COL, wbuf, sizeof(wbuf), getmarg);
1510 }
1511
1512 /* block and format ---*/
1513 /* use blen, mk, bb */
1514
mark_off()1515 void mark_off()
1516 {
1517 mk = NULL;
1518 flag[BLK] = 0;
1519 flag[SHW] = 1;
1520 show_top();
1521 }
1522
reset_mark()1523 void reset_mark()
1524 {
1525 if (!last_mk) return;
1526 flag[BLK] = 1; mk = last_mk;
1527 }
1528
block_mark()1529 void block_mark()
1530 {
1531 if( mk == NULL ) {
1532 mk = cur_pos;
1533 last_mk = mk;
1534 flag[BLK] = 1;
1535 show_top();
1536 }
1537 else
1538 mark_off();
1539 }
1540
block_put()1541 void block_put()
1542 {
1543 while (blen >= bmax && realloc_buffer(1));
1544
1545 if (blen < bmax)
1546 memcpy(bb, mk, blen);
1547 else {
1548 if(fb == 0 && (fb = tmpfile()) == 0) return;
1549 fseek(fb, 0L, 0);
1550 fwrite(mk, 1, blen, fb);
1551 }
1552 }
1553
block_get()1554 void block_get()
1555 {
1556 int i;
1557
1558 while (mk+blen >= edbuf+amax && realloc_buffer(0));
1559 if (mk+blen < edbuf+amax)
1560 memcpy(mk, bb, blen);
1561 else {
1562 if(fb == 0) return;
1563 fseek(fb, 0L, 0); /* 0L offset, 0=beginning of file */
1564 fread(mk, 1, blen, fb);
1565 }
1566 /* calculate ytot */
1567 for(i=0; i<blen; i++) {
1568 if((mk[i] == EOL) || (mk[i] == LF)) {
1569 ytot++;
1570 mk[i] = 0;
1571 }
1572 }
1573 }
1574
block_line()1575 void block_line()
1576 {
1577 if(ytru == ytot) return;
1578 goto_x(1 );
1579 for(blen = 0; line_start[++blen] != EOL; ) ;
1580 mk = line_start+1;
1581 block_put();
1582
1583 /* delete line and save to undo buf */
1584 file_resize(line_start+blen, line_start);
1585 show_sdn(y);
1586 mark_off();
1587 }
1588
remove_block()1589 void remove_block()
1590 {
1591 char *s;
1592
1593 if(!flag[BLK]) return; /* exit if no mark */
1594 if(cur_pos < mk) { /* ensure cur_pos >= mk */
1595 s = cur_pos ; /* swap cur_pos & mk */
1596 cur_pos = mk ;
1597 mk = s ;
1598 }
1599 s = cur_pos;
1600 goto_ptr(mk);
1601
1602 /* delete block and save to undo buf */
1603 file_resize(s, mk);
1604 cur_pos = mk;
1605 }
1606
block_remove_update()1607 void block_remove_update()
1608 {
1609 remove_block();
1610 mark_off();
1611 }
1612
chg_case(int upper)1613 void chg_case(int upper)
1614 {
1615 char *s;
1616 int i, j, change=0;
1617
1618 if(!flag[BLK]) return; /* exit if no mark */
1619 if(cur_pos < mk) { /* ensure cur_pos >= mk */
1620 s = cur_pos ; /* swap cur_pos & mk */
1621 cur_pos = mk ;
1622 mk = s ;
1623 goto_ptr(cur_pos);
1624 }
1625 i = j = cur_pos+1 - mk; /* get length */
1626
1627 /* detect whether there is any change */
1628 while(j--)
1629 if (mk[j] != (!upper)? tolower(mk[j]) : toupper(mk[j])) {
1630 change = 1;
1631 break;
1632 }
1633 if (!change) return;
1634 u_del(mk, i-1); /* save undo data enmasse */
1635 /* printf("mk=%x, i=%d.\n",mk,i); */
1636 while(i--) mk[i] = !upper ? tolower(mk[i]) : toupper(mk[i]);
1637 u_ins(mk, cur_pos - mk);
1638 flag[CHG] = 1;
1639 flag[SHW] = 1;
1640 }
1641
transpose()1642 void transpose()
1643 {
1644 char c;
1645 if (cur_pos && cur_pos>edbuf+1 && cur_pos<file_end) {
1646 u_del(cur_pos-1, 2);
1647 c = *cur_pos;
1648 *cur_pos = *(cur_pos-1);
1649 *(cur_pos-1) = c;
1650 u_ins(cur_pos-1, 2);
1651 flag[CHG] = 1;
1652 flag[SHW] = 1;
1653 }
1654 }
1655
block_copy(int delete)1656 void block_copy(int delete)
1657 {
1658 char *s;
1659
1660 if(!flag[BLK]) return; /* exit if no mark */
1661 if(cur_pos < mk) { /* ensure cur_pos >= mk */
1662 s = cur_pos ; /* swap cur_pos & mk */
1663 cur_pos = mk ;
1664 mk = s ;
1665 }
1666 blen = cur_pos - mk; /* get length */
1667 block_put(); /* copy block to buffer */
1668 if(delete) {
1669 block_remove_update();
1670 return;
1671 }
1672 mark_off();
1673 }
1674
block_paste()1675 void block_paste()
1676 {
1677 if(!blen) return; /* dont paste nothing */
1678 if(flag[BLK]) block_remove_update(); /* delete marked block */
1679
1680 file_resize(cur_pos, cur_pos+blen);
1681 mk = cur_pos;
1682 block_get();
1683
1684 /* save to undo buf */
1685 u_ins(mk - 1, blen);
1686 goto_ptr(mk + blen);
1687 mark_off();
1688 }
1689
1690 /* read file into cursor position */
doblockr()1691 void doblockr()
1692 {
1693 char *bb_end;
1694 int c, d;
1695 char *col;
1696
1697 if(!(fb = fopen(fbuf, "r"))) { bell(); return; };
1698
1699 fseek(fb, 0L, 2); /* seek to 0L offset, 2=end of file */
1700 blen=ftell(fb); /* get file length */
1701 fseek(fb, 0L, 0); /* seek back to file start */
1702 bb_end = col = bb;
1703
1704 /* read complete file */
1705 do {
1706 c = fgetc(fb);
1707 if(c == EOF) {
1708 fclose(fb);
1709 fb = 0; /* no more read */
1710 break;
1711 }
1712 if(c == '\t' && flag[TAB]) {
1713 do (*bb_end++ = BLNK);
1714 while( ((bb_end-col) % tabsize) != 0);
1715 }
1716 else
1717 if(c == LF) {
1718 *bb_end++ = EOL;
1719 col = bb_end;
1720 }
1721 else
1722 *bb_end++ = c;
1723 if (bb_end >= bb+bmax) {
1724 d = (int)bb;
1725 realloc_buffer(1);
1726 d = (int)bb - d;
1727 col += d;
1728 bb_end += d;
1729 }
1730 } while(bb_end < bb+bmax);
1731
1732 blen = bb_end - bb;
1733 block_paste();
1734 }
1735
block_read()1736 void block_read()
1737 {
1738 show_gets(READ_FILE, fbuf, sizeof(fbuf), doblockr);
1739 }
1740
1741 /* copy block to file, not to block buffer */
doblockw()1742 void doblockw()
1743 {
1744 FILE *fp;
1745 show_flag(TAB, 0);
1746 fp = fopen(fbuf, "w");
1747 file_write(fp, bstart, bend);
1748 fclose(fp);
1749 show_top();
1750 }
1751
block_write()1752 void block_write()
1753 {
1754 if (!flag[EDT]) return;
1755 if(!flag[BLK]) return;
1756 if(cur_pos < mk)
1757 { bstart = cur_pos; bend = mk; }
1758 else
1759 { bstart = mk; bend = cur_pos; }
1760
1761 show_gets(WRITE_FILE, fbuf, sizeof(fbuf), (void*) doblockw);
1762 }
1763
1764 /* fill current line; does not change cursor or file len */
block_fill()1765 int block_fill()
1766 {
1767 int i=screen_width;
1768
1769 while(line_start[--i] > BLNK) ;
1770 if(i == 0) i = screen_width-1;
1771 u_del(&line_start[i],1);
1772 line_start[i] = EOL;
1773 u_ins(&line_start[i],1);
1774 ytot++;
1775 cursor_down();
1776 goto_x(1);
1777 goto_x(strlen(line_start+1)+1);
1778 flag[CHG] = 1;
1779 return i;
1780 }
1781
1782 #ifdef JUSTIFY
1783
1784 /* right justify a line : enlarge from oldlen to newlen by adding blank chars
1785 at suitable places, preferably after punctuation signs */
justify_line(char * newline,int newlen,char * oldline,int oldlen)1786 void justify_line(char *newline, int newlen, char *oldline, int oldlen)
1787 {
1788 int added, i, j, k, l, num=0, npunct=0, quot, rem, suppl;
1789
1790 added = newlen - oldlen;
1791 if (added <= 0) {
1792 strncpy(newline, oldline, newlen);
1793 return;
1794 }
1795
1796 /* Count the number of punctuation signs. Justify routine is smart:
1797 it attempts to increase spaces after punctuation marks rather
1798 than in random places */
1799 for (i=0; i < oldlen; i++) {
1800 if (isspace(oldline[i])) {
1801 num++;
1802 if (i && ispunct(oldline[i-1])) ++npunct;
1803 }
1804 }
1805
1806 if (!num) return;
1807
1808 quot = added / num;
1809 rem = added % num;
1810 if (rem >= npunct) {
1811 rem = rem - npunct;
1812 suppl = 1;
1813 } else
1814 suppl = 0;
1815
1816 j = 0;
1817 for (i=0; i < oldlen; i++) {
1818 newline[j] = oldline[i];
1819 j++;
1820 k = 0;
1821 if (isspace(oldline[i])) {
1822 k = quot;
1823 if ( i > 0 && ispunct(oldline[i-1])) {
1824 if (suppl || rem>0) {
1825 ++k;
1826 if (!suppl) --rem;
1827 }
1828 } else
1829 if (suppl && rem>0) {
1830 ++k;
1831 --rem;
1832 }
1833 }
1834 for (l=0; l<k; l++) {
1835 newline[j] = BLNK;
1836 j++;
1837 }
1838 }
1839 }
1840
1841 /* format paragraph : mode==0 don't fill, mode==1 fill lines */
block_format(int mode)1842 void block_format(int mode)
1843 {
1844 char *s, *sp, *line = NULL, *newline, *newpar;
1845 int j, k, l, xtmp, length, maxlen, parlen, pb, nret;
1846
1847 xtmp = x-1;
1848 if (xtmp<0) xtmp = 0;
1849 length = screen_width - 4 - xtmp;
1850 if (length <= 5) return;
1851
1852 goto_x(1);
1853 s = cur_pos;
1854 nret = 0;
1855
1856 while(s<file_end && (*s==EOL || isspace(*s))) {
1857 if (*s==EOL) ++nret;
1858 ++s;
1859 }
1860 if (s==file_end) return;
1861 if (nret) {
1862 goto_ptr(s);
1863 goto_x(xtmp+1);
1864 return;
1865 }
1866 mk = last_mk = cur_pos;
1867
1868 j = l = 0;
1869 pb = -1;
1870 maxlen = length+2;
1871 parlen = maxlen+xtmp+2;
1872
1873 newline = malloc(maxlen);
1874 newpar = malloc(parlen);
1875
1876 iter:
1877 if (j > maxlen-2 || !line) {
1878 maxlen = j+2;
1879 line = realloc(line, maxlen);
1880 }
1881 nret = 2;
1882 if (*s==EOL || isspace(*s)) {
1883 sp = s;
1884 while (nret && sp<file_end && (*sp==EOL || isspace(*sp))) {
1885 if (*sp==EOL) --nret;
1886 ++sp;
1887 if (sp==file_end) nret = 0;
1888 }
1889 line[j] = BLNK;
1890 if (j==length) pb = j;
1891 if (j>=length || !nret) {
1892 if (l+j+length+xtmp>parlen-2) {
1893 parlen = l+j+length+xtmp+2;
1894 newpar = realloc(newpar, parlen);
1895 }
1896 for (k=0; k<xtmp; k++)
1897 newpar[l++] = BLNK;
1898 if (pb<0 || (!nret && j<=length)) {
1899 for (k=0; k<j; k++)
1900 newpar[l++] = line[k];
1901 } else {
1902 if (mode) {
1903 justify_line(newline,length, line,pb);
1904 for (k=0; k<length; k++)
1905 newpar[l++] = newline[k];
1906 } else {
1907 for (k=0; k<pb; k++)
1908 newpar[l++] = line[k];
1909 }
1910 if (j>length) {
1911 --s;
1912 while(!isspace(*s)&& *s!=EOL) --s;
1913 sp = s+1;
1914 nret = 2;
1915 }
1916 }
1917 newpar[l++] = EOL;
1918 j = 0;
1919 pb = -1;
1920 } else {
1921 pb = j;
1922 ++j;
1923 }
1924 if (!nret) goto finish;
1925 s = sp;
1926 } else {
1927 line[j] = *s;
1928 ++j;
1929 ++s;
1930 }
1931 goto iter;
1932
1933 finish:
1934 --l;
1935 while (*s==EOL || isspace(*s)) --s;
1936 ++s;
1937
1938 /* store data only if a change occurred */
1939 if (l!=s-last_mk || memcmp(last_mk, newpar, l)) {
1940 k = flag[OVR];
1941 cur_pos = s;
1942 flag[BLK] = 1;
1943 flag[OVR] = 0;
1944 remove_block();
1945 goto_ptr(last_mk);
1946 for (j=0; j<l; j++) {
1947 if (newpar[j] == EOL) ++ytot;
1948 key_normal(newpar[j]);
1949 }
1950 s = cur_pos;
1951 flag[OVR] = k;
1952 }
1953 while (s<file_end && (*s==EOL || isspace(*s))) ++s;
1954 goto_ptr(s);
1955 goto_x(xtmp+1);
1956 flag[CHG] = 1;
1957 flag[SHW] = 1;
1958 free(line);
1959 free(newline);
1960 free(newpar);
1961 }
1962 #else
1963
1964 /* format paragraph */
block_format(int mode)1965 void block_format(int mode)
1966 {
1967 char *s=line_start;
1968 int ytmp = y;
1969
1970 goto_x(1);
1971 /* remove newlines to end of para */
1972 while(s = strchr(++s, EOL), ytru < ytot && s[1] != EOL) {
1973 u_del(s,1);
1974 *s = BLNK;
1975 u_ins(s,1);
1976 ytot--;
1977 flag[CHG] = 1;
1978 }
1979 /* truncate line <= screen_width */
1980 while(goto_x(strlen(line_start+1)+1), x_offset >= screen_width) block_fill();
1981 /* goto end of line */
1982 while(line_start[x_offset] ) cursor_right();
1983 show_top();
1984 if( flag[SHW] == 0) show_scr(ytmp, screen_height);
1985 }
1986 #endif
1987
1988 /* key actions ---*/
1989
key_deleol(char * s)1990 void key_deleol(char *s)
1991 {
1992 if(ytru == ytot) return;
1993 if(flag[BLK]) {
1994 block_remove_update(); /* delete marked block */
1995 return;
1996 }
1997 goto_ptr(s);
1998
1999 /* delete eol and save to undo buf */
2000 file_resize(s+1, s);
2001 flag[SHW]=1;
2002 }
2003
2004 /* delete char under cursor */
key_delete()2005 void key_delete()
2006 {
2007 char *s=cur_pos;
2008
2009 if(flag[BLK]) {
2010 block_remove_update();
2011 return;
2012 }
2013 else if( *s == EOL) {
2014 key_deleol(s);
2015 return;
2016 }
2017 /* delete cursor char and save to undo buf */
2018 file_resize(s+1, s);
2019 show_rest(screen_width-x, s);
2020 }
2021
2022 /* delete char before cursor */
key_backspace()2023 void key_backspace()
2024 {
2025 char *s=cur_pos;
2026
2027 if(flag[BLK]) {
2028 block_remove_update();
2029 return;
2030 }
2031 if(*--s == EOL) { /* delete EOL */
2032 if(ytru == 0) return;
2033 cursor_up();
2034 goto_x(strlen(line_start+1)+1);
2035 key_deleol(s);
2036 return;
2037 }
2038 cursor_left();
2039 key_delete();
2040 flag[SHW]=1;
2041 }
2042
2043 /* delete non-white string + white-space string */
key_delword(int eol)2044 void key_delword(int eol)
2045 {
2046 char *d=cur_pos;
2047
2048 if(flag[BLK]) {
2049 block_remove_update();
2050 return;
2051 }
2052 if(*d == EOL) {
2053 blen = 1;
2054 mk = d;
2055 block_put();
2056 key_deleol(d);
2057 return;
2058 }
2059 if(eol) while(*d != EOL) d++;
2060 else {
2061 while(!strchr(sdelims,*d) && *d != EOL) d++;
2062 while(strchr(s1delims,*d) && *d != EOL) d++;
2063 }
2064 mk = cur_pos;
2065 blen = d-mk;
2066 block_put();
2067 /* delete word and save to undo buf */
2068 file_resize(d, cur_pos);
2069 flag[SHW]=1;
2070 }
2071
2072 /* insert tab char */
key_tab(int tabi)2073 void key_tab(int tabi)
2074 {
2075 if(flag[BLK]) {
2076 key_delete();
2077 }
2078
2079 if(flag[TAB]){
2080 do key_normal(BLNK);
2081 while((xtru%tabsize) != 1 && *cur_pos != EOL);
2082 } else {
2083 key_normal('\t');
2084 }
2085 }
2086
2087 /* insert newline, increase line count */
key_return()2088 void key_return()
2089 {
2090 char *s = cur_pos;
2091
2092 /* reset marked block on char entry */
2093 /* JPD: disable this behaviour !
2094 if(flag[BLK]) {
2095 key_delete();
2096 s = cur_pos;
2097 }
2098 else
2099 */
2100 if(flag[OVR] ) {
2101 cursor_down();
2102 goto_x(1);
2103 return;
2104 }
2105 file_resize(s, s+1);
2106 goto_x(1);
2107 *s = EOL;
2108 /* save newly inserted EOL to undo buf */
2109 u_ins(s, 1);
2110 ytot++;
2111 /* get prev line_start */
2112 s = line_start+1;
2113 cursor_down();
2114 goto_x(1); /* ensure visible cursor */
2115 if(flag[IND]) {
2116 int i=0;
2117 /* count spaces and tabs */
2118 while(s[i] == BLNK || s[i] == '\t') i++;
2119 if(i){ /* and only if */
2120 file_resize(line_start+1, line_start+1+i);
2121 memcpy(line_start+1,s, sizeof(char) * i);
2122 /* save undo info */
2123 u_ins(line_start+1, i);
2124 x_offset += i;
2125 goto_x(i+1);
2126 }
2127 }
2128 flag[SHW]=1;
2129 }
2130
2131 /* everything ASCII else */
key_normal(int key)2132 void key_normal(int key)
2133 {
2134 char *s=line_start+x_offset;
2135 int xtmp;
2136
2137 /* reset marked block on char entry */
2138 if(flag[BLK]) { key_delete(); s = cur_pos; }
2139
2140 if(flag[OVR] && *s != EOL) {
2141 /* save old overwrite char to undo buf */
2142 u_del(s, 1);
2143 putch(*s = key);
2144 flag[CHG] = 1;
2145 }
2146 else {
2147 file_resize(s, s+1);
2148 *s = key;
2149 flag[SHW] =1 ;
2150 }
2151 cursor_right();
2152 /* save new overwrite/insert char to undo buf */
2153 u_ins(s, 1);
2154
2155 if(!flag[FIL] || xtru < screen_width) return;
2156
2157 xtmp = block_fill(); /* cursor_down */
2158 }
2159
2160 /* simple, aint it? */
rec_macro(int k)2161 void rec_macro(int k)
2162 {
2163
2164 if(k & 0xff00) bell(); /* beep&discard non ASCII, ie func keys */
2165 else /* else record key */
2166 #ifdef X11
2167 *pmbuf++ = keve->state & ControlMask ? k & 0x1f: k;
2168 #else
2169 *pmbuf++ = k;
2170 #endif
2171 }
2172
2173 /* turn on macro recording or play back macro */
key_macros(int record)2174 void key_macros(int record)
2175 {
2176 char *s=mbuf;
2177 int k;
2178
2179 if(!record) { /* play macro back */
2180 if(*s == 0) { bell(); return; }; /* ding user on empty mbuf */
2181 doCtrlX = 0; /* turn off control key state from ^K */
2182 #ifdef X11
2183 keve->state = 0; /* turn off control key state from ^P */
2184 #endif
2185 while(*s != 0) {
2186 k = 255 & *s++;
2187 switch(executive) {
2188 case MAIN:
2189 main_exec(k);
2190 break;
2191 case DIALOG:
2192 dialog(k);
2193 break;
2194 case OPTIONS:
2195 options(k);
2196 break;
2197 }
2198 }
2199 flag[SHW] = 1;
2200 return;
2201 }
2202 /* else toggle recording on/off */
2203 flag[REC] ^= 1;
2204 show_top();
2205 if(!flag[REC]) { /* terminal condition */
2206 pmbuf[-2] = 0; /* backup over ^K^M & terminate macro with a 0x0 */
2207 pmbuf = mbuf; /* reset record pointer to start of mbuf */
2208 }
2209 }
2210
2211 #ifdef GREEK
key_greek(int key)2212 void key_greek(int key)
2213 {
2214 unsigned char c;
2215 char *seq = NULL;
2216 int i, l;
2217 c = key | 0x40;
2218 if (c>='a' && c<='z')
2219 seq = greek_letter[c-'a'];
2220 if (c>='A' && c<='Z')
2221 seq = greek_letter[c-'A'];
2222 if (seq) {
2223 key_normal('\\');
2224 if (*seq=='!') {
2225 ++seq;
2226 if (var_greek && c>='a') {
2227 key_normal('v');
2228 key_normal('a');
2229 key_normal('r');
2230 }
2231 }
2232 l = strlen(seq);
2233 if (c>='a')
2234 for (i=0; i<l; i++) key_normal(tolower(seq[i]));
2235 else
2236 for (i=0; i<l; i++) key_normal(seq[i]);
2237 }
2238 var_greek = (c == 'v' || c=='V');
2239 }
2240 #endif
2241
2242 #ifndef MINIMAL
key_binding(int key)2243 void key_binding(int key)
2244 {
2245 char b[1024];
2246 if (key=='!') {
2247 run();
2248 return;
2249 }
2250 if (key=='?') {
2251 show_help(1);
2252 return;
2253 }
2254 if (key>=0x20) key = (key|0x60)-'a';
2255 if (key>=0 && key<26) if (binding[key]) {
2256 sprintf(b, binding[key], (cfdpath? cfdpath : "./"), ewin.name);
2257 SYSTEM(b);
2258 }
2259 }
2260 #endif
2261
2262
2263