1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: usreditemacs.c
6  * User interface tool: EMACS-like text window handler
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 /*
33  * This EMACS-like text editor accepts the following commands:
34  * ^A     cursor to start-of-line
35  * ^B     backup one character
36  * ^D     delete the next character (cannot delete line breaks)
37  * ^E     cursor to end-of-line
38  * ^F     forward one character
39  * ^G     flush state (and force evaluation of changed line)
40  * ^H     delete the previous character (cannot delete line breaks)
41  * ^K     delete to end-of-line (or kill line if on a null line)
42  * ^L     redraw screen
43  * RETURN insert new line (only if at end of line)
44  * ^N     next line
45  * ^O     insert new line (only if at beginning of line)
46  * ^P     previous line
47  * ^R     reverse search
48  * ^S     forward search
49  * ^V     shift screen up one page
50  * ^X^V   read a text file from disk (you are prompted for the file name)
51  * ^X^W   write the text file to disk (you are prompted for the file name)
52  * ^Xd    terminate this editor window
53  * ^Y     restore line deleted with ^K
54  * ^Z     shift screen up one line
55  * DEL    delete the previous character (cannot delete line breaks)
56  * M(B)   backup one word
57  * M(D)   delete the next word (cannot delete line breaks)
58  * M(F)   forward one word
59  * M(H)   delete the previous word (cannot delete line breaks)
60  * M(V)   shift screen down one page
61  * M(X)   execute an Electric command
62  * M(Z)   shift screen down one line
63  * M(<)   cursor to beginning of file
64  * M(>)   cursor to end of file
65  * M(DEL) delete the previous word (cannot delete line breaks)
66  *
67  * All printing characters "self-insert"
68  * Meta characters can be typed by holding the META key or by prefixing
69  * the character with an ESCAPE.
70  * In popup editor windows, all commands that would create a new line
71  * cause the editor to exit
72  */
73 
74 #include "global.h"
75 #include "egraphics.h"
76 #include "usr.h"
77 #include "usreditemacs.h"
78 
79 #define CTLA   01			/* ^A */
80 #define CTLB   02			/* ^B */
81 #define CTLC   03			/* ^C */
82 #define CTLD   04			/* ^D */
83 #define CTLE   05			/* ^E */
84 #define CTLF   06			/* ^F */
85 #define CTLG   07			/* ^G */
86 #define CTLH  010			/* ^H */
87 #define CTLK  013			/* ^K */
88 #define CTLL  014			/* ^L */
89 #define CTLN  016			/* ^N */
90 #define CTLO  017			/* ^O */
91 #define CTLP  020			/* ^P */
92 #define CTLR  022			/* ^R */
93 #define CTLS  023			/* ^S */
94 #define CTLV  026			/* ^V */
95 #define CTLW  027			/* ^W */
96 #define CTLX  030			/* ^X */
97 #define CTLY  031			/* ^Y */
98 #define CTLZ  032			/* ^Z */
99 
100 /* the bits in us_lastemacschar */
101 #define CONTROLX 1			/* ^X was last character typed */
102 #define ESCAPE   2			/* ESCAPE was last character typed */
103 
104 #define HEADERLINES 2
105 
106 extern GRAPHICS us_ebox, us_menutext, us_menufigs;
107 
108 INTBIG          us_lastemacschar;		/* state of last character typed */
109 static INTBIG   us_twid, us_thei;		/* size of a single letter */
110 static INTBIG   us_editemacsfont;		/* font size for editor */
111 static CHAR    *us_killbuf;				/* saved line when ^K is done */
112 static INTBIG   us_killbufchars = 0;	/* characters in kill buffer */
113 static CHAR    *us_searchbuf = 0;		/* search string for ^S and ^R */
114 
115 /* prototypes for local routines */
116 static void us_editemacsgotbutton(WINDOWPART*, INTBIG, INTBIG, INTBIG);
117 static void us_editemacsredraweditor(WINDOWPART*);
118 static BOOLEAN us_editemacsimplementchar(WINDOWPART*, INTBIG, BOOLEAN, BOOLEAN);
119 static BOOLEAN us_editemacsbackupchar(WINDOWPART*, BOOLEAN);
120 static BOOLEAN us_editemacsadvancechar(WINDOWPART*, BOOLEAN);
121 static void us_editemacsdeletechar(WINDOWPART*, BOOLEAN fromuser);
122 static void us_editemacsshiftscreenup(WINDOWPART*);
123 static void us_editemacsshiftscreendown(WINDOWPART*);
124 static void us_editemacsensuretextshown(WINDOWPART*, INTBIG);
125 static void us_editemacsredrawscreen(WINDOWPART*);
126 static void us_editemacsredrawline(WINDOWPART*, INTBIG);
127 static void us_editemacssetheader(WINDOWPART*, CHAR*);
128 static void us_editemacsflashcursor(WINDOWPART*);
129 static void us_editemacsoffhighlight(WINDOWPART*);
130 static void us_editemacscleanupline(WINDOWPART*, INTBIG);
131 static void us_editemacsworkingoncurline(EDITOR*);
132 static void us_editemacsaddmorelines(EDITOR*);
133 static void us_editemacsaddmorechars(EDITOR*, INTBIG);
134 static void us_editemacsgetbuffers(EDITOR*);
135 static void us_editemacsmovebox(WINDOWPART*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
136 static void us_editemacsclearbox(WINDOWPART*, INTBIG, INTBIG, INTBIG, INTBIG);
137 static void us_editemacsinvertbox(WINDOWPART*, INTBIG, INTBIG, INTBIG, INTBIG);
138 static void us_editemacstext(WINDOWPART*, CHAR*, INTBIG, INTBIG);
139 static void us_editemacsdosearch(WINDOWPART *win, CHAR *str, BOOLEAN reverse,
140 			BOOLEAN fromtop, BOOLEAN casesensitive, BOOLEAN fromuser);
141 static CHAR us_editemacsnextvalidcharacter(EDITOR *e);
142 
143 /******************** INTERFACE FOR TEXT WINDOW ********************/
144 
145 /*
146  * routine to convert window "oriwin" to an EMACS editor.  If "oriwin" is
147  * NOWINDOWPART, create a popup window with one line.  The window header is in
148  * "header".  The number of characters and lines are placed in "chars" and
149  * "lines".  Returns the window (NOWINDOWPART if the editor cannot be started).
150  */
us_editemacsmakeeditor(WINDOWPART * oriwin,CHAR * header,INTBIG * chars,INTBIG * lines)151 WINDOWPART *us_editemacsmakeeditor(WINDOWPART *oriwin, CHAR *header, INTBIG *chars, INTBIG *lines)
152 {
153 	INTBIG i, x, y;
154 	UINTBIG descript[TEXTDESCRIPTSIZE];
155 	INTBIG swid, shei, pwid;
156 	REGISTER EDITOR *e;
157 	REGISTER VARIABLE *var;
158 	REGISTER WINDOWPART *win;
159 
160 	/* if no window exists, create one as a popup */
161 	win = oriwin;
162 	if (win == NOWINDOWPART)
163 	{
164 		getpaletteparameters(&swid, &shei, &pwid);
165 		if (el_curwindowpart == NOWINDOWPART)
166 		{
167 			x = swid / 2;
168 			y = shei / 2;
169 		} else
170 		{
171 			(void)getxy(&x, &y);
172 			x = applyxscale(el_curwindowpart, x-el_curwindowpart->screenlx) +
173 				el_curwindowpart->uselx;
174 			y = applyyscale(el_curwindowpart, y-el_curwindowpart->screenly) +
175 				el_curwindowpart->usely;
176 		}
177 
178 		/* create a window that covers the popup */
179 		startobjectchange((INTBIG)us_tool, VTOOL);
180 		win = newwindowpart(x_("popup"), el_curwindowpart);
181 		win->uselx = maxi(x-200, 0);
182 		win->usely = maxi(y-us_thei-1, 0);
183 		win->usehx = mini(win->uselx+400, swid-1);
184 		win->usehy = mini(win->usely+us_thei*(HEADERLINES+1)+3, shei-1);
185 		win->screenlx = win->uselx;
186 		win->screenhx = win->usehx;
187 		win->screenly = win->usely;
188 		win->screenhy = win->usehy;
189 		computewindowscale(win);
190 		win->state = (win->state & ~WINDOWTYPE) | POPTEXTWINDOW;
191 	} else
192 	{
193 		if ((win->state&WINDOWTYPE) == DISPWINDOW)
194 		{
195 			win->usehx += DISPLAYSLIDERSIZE;
196 			win->usely -= DISPLAYSLIDERSIZE;
197 		}
198 		win->state = (win->state & ~(WINDOWTYPE|WINDOWMODE)) | TEXTWINDOW;
199 	}
200 
201 	win->curnodeproto = NONODEPROTO;
202 	win->buttonhandler = us_editemacsgotbutton;
203 	win->charhandler = us_editemacsgotchar;
204 	win->termhandler = us_editemacseditorterm;
205 	win->redisphandler = us_editemacsredraweditor;
206 	win->changehandler = 0;
207 	win->screenlx = win->uselx;   win->screenhx = win->usehx;
208 	win->screenly = win->usely;   win->screenhy = win->usehy;
209 	computewindowscale(win);
210 
211 	/*
212 	 * the font that is used by the editor is the fixed-width font, TXTEDITOR.
213 	 * This can be changed by setting the variable "USER_textedit_font" on the user tool
214 	 * object.  The value is the point size minus 4 divided by 2 (the value 0 is the
215 	 * default font TXTEDITOR).  For example, to set the font to be 14 points, type:
216 	 *     -var set tool:user.USER_textedit_font 5
217 	 */
218 	us_editemacsfont = TXTEDITOR;
219 	var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_textedit_font"));
220 	if (var != NOVARIABLE && var->addr >= 4)
221 		us_editemacsfont = var->addr;
222 	TDCLEAR(descript);
223 	TDSETSIZE(descript, us_editemacsfont);
224 	screensettextinfo(win, NOTECHNOLOGY, descript);
225 	screengettextsize(win, x_("X"), &us_twid, &us_thei);
226 
227 	/* create a new editor object */
228 	e = us_alloceditor();
229 	if (e == NOEDITOR) return(NOWINDOWPART);
230 	e->state = (e->state & ~(EDITORTYPE|EGRAPHICSOFF|LINESFIXED)) | EMACSEDITOR;
231 	(void)allocstring(&e->header, header, us_tool->cluster);
232 	e->highlightedline = -1;
233 	us_lastemacschar = 0;
234 	e->curline = e->curchar = 0;
235 	e->working = -1;
236 	e->firstline = 0;
237 	e->swid = win->usehx - win->uselx - 2;
238 	e->shei = win->usehy - win->usely - us_thei*HEADERLINES - 1;
239 	e->offx = win->uselx + 1;
240 	e->revy = e->shei + win->usely + 1;
241 	*chars = e->screenchars = e->swid / us_twid;
242 	*lines = e->screenlines = e->shei / us_thei;
243 
244 	/* turn this window into an EMACS editor */
245 	if ((e->state&EDITORINITED) == 0)
246 	{
247 		/* first time: allocate buffers */
248 		e->state |= EDITORINITED;
249 		e->maxlines = e->screenlines;
250 		e->mostchars = e->screenchars;
251 		e->textarray = (CHAR **)emalloc((e->maxlines * (sizeof (CHAR *))),
252 			us_tool->cluster);
253 		if (e->textarray == 0) ttyputnomemory();
254 		e->maxchars = (INTBIG *)emalloc((e->maxlines * SIZEOFINTBIG), us_tool->cluster);
255 		if (e->maxchars == 0) ttyputnomemory();
256 		us_editemacsgetbuffers(e);
257 		for(i=0; i<e->maxlines; i++)
258 		{
259 			e->textarray[i] = (CHAR *)emalloc((e->screenchars+1) * SIZEOFCHAR, us_tool->cluster);
260 			if (e->textarray[i] == 0) ttyputnomemory();
261 			e->textarray[i][0] = 0;
262 			e->maxchars[i] = e->screenchars;
263 		}
264 	} else
265 	{
266 		/* make sure buffers cover the screen */
267 		while (e->screenlines > e->maxlines) us_editemacsaddmorelines(e);
268 		for(i=0; i<e->maxlines; i++)
269 		{
270 			e->textarray[i][0] = 0;
271 			while (e->screenchars > e->maxchars[i])
272 				us_editemacsaddmorechars(e, i);
273 		}
274 	}
275 
276 	/* now finish initializing window */
277 	win->editor = e;
278 	if (oriwin != NOWINDOWPART)
279 	{
280 		/* clear window and write header */
281 		us_editemacssetheader(win, header);
282 
283 		/* show initial cursor */
284 		us_editemacsflashcursor(win);
285 	} else
286 	{
287 		/* finish initializing window if it is a new popup one */
288 		e->savedbox = screensavebox(win, maxi(e->offx-2,0),
289 			e->offx+e->swid+2, maxi(e->revy-e->shei-2,0),
290 				e->revy+us_thei*HEADERLINES+1);
291 		endobjectchange((INTBIG)us_tool, VTOOL);
292 	}
293 	return(win);
294 }
295 
us_freeedemacsmemory(void)296 void us_freeedemacsmemory(void)
297 {
298 	if (us_searchbuf != 0) efree(us_searchbuf);
299 }
300 
301 /*
302  * routine to free all memory associated with this editor
303  */
us_editemacsterminate(EDITOR * e)304 void us_editemacsterminate(EDITOR *e)
305 {
306 	REGISTER INTBIG i;
307 
308 	for(i=0; i<e->maxlines; i++)
309 		efree((CHAR *)e->textarray[i]);
310 	efree((CHAR *)e->textarray);
311 	efree((CHAR *)e->maxchars);
312 	efree((CHAR *)e->formerline);
313 	efree((CHAR *)us_killbuf);
314 	us_killbufchars = 0;
315 }
316 
317 /*
318  * routine to return the total number of valid lines in the edit buffer
319  */
us_editemacstotallines(WINDOWPART * win)320 INTBIG us_editemacstotallines(WINDOWPART *win)
321 {
322 	REGISTER INTBIG i;
323 	REGISTER EDITOR *e;
324 
325 	e = win->editor;
326 	if (e == NOEDITOR) return(0);
327 	for(i = e->maxlines-1; i >= 0; i--) if (e->textarray[i][0] != 0) break;
328 	return(i+1);
329 }
330 
331 /*
332  * routine to get the string on line "lindex" (0 based).  A negative line
333  * returns the current line.  Returns -1 if the index is beyond the file limit
334  */
us_editemacsgetline(WINDOWPART * win,INTBIG lindex)335 CHAR *us_editemacsgetline(WINDOWPART *win, INTBIG lindex)
336 {
337 	REGISTER EDITOR *e;
338 
339 	e = win->editor;
340 	if (e == NOEDITOR) return(x_(""));
341 	if (lindex < 0) lindex = e->curline;
342 	if (lindex >= e->maxlines) return(NOSTRING);
343 	return(e->textarray[lindex]);
344 }
345 
346 /*
347  * routine to add line "str" to the text cell to become line "lindex"
348  */
us_editemacsaddline(WINDOWPART * win,INTBIG lindex,CHAR * str)349 void us_editemacsaddline(WINDOWPART *win, INTBIG lindex, CHAR *str)
350 {
351 	REGISTER CHAR *pt;
352 	REGISTER INTBIG savedline, savedchar;
353 	REGISTER EDITOR *e;
354 
355 	e = win->editor;
356 	if (e == NOEDITOR) return;
357 	us_editemacsflashcursor(win);
358 	savedchar = e->curchar;   savedline = e->curline;
359 	e->curline = lindex;   e->curchar = 0;
360 	(void)us_editemacsimplementchar(win, CTLO, FALSE, FALSE);
361 	if (str[0] == 0) (void)us_editemacsimplementchar(win, ' ', FALSE, FALSE); else
362 		for(pt = str; *pt != 0; pt++)
363 			(void)us_editemacsimplementchar(win, *pt, FALSE, FALSE);
364 	e->curchar = savedchar;   e->curline = savedline;
365 	us_editemacsflashcursor(win);
366 }
367 
368 /*
369  * routine to replace the line number "lindex" with the string "str".
370  */
us_editemacsreplaceline(WINDOWPART * win,INTBIG lindex,CHAR * str)371 void us_editemacsreplaceline(WINDOWPART *win, INTBIG lindex, CHAR *str)
372 {
373 	REGISTER CHAR *pt;
374 	REGISTER INTBIG savedline, savedchar;
375 	REGISTER EDITOR *e;
376 
377 	e = win->editor;
378 	if (e == NOEDITOR) return;
379 	us_editemacsflashcursor(win);
380 	savedchar = e->curchar;   savedline = e->curline;
381 	if (e->curline == lindex) savedchar = 0;
382 	e->curline = lindex;   e->curchar = 0;
383 	if (e->textarray[lindex][0] != 0)
384 		(void)us_editemacsimplementchar(win, CTLK, FALSE, FALSE);
385 	for(pt = str; *pt != 0; pt++)
386 		(void)us_editemacsimplementchar(win, *pt, FALSE, FALSE);
387 	e->curchar = savedchar;   e->curline = savedline;
388 	us_editemacsflashcursor(win);
389 }
390 
391 /*
392  * routine to delete line number "lindex"
393  */
us_editemacsdeleteline(WINDOWPART * win,INTBIG lindex)394 void us_editemacsdeleteline(WINDOWPART *win, INTBIG lindex)
395 {
396 	REGISTER INTBIG savedchar, savedline;
397 	REGISTER EDITOR *e;
398 
399 	e = win->editor;
400 	if (e == NOEDITOR) return;
401 	us_editemacsflashcursor(win);
402 	savedchar = e->curchar;   savedline = e->curline;
403 	if (e->curline == lindex) { savedline++;   savedchar = 0; }
404 	e->curline = lindex;   e->curchar = 0;
405 	if (e->textarray[lindex][0] != 0)
406 		(void)us_editemacsimplementchar(win, CTLK, FALSE, FALSE);
407 	(void)us_editemacsimplementchar(win, CTLK, FALSE, FALSE);
408 	e->curchar = savedchar;   e->curline = savedline;
409 	us_editemacsflashcursor(win);
410 }
411 
412 /*
413  * routine to highlight lines "lindex" to "hindex" in the text window
414  */
us_editemacshighlightline(WINDOWPART * win,INTBIG lindex,INTBIG hindex)415 void us_editemacshighlightline(WINDOWPART *win, INTBIG lindex, INTBIG hindex)
416 {
417 	REGISTER EDITOR *e;
418 
419 	e = win->editor;
420 	if (e == NOEDITOR) return;
421 	us_editemacsoffhighlight(win);
422 	if ((e->state&EGRAPHICSOFF) != 0) return;
423 	if (hindex != lindex)
424 		ttyputmsg(_("EMACS can only highlight a single line"));
425 	e->highlightedline = lindex;
426 	us_editemacsensuretextshown(win, e->highlightedline);
427 	if (e->highlightedline-e->firstline < e->screenlines &&
428 		e->highlightedline >= e->firstline)
429 			us_editemacsinvertbox(win, 0, e->highlightedline-e->firstline,
430 				e->swid, us_thei);
431 }
432 
433 /*
434  * routine to stop the graphic display of changes (for batching)
435  */
us_editemacssuspendgraphics(WINDOWPART * win)436 void us_editemacssuspendgraphics(WINDOWPART *win)
437 {
438 	REGISTER EDITOR *e;
439 
440 	e = win->editor;
441 	if (e == NOEDITOR) return;
442 	e->state |= EGRAPHICSOFF;
443 }
444 
445 /*
446  * routine to restart the graphic display of changes and redisplay (for batching)
447  */
us_editemacsresumegraphics(WINDOWPART * win)448 void us_editemacsresumegraphics(WINDOWPART *win)
449 {
450 	REGISTER EDITOR *e;
451 
452 	e = win->editor;
453 	if (e == NOEDITOR) return;
454 	e->state &= ~EGRAPHICSOFF;
455 	us_editemacsredrawscreen(win);
456 	us_editemacsflashcursor(win);
457 }
458 
459 /*
460  * routine to write the text file to "file"
461  */
us_editemacswritetextfile(WINDOWPART * win,CHAR * file)462 void us_editemacswritetextfile(WINDOWPART *win, CHAR *file)
463 {
464 	REGISTER EDITOR *e;
465 	REGISTER INTBIG i, j;
466 	REGISTER FILE *f;
467 	CHAR *truename;
468 
469 	e = win->editor;
470 	if (e == NOEDITOR) return;
471 
472 	/* find the last line */
473 	for(j = e->maxlines-1; j >= 0; j--)
474 		if (e->textarray[j][0] != 0) break;
475 	if (j < 0)
476 	{
477 		ttyputerr(_("File is empty"));
478 		return;
479 	}
480 
481 	f = xcreate(file, el_filetypetext, _("Text File"), &truename);
482 	if (f == NULL)
483 	{
484 		if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
485 		return;
486 	}
487 
488 	for(i=0; i<=j; i++) xprintf(f, x_("%s\n"), e->textarray[i]);
489 	xclose(f);
490 	ttyputmsg(_("%s written"), truename);
491 }
492 
493 /*
494  * routine to read the text file "file"
495  */
us_editemacsreadtextfile(WINDOWPART * win,CHAR * file)496 void us_editemacsreadtextfile(WINDOWPART *win, CHAR *file)
497 {
498 	REGISTER EDITOR *e;
499 	REGISTER INTBIG linecount, i, c;
500 	REGISTER FILE *f;
501 	CHAR *filename;
502 
503 	e = win->editor;
504 	if (e == NOEDITOR) return;
505 
506 	/* get the file */
507 	f = xopen(file, el_filetypetext, x_(""), &filename);
508 	if (f == NULL)
509 	{
510 		ttyputerr(_("Cannot read %s"), file);
511 		return;
512 	}
513 	ttyputmsg(_("Reading %s"), file);
514 
515 	/* erase the text that is there */
516 	e->state |= EGRAPHICSOFF;
517 	for(i=0; i<e->maxlines; i++)
518 		e->textarray[i][0] = 0;
519 	e->curline = e->curchar = e->firstline = 0;
520 
521 	/* read the file */
522 	for(;;)
523 	{
524 		c = xgetc(f);
525 		if (c == EOF) break;
526 		(void)us_editemacsimplementchar(win, c&0177, FALSE, FALSE);
527 	}
528 	xclose(f);
529 
530 	/* announce the new text */
531 	if (win->changehandler != 0)
532 	{
533 		linecount = e->curline;
534 		if (e->curchar != 0) linecount++;
535 		(*win->changehandler)(win, REPLACEALLTEXT, x_(""), (CHAR *)e->textarray,
536 			linecount);
537 	}
538 
539 	/* restore the display */
540 	e->state &= ~EGRAPHICSOFF;
541 	us_editemacsredrawscreen(win);
542 }
543 
544 /******************** WINDOW CONTROL ********************/
545 
us_editemacseditorterm(WINDOWPART * win)546 void us_editemacseditorterm(WINDOWPART *win)
547 {
548 	REGISTER EDITOR *e;
549 
550 	e = win->editor;
551 	if (e == NOEDITOR) return;
552 
553 	us_editemacsshipchanges(win);
554 	if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
555 	{
556 		screenrestorebox(e->savedbox, 0);
557 	}
558 }
559 
us_editemacsgotbutton(WINDOWPART * win,INTBIG but,INTBIG x,INTBIG y)560 void us_editemacsgotbutton(WINDOWPART *win, INTBIG but, INTBIG x, INTBIG y)
561 {
562 	REGISTER EDITOR *e;
563 	REGISTER INTBIG xc, yc, len;
564 
565 	/* changes to the mouse-wheel are handled by the user interface */
566 	if (wheelbutton(but))
567 	{
568 		us_buttonhandler(win, but, x, y);
569 		return;
570 	}
571 	ttynewcommand();
572 
573 	e = win->editor;
574 	if (e == NOEDITOR) return;
575 	xc = (x-e->offx) / us_twid;
576 	if (xc < 0) xc = 0;
577 	yc = (e->revy-y) / us_thei + e->firstline;
578 	if (yc < e->firstline) yc = e->firstline;
579 	if (yc >= e->maxlines) yc = e->maxlines-1;
580 	len = estrlen(e->textarray[yc]);
581 	if (xc > len) xc = len;
582 	us_editemacsflashcursor(win);
583 	e->curchar = xc;
584 	e->curline = yc;
585 	us_editemacsflashcursor(win);
586 }
587 
us_editemacsredraweditor(WINDOWPART * win)588 void us_editemacsredraweditor(WINDOWPART *win)
589 {
590 	REGISTER INTBIG i;
591 	REGISTER EDITOR *e;
592 
593 	e = win->editor;
594 	if (e == NOEDITOR) return;
595 
596 	/* compute window extents */
597 	e->swid = win->usehx - win->uselx - 2;
598 	e->shei = win->usehy - win->usely - us_thei*HEADERLINES - 1;
599 	e->offx = win->uselx + 1;
600 	e->revy = e->shei + win->usely + 1;
601 	e->screenlines = e->shei / us_thei;
602 	e->screenchars = e->swid / us_twid;
603 
604 	while (e->screenlines > e->maxlines) us_editemacsaddmorelines(e);
605 	for(i=0; i<e->maxlines; i++)
606 	{
607 		while (e->screenchars > e->maxchars[i])
608 			us_editemacsaddmorechars(e, i);
609 	}
610 
611 	us_editemacsredrawscreen(win);
612 	us_editemacsflashcursor(win);
613 }
614 
615 /*
616  * keyboard interrupt routine for the text window
617  */
us_editemacsgotchar(WINDOWPART * win,INTSML i,INTBIG special)618 BOOLEAN us_editemacsgotchar(WINDOWPART *win, INTSML i, INTBIG special)
619 {
620 	REGISTER EDITOR *e;
621 
622 	e = win->editor;
623 	if (e == NOEDITOR) return(TRUE);
624 
625 	/* convert arrow keys to movement keys */
626 	if ((special&SPECIALKEYDOWN) != 0)
627 	{
628 		switch ((special&SPECIALKEY) >> SPECIALKEYSH)
629 		{
630 			case SPECIALKEYARROWL: i = 'b';  special = ACCELERATORDOWN;   break;
631 			case SPECIALKEYARROWR: i = 'f';  special = ACCELERATORDOWN;   break;
632 			case SPECIALKEYARROWU: i = 'p';  special = ACCELERATORDOWN;   break;
633 			case SPECIALKEYARROWD: i = 'n';  special = ACCELERATORDOWN;   break;
634 		}
635 	}
636 	if ((special&ACCELERATORDOWN) != 0)
637 	{
638 		us_editemacsflashcursor(win);
639 #ifndef MACOS
640 		i = i - 'a' + CTLA;
641 		if (us_editemacsimplementchar(win, i, FALSE, TRUE)) return(TRUE);
642 #else
643 		if (us_editemacsimplementchar(win, i, TRUE, TRUE)) return(TRUE);
644 #endif
645 		us_editemacsflashcursor(win);
646 	} else
647 	{
648 		us_editemacsflashcursor(win);
649 		if (us_editemacsimplementchar(win, i, FALSE, TRUE)) return(TRUE);
650 		us_editemacsflashcursor(win);
651 	}
652 	setactivity(_("EMACS Editing"));
653 	return(FALSE);
654 }
655 
us_editemacscut(WINDOWPART * w)656 void us_editemacscut(WINDOWPART *w) { ttybeep(SOUNDBEEP, TRUE); }
657 
us_editemacscopy(WINDOWPART * w)658 void us_editemacscopy(WINDOWPART *w) { ttybeep(SOUNDBEEP, TRUE); }
659 
us_editemacspaste(WINDOWPART * w)660 void us_editemacspaste(WINDOWPART *w) { ttybeep(SOUNDBEEP, TRUE); }
661 
us_editemacsundo(WINDOWPART * w)662 void us_editemacsundo(WINDOWPART *w) { ttybeep(SOUNDBEEP, TRUE); }
663 
664 /*
665  * routine to search and/or replace text.  If "replace" is nonzero, this is
666  * a replace.  The meaning of "bits" is as follows:
667  *   1   search from top
668  *   2   replace all
669  *   4   case sensitive
670  *   8   search upwards
671  */
us_editemacssearch(WINDOWPART * w,CHAR * str,CHAR * replace,INTBIG bits)672 void us_editemacssearch(WINDOWPART *w, CHAR *str, CHAR *replace, INTBIG bits)
673 {
674 	REGISTER BOOLEAN fromtop, reverse, casesensitive;
675 
676 	if (replace != 0)
677 	{
678 		ttyputerr(_("EMACS cannot replace yet"));
679 		return;
680 	}
681 	if ((bits&1) != 0) fromtop = TRUE; else fromtop = FALSE;
682 	if ((bits&4) != 0) casesensitive = TRUE; else casesensitive = FALSE;
683 	if ((bits&8) != 0) reverse = TRUE; else reverse = FALSE;
684 	us_editemacsflashcursor(w);
685 	us_editemacsdosearch(w, str, reverse, fromtop, casesensitive, TRUE);
686 	us_editemacsflashcursor(w);
687 }
688 
us_editemacspan(WINDOWPART * win,INTBIG dx,INTBIG dy)689 void us_editemacspan(WINDOWPART *win, INTBIG dx, INTBIG dy)
690 {
691 	REGISTER EDITOR *e;
692 
693 	e = win->editor;
694 	if (e == NOEDITOR) return;
695 
696 	/* EMACS cannot handle horizontal panning */
697 	if (dx != 0) return;
698 	if (dy < 0)
699 	{
700 		if (e->firstline <= 0) return;
701 		us_editemacsflashcursor(win);
702 		e->firstline--;
703 	} else
704 	{
705 		us_editemacsflashcursor(win);
706 		e->firstline++;
707 	}
708 	us_editemacsredrawscreen(win);
709 	us_editemacsflashcursor(win);
710 }
711 
712 /******************** EDITOR CONTROL ********************/
713 
714 /*
715  * routine to implement EMACS character "i", with meta key held down if "m" is
716  * 1.  The key is issued internally if "fromuser" is zero.  Routine returns
717  * true if the editor window has been terminated.
718  */
us_editemacsimplementchar(WINDOWPART * win,INTBIG i,BOOLEAN m,BOOLEAN fromuser)719 BOOLEAN us_editemacsimplementchar(WINDOWPART *win, INTBIG i, BOOLEAN m, BOOLEAN fromuser)
720 {
721 	REGISTER EDITOR *e;
722 	INTBIG j, k, savecur, len, nextlineno, nextcharno;
723 	CHAR s[2], *pt, *nextline, ch;
724 	REGISTER void *infstr;
725 
726 	e = win->editor;
727 	if (e == NOEDITOR) return(TRUE);
728 
729 	/* make sure line highlighting is off */
730 	us_editemacsoffhighlight(win);
731 
732 	/* if ESCAPE was typed, set meta bit */
733 	if ((us_lastemacschar&ESCAPE) != 0)
734 	{
735 		m = TRUE;
736 		us_lastemacschar &= ~ESCAPE;
737 	}
738 
739 	/* separate interpreter for ^X prefix */
740 	if ((us_lastemacschar&CONTROLX) != 0)
741 	{
742 		us_lastemacschar &= ~CONTROLX;
743 
744 		/* save the text in a disk file */
745 		if (i == CTLW && !m)
746 		{
747 			if (fromuser) us_editemacsshipchanges(win);
748 			us_editemacswritetextfile(win, x_("EMACSbuffer"));
749 			return(FALSE);
750 		}
751 
752 		/* read a text from a disk file */
753 		if (i == CTLV && !m)
754 		{
755 			if (fromuser) us_editemacsshipchanges(win);
756 			pt = (CHAR *)fileselect(_("File name: "), el_filetypetext, x_(""));
757 			if (pt == 0 || *pt == 0)
758 			{
759 				us_abortedmsg();
760 				return(FALSE);
761 			}
762 			us_editemacsreadtextfile(win, pt);
763 			return(FALSE);
764 		}
765 
766 		ttyputerr(_("The sequence '^X%s' is not valid in EMACS"),
767 			us_describeboundkey((INTSML)i, (!m ? 0 : ACCELERATORDOWN), 1));
768 		return(FALSE);
769 	}
770 
771 	/* ESCAPE prefix for the next character */
772 	if (i == ESCKEY && !m)
773 	{
774 		us_lastemacschar |= ESCAPE;
775 		return(FALSE);
776 	}
777 
778 	/* ^X prefix for the next character */
779 	if (i == CTLX && !m)
780 	{
781 		us_lastemacschar |= CONTROLX;
782 		return(FALSE);
783 	}
784 
785 	/* self-insert of normal characters */
786 	if (i == '\t') i = ' ';
787 	if (i >= ' ' && i <= '~' && !m)
788 	{
789 		if (fromuser) us_editemacsworkingoncurline(e);
790 
791 		/* see if line needs to be extended */
792 		if ((INTBIG)estrlen(e->textarray[e->curline]) >= e->maxchars[e->curline])
793 			us_editemacsaddmorechars(e, e->curline);
794 
795 		/* see if new character is at end of line */
796 		if (e->textarray[e->curline][e->curchar] != 0)
797 		{
798 			/* it is not: shift letters on the line */
799 			for(j=e->maxchars[e->curline]; j>e->curchar; j--)
800 				e->textarray[e->curline][j] = e->textarray[e->curline][j-1];
801 			if (e->curline-e->firstline < e->screenlines &&
802 				e->curline >= e->firstline && e->curchar < e->screenchars-1 &&
803 					(e->state&EGRAPHICSOFF) == 0)
804 			{
805 				us_editemacsmovebox(win, e->curchar+1, e->curline-e->firstline,
806 					e->swid-e->curchar*us_twid-us_twid, us_thei, e->curchar,
807 						e->curline-e->firstline);
808 				us_editemacscleanupline(win, e->curline);
809 			}
810 		} else e->textarray[e->curline][e->curchar+1] = 0;
811 
812 		/* put the character on the display and into image memory */
813 		if (e->curline-e->firstline < e->screenlines &&
814 			e->curline >= e->firstline && e->curchar < e->screenchars &&
815 				(e->state&EGRAPHICSOFF) == 0)
816 		{
817 			us_editemacsclearbox(win, e->curchar, e->curline-e->firstline,
818 				us_twid, us_thei);
819 			s[0] = (CHAR)i;   s[1] = 0;
820 			us_editemacstext(win, s, e->curchar, e->curline-e->firstline);
821 			us_editemacscleanupline(win, e->curline);
822 		}
823 		e->textarray[e->curline][e->curchar] = (CHAR)i;
824 
825 		/* advance the character pointer */
826 		e->curchar++;
827 		return(FALSE);
828 	}
829 
830 	/* search for a string */
831 	if (i == CTLS && !m)
832 	{
833 		if (us_searchbuf == 0)
834 		{
835 			pt = ttygetlinemessages(_("Search for: "));
836 		} else
837 		{
838 			infstr = initinfstr();
839 			formatinfstr(infstr, _("Search for [%s]: "), us_searchbuf);
840 			pt = ttygetlinemessages(returninfstr(infstr));
841 		}
842 		if (pt == 0) return(FALSE);
843 		if (*pt == 0)
844 		{
845 			if (us_searchbuf == 0)
846 			{
847 				ttyputmsg(_("No previous search string"));
848 				return(FALSE);
849 			}
850 			pt = us_searchbuf;
851 		} else
852 		{
853 			if (us_searchbuf != 0) efree(us_searchbuf);
854 			(void)allocstring(&us_searchbuf, pt, us_tool->cluster);
855 		}
856 		us_editemacsdosearch(win, us_searchbuf, FALSE, FALSE, FALSE, fromuser);
857 		return(FALSE);
858 	}
859 
860 	/* reverse search for a string */
861 	if (i == CTLR && !m)
862 	{
863 		if (us_searchbuf == 0)
864 		{
865 			pt = ttygetlinemessages(_("Reverse search for: "));
866 		} else
867 		{
868 			infstr = initinfstr();
869 			formatinfstr(infstr, _("Reverse search for [%s]: "), us_searchbuf);
870 			pt = ttygetlinemessages(returninfstr(infstr));
871 		}
872 		if (pt == 0) return(FALSE);
873 		if (*pt == 0)
874 		{
875 			if (us_searchbuf == 0)
876 			{
877 				ttyputmsg(_("No previous search string"));
878 				return(FALSE);
879 			}
880 			pt = us_searchbuf;
881 		} else
882 		{
883 			if (us_searchbuf != 0) efree(us_searchbuf);
884 			(void)allocstring(&us_searchbuf, pt, us_tool->cluster);
885 		}
886 		us_editemacsdosearch(win, us_searchbuf, TRUE, FALSE, FALSE, fromuser);
887 		return(FALSE);
888 	}
889 
890 	/* delete next character on a line (cannot delete line break) */
891 	if (i == CTLD && !m)
892 	{
893 		if (fromuser) us_editemacsworkingoncurline(e);
894 		us_editemacsdeletechar(win, fromuser);
895 		return(FALSE);
896 	}
897 
898 	/* delete next word on a line (cannot delete line break) */
899 	if (i == 'd' && m)
900 	{
901 		if (fromuser) us_editemacsworkingoncurline(e);
902 
903 		/* first delete all nonalphanumeric characters */
904 		for(;;)
905 		{
906 			ch = us_editemacsnextvalidcharacter(e);
907 			if (ch == 0) break;
908 			if (isalnum(ch)) break;
909 			us_editemacsdeletechar(win, fromuser);
910 		}
911 
912 		for(;;)
913 		{
914 			us_editemacsdeletechar(win, fromuser);
915 			if (!isalnum(e->textarray[e->curline][e->curchar])) break;
916 		}
917 		return(FALSE);
918 	}
919 
920 	/* delete previous character on a line (cannot delete line break) */
921 	if ((i == CTLH || i == DELETEKEY) && !m)
922 	{
923 		if (fromuser) us_editemacsworkingoncurline(e);
924 		e->curchar--;
925 		if (e->curchar < 0)
926 		{
927 			if (e->curline <= 0) { e->curchar++;   return(FALSE); }
928 			e->curline--;
929 			e->curchar = estrlen(e->textarray[e->curline]);
930 		}
931 		us_editemacsdeletechar(win, fromuser);
932 		return(FALSE);
933 	}
934 
935 	/* delete previous word on a line (cannot delete line break) */
936 	if ((i == 'h' || i == DELETEKEY) && m)
937 	{
938 		if (fromuser) us_editemacsworkingoncurline(e);
939 
940 		/* first backwards delete all nonalphanumeric characters */
941 		for(;;)
942 		{
943 			e->curchar--;
944 			if (e->curchar < 0)
945 			{
946 				if (e->curline <= 0) { e->curchar++;   return(FALSE); }
947 				e->curline--;
948 				e->curchar = estrlen(e->textarray[e->curline]);
949 			}
950 			if (isalnum(e->textarray[e->curline][e->curchar])) break;
951 			us_editemacsdeletechar(win, fromuser);
952 		}
953 
954 		/* now backwards delete alphanumeric characters */
955 		for(;;)
956 		{
957 			us_editemacsdeletechar(win, fromuser);
958 			nextcharno = e->curchar - 1;
959 			nextlineno = e->curline;
960 			if (nextcharno < 0)
961 			{
962 				if (nextlineno <= 0) return(FALSE);
963 				nextlineno--;
964 				nextcharno = estrlen(e->textarray[nextlineno]);
965 			}
966 			if (!isalnum(e->textarray[nextlineno][nextcharno])) break;
967 			e->curchar = nextcharno;
968 			e->curline = nextlineno;
969 		}
970 		return(FALSE);
971 	}
972 
973 	/* kill to end of line (delete line if at beginning of empty line) */
974 	if (i == CTLK && !m)
975 	{
976 		if (e->curchar == 0 && e->textarray[e->curline][e->curchar] == 0)
977 		{
978 			/* exit editor if only editing one line */
979 			if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
980 			{
981 				if (fromuser) us_editemacsshipchanges(win);
982 				return(TRUE);
983 			}
984 
985 			/* cannot change number of lines if not allowed */
986 			if (fromuser && (e->state&LINESFIXED) != 0)
987 			{
988 				ttyputerr(_("Cannot delete lines in this edit session"));
989 				return(FALSE);
990 			}
991 
992 			/* delete line in memory */
993 			if (fromuser) us_editemacsshipchanges(win);
994 			savecur = e->curline;
995 			for(; e->curline < e->maxlines; e->curline++)
996 			{
997 				if (e->curline == e->maxlines-1) nextline = x_(""); else
998 					nextline = e->textarray[e->curline+1];
999 				if (estrcmp(e->textarray[e->curline], nextline) == 0) continue;
1000 				if (fromuser) us_editemacsworkingoncurline(e);
1001 				len = estrlen(nextline);
1002 				while (len > e->maxchars[e->curline])
1003 					us_editemacsaddmorechars(e, e->curline);
1004 				(void)estrcpy(e->textarray[e->curline], nextline);
1005 				if (fromuser) us_editemacsshipchanges(win);
1006 			}
1007 			e->curline = savecur;
1008 
1009 			/* delete line on the screen */
1010 			if (e->curline-e->firstline < e->screenlines-1 &&
1011 				e->curline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1012 			{
1013 				us_editemacsmovebox(win, 0, e->curline-e->firstline, e->swid,
1014 					e->shei-(e->curline-e->firstline+1)*us_thei, 0,
1015 						e->curline-e->firstline+1);
1016 				if (e->screenlines < e->maxlines)
1017 				{
1018 					us_editemacsclearbox(win, 0, e->screenlines-1, e->swid, us_thei);
1019 					us_editemacsredrawline(win, e->screenlines-1);
1020 				}
1021 			}
1022 		} else
1023 		{
1024 			if (e->textarray[e->curline][e->curchar] == 0)
1025 			{
1026 				ttyputerr(_("Can only delete entire lines"));
1027 				return(FALSE);
1028 			}
1029 
1030 			/* kill to end of line */
1031 			if (fromuser) us_editemacsworkingoncurline(e);
1032 			(void)estrcpy(us_killbuf, &e->textarray[e->curline][e->curchar]);
1033 			if (e->curline-e->firstline < e->screenlines &&
1034 				e->curline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1035 					us_editemacsclearbox(win, e->curchar, e->curline-e->firstline,
1036 						e->swid-e->curchar*us_twid, us_thei);
1037 			e->textarray[e->curline][e->curchar] = 0;
1038 		}
1039 		return(FALSE);
1040 	}
1041 
1042 	if (i == CTLY && !m)
1043 	{
1044 		for(pt = us_killbuf; *pt != 0; pt++)
1045 		{
1046 			if (*pt == CTLY || *pt == CTLK) continue;
1047 			(void)us_editemacsimplementchar(win, *pt, FALSE, fromuser);
1048 		}
1049 		return(FALSE);
1050 	}
1051 
1052 	if (i == CTLL && !m)
1053 	{
1054 		us_editemacsredrawscreen(win);
1055 		return(FALSE);
1056 	}
1057 
1058 	if (i == CTLB && !m)
1059 	{
1060 		(void)us_editemacsbackupchar(win, fromuser);
1061 		return(FALSE);
1062 	}
1063 
1064 	if (i == 'b' && m)
1065 	{
1066 		for(;;)
1067 		{
1068 			if (us_editemacsbackupchar(win, fromuser)) break;
1069 			if (isalnum(e->textarray[e->curline][e->curchar])) break;
1070 		}
1071 		for(;;)
1072 		{
1073 			if (e->curchar <= 0) break;
1074 			if (!isalnum(e->textarray[e->curline][e->curchar-1])) break;
1075 			(void)us_editemacsbackupchar(win, fromuser);
1076 		}
1077 		return(FALSE);
1078 	}
1079 
1080 	if (i == CTLF && !m)
1081 	{
1082 		/* exit editor if at end of line and only editing one line */
1083 		if (e->textarray[e->curline][e->curchar] == 0 &&
1084 			(win->state&WINDOWTYPE) == POPTEXTWINDOW)
1085 		{
1086 			if (fromuser) us_editemacsshipchanges(win);
1087 			return(TRUE);
1088 		}
1089 
1090 		(void)us_editemacsadvancechar(win, fromuser);
1091 		return(FALSE);
1092 	}
1093 
1094 	if (i == 'f' && m)
1095 	{
1096 		/* exit editor if at end of line and only editing one line */
1097 		if (e->textarray[e->curline][e->curchar] == 0 &&
1098 			(win->state&WINDOWTYPE) == POPTEXTWINDOW)
1099 		{
1100 			if (fromuser) us_editemacsshipchanges(win);
1101 			return(TRUE);
1102 		}
1103 
1104 		for(;;)
1105 		{
1106 			if (isalnum(e->textarray[e->curline][e->curchar])) break;
1107 			if (us_editemacsadvancechar(win, fromuser)) break;
1108 		}
1109 		for(;;)
1110 		{
1111 			if (us_editemacsadvancechar(win, fromuser)) break;
1112 			if (!isalnum(e->textarray[e->curline][e->curchar])) break;
1113 		}
1114 		return(FALSE);
1115 	}
1116 
1117 	if (i == CTLA && !m)
1118 	{
1119 		e->curchar = 0;
1120 		return(FALSE);
1121 	}
1122 
1123 	if (i == CTLE && !m)
1124 	{
1125 		for(j=0; e->textarray[e->curline][j] != 0; j++) ;
1126 		e->curchar = j;
1127 		return(FALSE);
1128 	}
1129 
1130 	if (i == CTLG && !m)
1131 	{
1132 		ttyputmsg(_("Analyzing this line"));
1133 		if (fromuser) us_editemacsshipchanges(win);
1134 		return(FALSE);
1135 	}
1136 
1137 	if (i == CTLP && !m)
1138 	{
1139 		/* exit editor if only editing one line */
1140 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1141 		{
1142 			if (fromuser) us_editemacsshipchanges(win);
1143 			return(TRUE);
1144 		}
1145 
1146 		if (e->curline <= 0) return(FALSE);
1147 		if (fromuser)
1148 		{
1149 			us_editemacsshipchanges(win);
1150 			if (e->curline == e->firstline && e->firstline > 0)
1151 				us_editemacsshiftscreendown(win);
1152 		}
1153 		e->curline--;
1154 		for(j=0; e->textarray[e->curline][j] != 0; j++) ;
1155 		if (e->curchar > j) e->curchar = j;
1156 		return(FALSE);
1157 	}
1158 
1159 	if (i == CTLN && !m)
1160 	{
1161 		/* exit editor if only editing one line */
1162 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1163 		{
1164 			if (fromuser) us_editemacsshipchanges(win);
1165 			return(TRUE);
1166 		}
1167 
1168 		if (e->curline >= e->maxlines-1) us_editemacsaddmorelines(e);
1169 		if (fromuser)
1170 		{
1171 			us_editemacsshipchanges(win);
1172 			if (e->curline == e->firstline+e->screenlines-1)
1173 				us_editemacsshiftscreenup(win);
1174 		}
1175 		e->curline++;
1176 		for(j=0; e->textarray[e->curline][j] != 0; j++) ;
1177 		if (e->curchar > j) e->curchar = j;
1178 		return(FALSE);
1179 	}
1180 
1181 	if (i == CTLZ && !m)
1182 	{
1183 		/* exit editor if only editing one line */
1184 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1185 		{
1186 			if (fromuser) us_editemacsshipchanges(win);
1187 			return(TRUE);
1188 		}
1189 
1190 		us_editemacsshiftscreenup(win);
1191 		if (fromuser && e->curline == e->firstline) e->curline++;
1192 		return(FALSE);
1193 	}
1194 
1195 	if (i == 'z' && m)
1196 	{
1197 		/* exit editor if only editing one line */
1198 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1199 		{
1200 			if (fromuser) us_editemacsshipchanges(win);
1201 			return(TRUE);
1202 		}
1203 
1204 		if (e->firstline <= 0) return(FALSE);
1205 		us_editemacsshiftscreendown(win);
1206 		if (fromuser && e->curline == e->firstline+e->screenlines-1)
1207 			e->curline--;
1208 		return(FALSE);
1209 	}
1210 
1211 	if (i == CTLV && !m)
1212 	{
1213 		/* exit editor if only editing one line */
1214 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1215 		{
1216 			if (fromuser) us_editemacsshipchanges(win);
1217 			return(TRUE);
1218 		}
1219 
1220 		j = e->screenlines / 5 * 4;
1221 		e->firstline += j;
1222 		if ((e->state&EGRAPHICSOFF) == 0)
1223 		{
1224 			us_editemacsmovebox(win, 0, 0, e->swid, us_thei*(e->screenlines-j), 0, j);
1225 			us_editemacsclearbox(win, 0, e->screenlines-j, e->swid, us_thei*j);
1226 			for(k=0; k<j; k++)
1227 			{
1228 				if (e->screenlines-j+k+e->firstline < e->maxlines)
1229 					us_editemacsredrawline(win, e->screenlines-j+k);
1230 			}
1231 		}
1232 		if (fromuser && e->curline < e->firstline)
1233 		{
1234 			us_editemacsshipchanges(win);
1235 			e->curline = e->firstline + e->screenlines/2;
1236 		}
1237 		return(FALSE);
1238 	}
1239 
1240 	if (i == 'v' && m)
1241 	{
1242 		/* exit editor if only editing one line */
1243 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1244 		{
1245 			if (fromuser) us_editemacsshipchanges(win);
1246 			return(TRUE);
1247 		}
1248 
1249 		if (e->firstline == 0) return(FALSE);
1250 		j = e->screenlines / 5 * 4;
1251 		if (j > e->firstline) j = e->firstline;
1252 		e->firstline -= j;
1253 		if ((e->state&EGRAPHICSOFF) == 0)
1254 		{
1255 			us_editemacsmovebox(win, 0, j, e->swid, us_thei*(e->screenlines-j), 0, 0);
1256 			us_editemacsclearbox(win, 0, 0, e->swid, us_thei*j);
1257 			for(k=0; k<j; k++)
1258 			{
1259 				if (e->firstline+k < e->maxlines) us_editemacsredrawline(win, k);
1260 			}
1261 		}
1262 		if (fromuser && e->curline >= e->screenlines+e->firstline)
1263 		{
1264 			us_editemacsshipchanges(win);
1265 			e->curline = e->firstline + e->screenlines/2;
1266 		}
1267 		return(FALSE);
1268 	}
1269 
1270 	if (i == '>' && m)
1271 	{
1272 		if (fromuser) us_editemacsshipchanges(win);
1273 		for(j=e->maxlines-1; j>=0; j--) if (e->textarray[j][0] != 0) break;
1274 		e->curline = j+1;
1275 		if (fromuser && e->curline >= e->firstline+e->screenlines)
1276 		{
1277 			e->firstline = e->curline - e->screenlines/2;
1278 			us_editemacsredrawscreen(win);
1279 		}
1280 		e->curchar = 0;
1281 		return(FALSE);
1282 	}
1283 
1284 	if (i == '<' && m)
1285 	{
1286 		if (fromuser)
1287 		{
1288 			us_editemacsshipchanges(win);
1289 			if (e->firstline != 0)
1290 			{
1291 				e->firstline = 0;
1292 				us_editemacsredrawscreen(win);
1293 			}
1294 		}
1295 		e->curline = 0;
1296 		e->curchar = 0;
1297 		return(FALSE);
1298 	}
1299 
1300 	if (i == CTLO && !m)
1301 	{
1302 		/* exit editor if only editing one line */
1303 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1304 		{
1305 			if (fromuser) us_editemacsshipchanges(win);
1306 			return(TRUE);
1307 		}
1308 
1309 		/* cannot change number of lines if not allowed */
1310 		if (fromuser && (e->state&LINESFIXED) != 0)
1311 		{
1312 			ttyputerr(_("Cannot insert lines in this edit session"));
1313 			return(FALSE);
1314 		}
1315 
1316 		/* see if there is room in the file */
1317 		for(i=e->maxlines-1; i>=0; i--) if (e->textarray[i][0] != 0) break;
1318 		if (i >= e->maxlines-1) us_editemacsaddmorelines(e);
1319 
1320 		/* shift lines down */
1321 		if (fromuser) us_editemacsworkingoncurline(e);
1322 		for(j = i+1; j > e->curline; j--)
1323 		{
1324 			if (j == e->curline+1) nextline = &e->textarray[e->curline][e->curchar]; else
1325 				nextline = e->textarray[j-1];
1326 			len = estrlen(nextline) + 1;
1327 			while (len > e->maxchars[j])
1328 				us_editemacsaddmorechars(e, j);
1329 			(void)estrcpy(e->textarray[j], nextline);
1330 		}
1331 		e->textarray[e->curline][e->curchar] = 0;
1332 		if ((e->state&EGRAPHICSOFF) == 0 && e->curline-e->firstline < e->screenlines &&
1333 			e->curline >= e->firstline)
1334 		{
1335 			us_editemacsclearbox(win, e->curchar, e->curline-e->firstline,
1336 				e->swid-e->curchar*us_twid, us_thei);
1337 		}
1338 
1339 		/* ship changes on the current line */
1340 		if (fromuser)
1341 		{
1342 			us_editemacsshipchanges(win);
1343 			if (win->changehandler != 0)
1344 				(*win->changehandler)(win, INSERTTEXTLINE, x_(""), e->textarray[e->curline+1], e->curline+1);
1345 			us_editemacsworkingoncurline(e);
1346 		}
1347 
1348 		/* shift lines down */
1349 		if (e->curline-e->firstline < e->screenlines-1 &&
1350 			e->curline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1351 				us_editemacsmovebox(win, 0, e->curline+1-e->firstline,
1352 					e->swid, e->shei-(e->curline+1-e->firstline)*us_thei, 0,
1353 						e->curline-e->firstline);
1354 
1355 		/* draw next line */
1356 		if (e->curline+1-e->firstline < e->screenlines &&
1357 			e->curline+1 >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1358 		{
1359 			us_editemacsclearbox(win, 0, e->curline+1-e->firstline,
1360 				e->swid, us_thei);
1361 			us_editemacstext(win, e->textarray[e->curline+1], 0, e->curline+1-e->firstline);
1362 		}
1363 		return(FALSE);
1364 	}
1365 
1366 	if ((i == '\n' || i == '\r') && !m)
1367 	{
1368 		/* exit editor if only editing one line */
1369 		if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1370 		{
1371 			if (fromuser) us_editemacsshipchanges(win);
1372 			return(TRUE);
1373 		}
1374 
1375 		/* cannot change number of lines if not allowed */
1376 		if (fromuser && (e->state&LINESFIXED) != 0)
1377 		{
1378 			ttyputerr(_("Cannot insert lines in this edit session"));
1379 			return(FALSE);
1380 		}
1381 
1382 		/* see if there is room in the file */
1383 		if (e->curline >= e->maxlines-1) us_editemacsaddmorelines(e);
1384 
1385 		/* shift lines down */
1386 		for(i=e->maxlines-1; i>=0; i--) if (e->textarray[i][0] != 0) break;
1387 		if (fromuser) us_editemacsworkingoncurline(e);
1388 		for(j = i+1; j > e->curline; j--)
1389 		{
1390 			if (j == e->curline+1) nextline = &e->textarray[e->curline][e->curchar]; else
1391 				nextline = e->textarray[j-1];
1392 			len = estrlen(nextline) + 1;
1393 			while (len > e->maxchars[j])
1394 				us_editemacsaddmorechars(e, j);
1395 			(void)estrcpy(e->textarray[j], nextline);
1396 		}
1397 		e->textarray[e->curline][e->curchar] = 0;
1398 		if ((e->state&EGRAPHICSOFF) == 0 && e->curline-e->firstline < e->screenlines &&
1399 			e->curline >= e->firstline)
1400 		{
1401 			us_editemacsclearbox(win, e->curchar, e->curline-e->firstline,
1402 				e->swid-e->curchar*us_twid, us_thei);
1403 		}
1404 
1405 		if (fromuser) us_editemacsshipchanges(win);
1406 		e->curline++;
1407 		e->curchar = 0;
1408 		if (fromuser)
1409 		{
1410 			if (win->changehandler != 0)
1411 				(*win->changehandler)(win, INSERTTEXTLINE, x_(""), e->textarray[e->curline], e->curline);
1412 			if (e->curline == e->firstline+e->screenlines-1)
1413 				us_editemacsshiftscreenup(win);
1414 			us_editemacsworkingoncurline(e);
1415 		}
1416 
1417 		/* shift lines down */
1418 		if (e->curline-e->firstline < e->screenlines-1 &&
1419 			e->curline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1420 				us_editemacsmovebox(win, 0, e->curline+1-e->firstline,
1421 					e->swid, e->shei-(e->curline+1-e->firstline)*us_thei, 0,
1422 						e->curline-e->firstline);
1423 
1424 		/* clear current line */
1425 		if (e->curline-e->firstline < e->screenlines &&
1426 			e->curline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1427 		{
1428 			us_editemacsclearbox(win, 0, e->curline-e->firstline,
1429 				e->swid, us_thei);
1430 			us_editemacstext(win, e->textarray[e->curline], 0, e->curline-e->firstline);
1431 		}
1432 		return(FALSE);
1433 	}
1434 
1435 	/* flash the display */
1436 	ttyputerr(_("The key '%s' is not valid in EMACS"),
1437 		us_describeboundkey((INTSML)i, (!m ? 0 : ACCELERATORDOWN), 1));
1438 	return(FALSE);
1439 }
1440 
1441 /*
1442  * routine to back the cursor by one character.  Returns true if at the
1443  * start of the file
1444  */
us_editemacsbackupchar(WINDOWPART * win,BOOLEAN fromuser)1445 BOOLEAN us_editemacsbackupchar(WINDOWPART *win, BOOLEAN fromuser)
1446 {
1447 	REGISTER EDITOR *e;
1448 	REGISTER INTBIG j;
1449 
1450 	e = win->editor;
1451 	if (e == NOEDITOR) return(TRUE);
1452 
1453 	if (e->curchar > 0)
1454 	{
1455 		e->curchar--;
1456 		return(FALSE);
1457 	}
1458 	if (e->curline <= 0) return(TRUE);
1459 
1460 	if (fromuser)
1461 	{
1462 		us_editemacsshipchanges(win);
1463 		if (e->curline == e->firstline && e->firstline > 0)
1464 			us_editemacsshiftscreendown(win);
1465 	}
1466 	e->curline--;
1467 	for(j=0; e->textarray[e->curline][j] != 0; j++) ;
1468 	e->curchar = j;
1469 	return(FALSE);
1470 }
1471 
1472 /*
1473  * routine to advance the cursor by one character.  Returns true if at the
1474  * end of the file
1475  */
us_editemacsadvancechar(WINDOWPART * win,BOOLEAN fromuser)1476 BOOLEAN us_editemacsadvancechar(WINDOWPART *win, BOOLEAN fromuser)
1477 {
1478 	REGISTER EDITOR *e;
1479 	REGISTER BOOLEAN atend;
1480 	REGISTER INTBIG j;
1481 
1482 	e = win->editor;
1483 	if (e == NOEDITOR) return(TRUE);
1484 
1485 	if (e->textarray[e->curline][e->curchar] != 0)
1486 	{
1487 		e->curchar++;
1488 		return(FALSE);
1489 	}
1490 
1491 	atend = TRUE;
1492 	for(j=e->curline+1; j < e->maxlines; j++)
1493 	{
1494 		if (e->textarray[j][0] == 0) continue;
1495 		atend = FALSE;
1496 		break;
1497 	}
1498 	if (e->curline >= e->maxlines-1) us_editemacsaddmorelines(e);
1499 	if (fromuser)
1500 	{
1501 		us_editemacsshipchanges(win);
1502 		if (e->curline == e->firstline+e->screenlines-1)
1503 			us_editemacsshiftscreenup(win);
1504 	}
1505 	e->curline++;
1506 	e->curchar = 0;
1507 	return(atend);
1508 }
1509 
1510 /*
1511  * routine to delete the current character
1512  */
us_editemacsdeletechar(WINDOWPART * win,BOOLEAN fromuser)1513 void us_editemacsdeletechar(WINDOWPART *win, BOOLEAN fromuser)
1514 {
1515 	REGISTER INTBIG j, curl, len;
1516 	REGISTER CHAR *nextline;
1517 	CHAR s[2];
1518 	REGISTER EDITOR *e;
1519 
1520 	e = win->editor;
1521 	if (e == NOEDITOR) return;
1522 
1523 	/* at end of line: delete an entire line */
1524 	if (e->textarray[e->curline][e->curchar] == 0)
1525 	{
1526 		/* only continue if there is a valid next line */
1527 		if (e->curline < e->maxlines-1)
1528 		{
1529 			/* start by appending the next line to this */
1530 			if (fromuser) us_editemacsworkingoncurline(e);
1531 			nextline = e->textarray[e->curline+1];
1532 			len = estrlen(e->textarray[e->curline]) + estrlen(nextline);
1533 			while (len > e->maxchars[e->curline])
1534 				us_editemacsaddmorechars(e, e->curline);
1535 			(void)estrcat(e->textarray[e->curline], nextline);
1536 			us_editemacsshipchanges(win);
1537 			us_editemacsredrawline(win, e->curline);
1538 
1539 			/* now report deletion of following line */
1540 			if (win->changehandler != 0)
1541 				(*win->changehandler)(win, DELETETEXTLINE, x_(""), e->textarray[e->curline+1], e->curline+1);
1542 			us_editemacsworkingoncurline(e);
1543 
1544 			/* shift up lines in memory */
1545 			for(curl = e->curline+1; curl < e->maxlines; curl++)
1546 			{
1547 				if (curl == e->maxlines-1) nextline = x_(""); else
1548 					nextline = e->textarray[curl+1];
1549 				if (estrcmp(e->textarray[curl], nextline) == 0) continue;
1550 				len = estrlen(nextline);
1551 				while (len > e->maxchars[curl])
1552 					us_editemacsaddmorechars(e, curl);
1553 				(void)estrcpy(e->textarray[curl], nextline);
1554 			}
1555 
1556 			/* delete line on the screen */
1557 			curl = e->curline + 1;
1558 			if (curl-e->firstline < e->screenlines-1 &&
1559 				curl >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1560 			{
1561 				us_editemacsmovebox(win, 0, curl-e->firstline, e->swid,
1562 					e->shei-(curl-e->firstline+1)*us_thei, 0,
1563 						curl-e->firstline+1);
1564 				if (e->screenlines < e->maxlines)
1565 				{
1566 					us_editemacsclearbox(win, 0, e->screenlines-1, e->swid, us_thei);
1567 					us_editemacsredrawline(win, e->screenlines-1);
1568 				}
1569 			}
1570 		}
1571 		return;
1572 	}
1573 
1574 	/* just delete the character in the line */
1575 	for(j=e->curchar; j<e->maxchars[e->curline]; j++)
1576 		e->textarray[e->curline][j] = e->textarray[e->curline][j+1];
1577 	if (e->curline-e->firstline < e->screenlines && e->curline >= e->firstline &&
1578 		e->curchar < e->screenchars && (e->state&EGRAPHICSOFF) == 0)
1579 	{
1580 		us_editemacsmovebox(win, e->curchar, e->curline-e->firstline,
1581 			e->swid-e->curchar*us_twid-us_twid, us_thei,
1582 				e->curchar+1, e->curline-e->firstline);
1583 		if ((INTBIG)estrlen(e->textarray[e->curline]) >= e->screenchars)
1584 		{
1585 			us_editemacsclearbox(win, e->screenchars-1, e->curline-e->firstline,
1586 				us_twid, us_thei);
1587 			s[0] = e->textarray[e->curline][e->screenchars-1];   s[1] = 0;
1588 			us_editemacstext(win, s, e->screenchars-1, e->curline-e->firstline);
1589 		}
1590 		us_editemacscleanupline(win, e->curline);
1591 	}
1592 }
1593 
1594 /*
1595  * Routine to search for "str" (search in the reverse direction if "reverse" is true).
1596  * Start search from the top if "fromtop" is true.  Issue proper calls if this was
1597  * made by the user ("fromuser" true).
1598  */
us_editemacsdosearch(WINDOWPART * win,CHAR * str,BOOLEAN reverse,BOOLEAN fromtop,BOOLEAN casesensitive,BOOLEAN fromuser)1599 void us_editemacsdosearch(WINDOWPART *win, CHAR *str, BOOLEAN reverse,
1600 	BOOLEAN fromtop, BOOLEAN casesensitive, BOOLEAN fromuser)
1601 {
1602 	REGISTER EDITOR *e;
1603 	REGISTER INTBIG i, j, k, startchr, startlne, match;
1604 
1605 	/* search for the string */
1606 	e = win->editor;
1607 	i = estrlen(str);
1608 	if (fromtop)
1609 	{
1610 		/* search from the top of the buffer */
1611 		startchr = 0;   startlne = 0;
1612 	} else
1613 	{
1614 		/* search from the end of the current selection */
1615 		startchr = e->curchar;   startlne = e->curline;
1616 	}
1617 	j = startlne;
1618 	k = startchr;
1619 	for(;;)
1620 	{
1621 		if (reverse)
1622 		{
1623 			/* reverse search: backup one place */
1624 			k--;
1625 			if (k < 0)
1626 			{
1627 				j--;
1628 				if (j < 0) j = e->maxlines - 1;
1629 				k = estrlen(e->textarray[j]);
1630 			}
1631 		} else
1632 		{
1633 			/* forward search: advance by one character */
1634 			if (e->textarray[j][k] != 0) k++; else
1635 			{
1636 				/* advance to the next line */
1637 				k = 0;
1638 				j++;
1639 				if (j >= e->maxlines) j = 0;
1640 			}
1641 		}
1642 
1643 		/* if it came all the way around, stop */
1644 		if (k == startchr && j == startlne)
1645 		{
1646 			ttyputmsg(_("Can't find \"%s\""), str);
1647 			break;
1648 		}
1649 
1650 		/* if string matches, set cursor pointers */
1651 		if (casesensitive)
1652 		{
1653 			match = estrncmp(str, &e->textarray[j][k], i);
1654 		} else
1655 		{
1656 			match = namesamen(str, &e->textarray[j][k], i);
1657 		}
1658 		if (match == 0)
1659 		{
1660 			if (fromuser) us_editemacsshipchanges(win);
1661 			if (reverse) e->curchar = k; else e->curchar = k+i;
1662 			e->curline = j;
1663 			us_editemacsensuretextshown(win, e->curline);
1664 			break;
1665 		}
1666 	}
1667 }
1668 
1669 /*
1670  * routine to shift the text screen up one line
1671  */
us_editemacsshiftscreenup(WINDOWPART * win)1672 void us_editemacsshiftscreenup(WINDOWPART *win)
1673 {
1674 	REGISTER EDITOR *e;
1675 
1676 	e = win->editor;
1677 	if (e == NOEDITOR) return;
1678 
1679 	e->firstline++;
1680 	if ((e->state&EGRAPHICSOFF) != 0) return;
1681 	us_editemacsmovebox(win, 0, 0, e->swid, us_thei*(e->screenlines-1), 0, 1);
1682 	us_editemacsclearbox(win, 0, e->screenlines-1, e->swid, us_thei);
1683 	if (e->screenlines+e->firstline <= e->maxlines)
1684 		us_editemacsredrawline(win, e->screenlines-1);
1685 }
1686 
1687 /*
1688  * routine to shift the text screen down one line
1689  */
us_editemacsshiftscreendown(WINDOWPART * win)1690 void us_editemacsshiftscreendown(WINDOWPART *win)
1691 {
1692 	REGISTER EDITOR *e;
1693 
1694 	e = win->editor;
1695 	if (e == NOEDITOR) return;
1696 
1697 	e->firstline--;
1698 	if ((e->state&EGRAPHICSOFF) != 0) return;
1699 	us_editemacsmovebox(win, 0, 1, e->swid, us_thei*(e->screenlines-1), 0, 0);
1700 	us_editemacsclearbox(win, 0, 0, e->swid, us_thei);
1701 	us_editemacsredrawline(win, 0);
1702 }
1703 
1704 /*
1705  * routine to ensure that line "line" is shown in the display
1706  */
us_editemacsensuretextshown(WINDOWPART * win,INTBIG line)1707 void us_editemacsensuretextshown(WINDOWPART *win, INTBIG line)
1708 {
1709 	REGISTER EDITOR *e;
1710 
1711 	e = win->editor;
1712 	if (e == NOEDITOR) return;
1713 
1714 	if (line-e->firstline >= e->screenlines || line < e->firstline)
1715 	{
1716 		e->firstline = maxi(0, line - e->screenlines/2);
1717 		us_editemacsredrawscreen(win);
1718 	}
1719 }
1720 
1721 /*
1722  * routine to redisplay the text screen
1723  */
us_editemacsredrawscreen(WINDOWPART * win)1724 void us_editemacsredrawscreen(WINDOWPART *win)
1725 {
1726 	REGISTER INTBIG j;
1727 	REGISTER EDITOR *e;
1728 
1729 	e = win->editor;
1730 	if (e == NOEDITOR) return;
1731 	if ((e->state&EGRAPHICSOFF) != 0) return;
1732 
1733 	/* put header on display */
1734 	us_editemacssetheader(win, e->header);
1735 
1736 	/* clear the screen */
1737 	us_editemacsclearbox(win, 0, 0, e->swid, e->shei);
1738 
1739 	/* rewrite each line */
1740 	for(j=0; j<e->screenlines; j++) if (j+e->firstline < e->maxlines)
1741 		us_editemacsredrawline(win, j);
1742 }
1743 
1744 /*
1745  * routine to write line "j" of the screen
1746  */
us_editemacsredrawline(WINDOWPART * win,INTBIG j)1747 void us_editemacsredrawline(WINDOWPART *win, INTBIG j)
1748 {
1749 	REGISTER INTBIG save;
1750 	REGISTER EDITOR *e;
1751 
1752 	e = win->editor;
1753 	if (e == NOEDITOR) return;
1754 
1755 	if ((INTBIG)estrlen(e->textarray[j+e->firstline]) > e->screenchars)
1756 	{
1757 		save = e->textarray[j+e->firstline][e->screenchars];
1758 		e->textarray[j+e->firstline][e->screenchars] = 0;
1759 	} else save = 0;
1760 	us_editemacstext(win, e->textarray[j+e->firstline], 0, j);
1761 	if (save != 0) e->textarray[j+e->firstline][e->screenchars] = (CHAR)save;
1762 }
1763 
1764 /*
1765  * routine to write the header string
1766  */
us_editemacssetheader(WINDOWPART * win,CHAR * header)1767 void us_editemacssetheader(WINDOWPART *win, CHAR *header)
1768 {
1769 	REGISTER INTBIG save;
1770 	REGISTER EDITOR *e;
1771 
1772 	e = win->editor;
1773 	if (e == NOEDITOR) return;
1774 	screendrawbox(win, win->uselx, win->usehx, win->usely, win->usehy, &us_ebox);
1775 	if ((INTBIG)estrlen(header) > e->screenchars)
1776 	{
1777 		save = header[e->screenchars];
1778 		header[e->screenchars] = 0;
1779 	} else save = 0;
1780 	us_editemacstext(win, header, 0, -2);
1781 	if ((win->state&WINDOWTYPE) == POPTEXTWINDOW)
1782 		us_editemacstext(win, _("EMACS editor: type RETURN when done"), 0, -1); else
1783 	{
1784 		if (estrcmp(win->location, x_("entire")) != 0)
1785 			us_editemacstext(win, _("EMACS editor: type ^Xd when done"), 0, -1); else
1786 		{
1787 			if (graphicshas(CANUSEFRAMES))
1788 				us_editemacstext(win, _("EMACS editor: close the window when done"), 0, -1); else
1789 					us_editemacstext(win, _("EMACS editor: text-only cell"), 0, -1);
1790 		}
1791 	}
1792 	if (save != 0) header[e->screenchars] = (CHAR)save;
1793 	screeninvertbox(win, e->offx-1, e->offx+e->swid,
1794 		e->revy+1, e->revy+us_thei*HEADERLINES);
1795 	us_menufigs.col = el_colmengly;
1796 	screendrawline(win, e->offx-1, e->revy, e->offx-1,
1797 		e->revy-e->shei-1, &us_menufigs, 0);
1798 	screendrawline(win, e->offx+e->swid+1, e->revy,
1799 		e->offx+e->swid+1, e->revy-e->shei-1, &us_menufigs, 0);
1800 	screendrawline(win, e->offx-1, e->revy-e->shei-1,
1801 		e->offx+e->swid+1, e->revy-e->shei-1, &us_menufigs, 0);
1802 }
1803 
1804 /*
1805  * Routine to return the next valid character (ignoring end-of-lines).
1806  */
us_editemacsnextvalidcharacter(EDITOR * e)1807 CHAR us_editemacsnextvalidcharacter(EDITOR *e)
1808 {
1809 	INTBIG line, chr;
1810 
1811 	line = e->curline;   chr = e->curchar;
1812 	while (line < e->maxlines && e->textarray[line][chr] == 0)
1813 	{
1814 		line++;
1815 		chr = 0;
1816 	}
1817 	return(e->textarray[line][chr]);
1818 }
1819 
1820 /*
1821  * routine to invert the character cursor, turning it on or off
1822  */
us_editemacsflashcursor(WINDOWPART * win)1823 void us_editemacsflashcursor(WINDOWPART *win)
1824 {
1825 	REGISTER EDITOR *e;
1826 
1827 	e = win->editor;
1828 	if (e == NOEDITOR) return;
1829 
1830 	if (e->curline-e->firstline < e->screenlines && e->curline >= e->firstline &&
1831 		e->curchar < e->screenchars && (e->state&EGRAPHICSOFF) == 0)
1832 			us_editemacsinvertbox(win, e->curchar, e->curline-e->firstline, us_twid,
1833 				us_thei);
1834 }
1835 
1836 /*
1837  * turn off the highlighting of a line of text (if one is highlighted)
1838  */
us_editemacsoffhighlight(WINDOWPART * win)1839 void us_editemacsoffhighlight(WINDOWPART *win)
1840 {
1841 	REGISTER EDITOR *e;
1842 
1843 	e = win->editor;
1844 	if (e == NOEDITOR) return;
1845 
1846 	if (e->highlightedline < 0) return;
1847 	if (e->highlightedline-e->firstline < e->screenlines &&
1848 		e->highlightedline >= e->firstline && (e->state&EGRAPHICSOFF) == 0)
1849 			us_editemacsinvertbox(win, 0, e->highlightedline-e->firstline,
1850 				e->swid, us_thei);
1851 	e->highlightedline = -1;
1852 }
1853 
1854 /*
1855  * routine to cleanup the bits at the end of a line that are not a full-width
1856  * character
1857  */
us_editemacscleanupline(WINDOWPART * win,INTBIG line)1858 void us_editemacscleanupline(WINDOWPART *win, INTBIG line)
1859 {
1860 	REGISTER INTBIG residue;
1861 	REGISTER EDITOR *e;
1862 
1863 	e = win->editor;
1864 	if (e == NOEDITOR) return;
1865 
1866 	residue = e->swid-e->screenchars*us_twid;
1867 	if (residue == 0) return;
1868 	us_editemacsclearbox(win, e->screenchars, line-e->firstline, residue, us_thei);
1869 }
1870 
1871 /*
1872  * routine to declare that the user is now working on line "line"
1873  */
us_editemacsworkingoncurline(EDITOR * e)1874 void us_editemacsworkingoncurline(EDITOR *e)
1875 {
1876 	if (e->working == -1)
1877 	{
1878 		/* first time: save the line */
1879 		(void)estrcpy(e->formerline, e->textarray[e->curline]);
1880 		e->working = e->curline;
1881 	}
1882 }
1883 
1884 /*
1885  * routine to declare that the user is done with line "line"
1886  */
us_editemacsshipchanges(WINDOWPART * win)1887 void us_editemacsshipchanges(WINDOWPART *win)
1888 {
1889 	REGISTER EDITOR *e;
1890 
1891 	e = win->editor;
1892 	if (e == NOEDITOR) return;
1893 
1894 	if (e->working == -1) return;
1895 	us_editemacsflashcursor(win);
1896 	if (win->changehandler != 0)
1897 		(*win->changehandler)(win, REPLACETEXTLINE, e->formerline,
1898 			e->textarray[e->curline], e->working);
1899 	us_editemacsflashcursor(win);
1900 	e->working = -1;
1901 }
1902 
1903 /******************** ALLOCATION ********************/
1904 
1905 /*
1906  * routine to double the number of lines in the text buffer
1907  */
us_editemacsaddmorelines(EDITOR * e)1908 void us_editemacsaddmorelines(EDITOR *e)
1909 {
1910 	REGISTER INTBIG oldlines, i;
1911 	REGISTER INTBIG *maxchars;
1912 	REGISTER CHAR **textarray;
1913 
1914 	/* save former buffer size, double it */
1915 	oldlines = e->maxlines;
1916 	e->maxlines *= 2;
1917 
1918 	/* allocate new arrays */
1919 	maxchars = (INTBIG *)emalloc((e->maxlines * SIZEOFINTBIG), us_tool->cluster);
1920 	if (maxchars == 0) ttyputnomemory();
1921 	textarray = (CHAR **)emalloc((e->maxlines * (sizeof (CHAR *))), us_tool->cluster);
1922 	if (textarray == 0) ttyputnomemory();
1923 
1924 	/* copy old information */
1925 	for(i=0; i<e->maxlines; i++)
1926 	{
1927 		if (i >= oldlines)
1928 		{
1929 			textarray[i] = (CHAR *)emalloc((e->screenchars+1) * SIZEOFCHAR, us_tool->cluster);
1930 			if (textarray[i] == 0) ttyputnomemory();
1931 			textarray[i][0] = 0;
1932 			maxchars[i] = e->screenchars;
1933 		} else
1934 		{
1935 			textarray[i] = (CHAR *)emalloc((e->maxchars[i]+1) * SIZEOFCHAR, us_tool->cluster);
1936 			if (textarray[i] == 0) ttyputnomemory();
1937 			(void)estrcpy(textarray[i], e->textarray[i]);
1938 			maxchars[i] = e->maxchars[i];
1939 		}
1940 	}
1941 
1942 	/* free old arrays */
1943 	for(i=0; i<oldlines; i++) efree(e->textarray[i]);
1944 	efree((CHAR *)e->textarray);
1945 	efree((CHAR *)e->maxchars);
1946 
1947 	/* setup pointers correctly */
1948 	e->textarray = textarray;
1949 	e->maxchars = maxchars;
1950 }
1951 
1952 /*
1953  * routine to double the number of characters in line "line"
1954  */
us_editemacsaddmorechars(EDITOR * e,INTBIG line)1955 void us_editemacsaddmorechars(EDITOR *e, INTBIG line)
1956 {
1957 	REGISTER CHAR *oldline;
1958 
1959 	oldline = e->textarray[line];
1960 	e->maxchars[line] *= 2;
1961 	e->textarray[line] = (CHAR *)emalloc((e->maxchars[line]+1) * SIZEOFCHAR, us_tool->cluster);
1962 	(void)estrcpy(e->textarray[line], oldline);
1963 	if (e->maxchars[line] > e->mostchars)
1964 	{
1965 		e->mostchars = e->maxchars[line];
1966 		efree(e->formerline);
1967 		us_editemacsgetbuffers(e);
1968 	}
1969 }
1970 
1971 /*
1972  * routine to allocate the single-line buffers
1973  */
us_editemacsgetbuffers(EDITOR * e)1974 void us_editemacsgetbuffers(EDITOR *e)
1975 {
1976 	e->formerline = (CHAR *)emalloc((e->mostchars+1) * SIZEOFCHAR, us_tool->cluster);
1977 	if (e->formerline == 0) ttyputnomemory();
1978 	if (e->mostchars > us_killbufchars)
1979 	{
1980 		if (us_killbufchars != 0) efree(us_killbuf);
1981 		us_killbuf = (CHAR *)emalloc(e->mostchars * SIZEOFCHAR, us_tool->cluster);
1982 		if (us_killbuf == 0) ttyputnomemory();
1983 		us_killbufchars = e->mostchars;
1984 	}
1985 }
1986 
1987 /******************** GRAPHIC SUPPORT ********************/
1988 
1989 /*
1990  * move text starting at character position (sx,sy) to character position
1991  * (dx, dy).
1992  */
us_editemacsmovebox(WINDOWPART * win,INTBIG dx,INTBIG dy,INTBIG wid,INTBIG hei,INTBIG sx,INTBIG sy)1993 void us_editemacsmovebox(WINDOWPART *win, INTBIG dx, INTBIG dy, INTBIG wid,
1994 	INTBIG hei, INTBIG sx, INTBIG sy)
1995 {
1996 	REGISTER EDITOR *e;
1997 
1998 	e = win->editor;
1999 	if (e == NOEDITOR) return;
2000 	screenmovebox(win, sx*us_twid+e->offx, e->revy-(sy*us_thei+hei-1), wid, hei,
2001 		dx*us_twid+e->offx, e->revy-(dy*us_thei+hei-1));
2002 }
2003 
2004 /*
2005  * erase text starting at character position (dx,dy) for (wid, hei)
2006  */
us_editemacsclearbox(WINDOWPART * win,INTBIG dx,INTBIG dy,INTBIG wid,INTBIG hei)2007 void us_editemacsclearbox(WINDOWPART *win, INTBIG dx, INTBIG dy, INTBIG wid, INTBIG hei)
2008 {
2009 	REGISTER EDITOR *e;
2010 
2011 	e = win->editor;
2012 	if (e == NOEDITOR) return;
2013 
2014 	dx = (dx * us_twid) + e->offx;
2015 	dy *= us_thei;
2016 	screendrawbox(win, dx, dx+wid-1, e->revy-(dy+hei-1), e->revy-dy, &us_ebox);
2017 }
2018 
2019 /*
2020  * invert text starting at character position (dx,dy) for (wid, hei)
2021  */
us_editemacsinvertbox(WINDOWPART * win,INTBIG dx,INTBIG dy,INTBIG wid,INTBIG hei)2022 void us_editemacsinvertbox(WINDOWPART *win, INTBIG dx, INTBIG dy, INTBIG wid, INTBIG hei)
2023 {
2024 	REGISTER EDITOR *e;
2025 
2026 	e = win->editor;
2027 	if (e == NOEDITOR) return;
2028 
2029 	dx = (dx * us_twid) + e->offx;
2030 	dy *= us_thei;
2031 	screeninvertbox(win, dx, dx+wid-1, e->revy-(dy+hei-1), e->revy-dy);
2032 }
2033 
2034 /*
2035  * write text "str" starting at character position (x,y)
2036  */
us_editemacstext(WINDOWPART * win,CHAR * str,INTBIG x,INTBIG y)2037 void us_editemacstext(WINDOWPART *win, CHAR *str, INTBIG x, INTBIG y)
2038 {
2039 	REGISTER EDITOR *e;
2040 	UINTBIG descript[TEXTDESCRIPTSIZE];
2041 
2042 	e = win->editor;
2043 	if (e == NOEDITOR) return;
2044 
2045 	TDCLEAR(descript);
2046 	TDSETSIZE(descript, us_editemacsfont);
2047 	screensettextinfo(win, NOTECHNOLOGY, descript);
2048 	us_menutext.col = el_colmentxt;
2049 	screendrawtext(win, x*us_twid + e->offx, e->revy-(y+1)*us_thei,
2050 		str, &us_menutext);
2051 }
2052