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