1 #include <stdlib.h>
2 #include "deco.h"
3 #include "scr.h"
4 #include "rec.h"
5 
6 static editmodflg;
7 
8 extern char viewsrch [SEARCHSZ];        /* search string */
9 extern viewraw;                         /* raw mode */
10 extern viewtabs;                        /* visible spaces mode */
11 extern viewfd;                          /* file descriptor */
12 extern REC *viewrec;
13 
14 static void clearline (REC *r, int line);
15 static void joinlines (REC *r, int line);
16 static void breakline (REC *r, int line, int off);
17 static void cleartoeoln (REC *r, int line, int off);
18 static int wordend (LINE *p, int off);
19 static int wordbeg (LINE *p, int off);
20 static int ischar (int c);
21 
charcode(int l,int n)22 static int charcode (int l, int n)
23 {
24 	LINE *p;
25 
26 	p = RecGet (viewrec, l);
27 	if (! p)
28 		return (0);
29 	if (n >= p->len)
30 		return ('\n');
31 	return (p->ptr [n] & 0xff);
32 }
33 
edithead(char * filename,int line,int col,int off)34 static void edithead (char *filename, int line, int col, int off)
35 {
36 	register i;
37 
38 	VSetDim ();
39 	VStandOut ();
40 	VMove (0, 0);
41 	for (i=80; --i>=0; VPutChar (' '));
42 	VMPutString (0, 1, "File ");
43 	VPutString (filename);
44 	VPrint ("  Lines %d", viewrec->len);
45 	VMove (0, 50);
46 	VPrint ("Line %-5d Col %d", line+1, col);
47 	i = charcode (line, off);
48 	VMove (0, 70);
49 	if (i)
50 		VPrint ("Char 0%-3o", i);
51 	else
52 		VPrint ("Char 0");
53 	VSetNormal ();
54 	VStandEnd ();
55 }
56 
lastpos(int n)57 static int lastpos (int n)
58 {
59 	register LINE *p;
60 
61 	p = RecGet (viewrec, n);
62 	if (! p)
63 		return (0);
64 	return (p->len);
65 }
66 
editfile(int d,char * filename,char * basename)67 void editfile (int d, char *filename, char *basename)
68 {
69 	register baseline, basecol;
70 	int stepud = LINES-3;                   /* step up-down */
71 	int sline, soff;                        /* search position */
72 	int ccol, lastccol, c;
73 
74 	viewfd = d;
75 	viewrec = RecOpen (d, 1);
76 	if (! viewrec)
77 		return;
78 	editmodflg = 0;
79 	if (viewrec->broken) {
80 		if (0 != getchoice (1, " Edit ",
81 		    "File contains too long lines.",
82 		    0, " Break lines ", " Cancel editing ", 0))
83 			return;
84 		RecBreak (viewrec);
85 		editmodflg = 1;
86 	}
87 	baseline = basecol = 0;
88 	sline = ccol = 0;
89 	VClearBox (1, 0, LINES-2, COLS);
90 	VMPutString (LINES-1, 0, "\0011\16Help  \17 2\16Save  \17 3\16Raw   \17 4\16      \17 5\16Top   \17 6\16Bottom\17 7\16Search\17 8\16Home  \17 9\16Spaces\01710\16Quit \17\2");
91 	for (;;) {
92 		viewpage (baseline, basecol);
93 		for (;;) {
94 			soff = offset (sline, ccol);
95 			if (soff > lastpos (sline))
96 				--soff;
97 			lastccol = column (sline, soff);
98 			if (lastccol < basecol || lastccol >= basecol+80) {
99 				basecol = lastccol / 40 * 40 - 40;
100 				if (basecol < 0)
101 					basecol = 0;
102 				break;
103 			}
104 			edithead (basename, sline, lastccol, soff);
105 			VMove (sline-baseline+1, lastccol-basecol);
106 			VSync ();
107 			switch (c = KeyGet ()) {
108 			case meta ('A'):        /* f1 */
109 				runhelp ("edit");
110 				continue;
111 			case cntrl (']'):       /* redraw screen */
112 				VRedraw ();
113 				continue;
114 			case cntrl ('Q'):
115 			case cntrl ('V'):       /* quote next char */
116 				VPutString ("\3\16#\2\17");
117 				ccol = column (sline, soff);
118 				VMove (sline-baseline+1, ccol-basecol);
119 				VSync ();
120 				c = KeyGetChar ();
121 				goto inschar;
122 			case meta ('b'):        /* back space */
123 				if (soff) {
124 					ccol = column (sline, --soff);
125 					editmodflg = 1;
126 					RecDelChar (viewrec, sline, soff);
127 					viewline (sline, basecol, sline-baseline+1);
128 					continue;
129 				}
130 				if (! sline)
131 					continue;
132 				--sline;
133 				soff = lastpos (sline);
134 				ccol = column (sline, soff);
135 join:
136 				editmodflg = 1;
137 				joinlines (viewrec, sline);
138 				RecDelLine (viewrec, sline+1);
139 				if (ccol < basecol || ccol >= basecol+80) {
140 					basecol = ccol<40 ? 0 : ((ccol - 40) / 40 * 40);
141 					break;
142 				}
143 				if (sline < baseline) {
144 					--baseline;
145 					viewline (baseline, basecol, 1);
146 					continue;
147 				}
148 				if (sline < baseline+LINES-4) {
149 					if (soff)
150 						VDelLine (2+sline-baseline);
151 					else
152 						VDelLine (1+sline-baseline);
153 					VInsLine (LINES-2);
154 					viewline (sline, basecol, sline-baseline+1);
155 					viewline (baseline+LINES-3, basecol, LINES-2);
156 					continue;
157 				}
158 				if (sline == baseline+LINES-4) {
159 					viewline (sline, basecol, LINES-3);
160 					viewline (sline+1, basecol, LINES-2);
161 					continue;
162 				}
163 				/* now sline equals to baseline+LINES-3 */
164 				viewline (sline, basecol, LINES-2);
165 				continue;
166 			case cntrl ('G'):       /* delete char */
167 				if (soff == lastpos (sline)) {
168 					if (sline == viewrec->len-1)
169 						continue;
170 					goto join;
171 				}
172 				editmodflg = 1;
173 				RecDelChar (viewrec, sline, soff);
174 				viewline (sline, basecol, sline-baseline+1);
175 				continue;
176 			case cntrl ('K'):       /* clear to end of line */
177 				if (soff == lastpos (sline))
178 					continue;
179 				editmodflg = 1;
180 				cleartoeoln (viewrec, sline, soff);
181 				viewline (sline, basecol, sline-baseline+1);
182 				continue;
183 			case cntrl ('Y'):       /* delete line */
184 				editmodflg = 1;
185 				ccol = 0;
186 				if (sline == viewrec->len-1) {
187 					clearline (viewrec, sline);
188 					viewline (sline, basecol, sline-baseline+1);
189 					continue;
190 				}
191 				RecDelLine (viewrec, sline);
192 				if (sline < baseline+LINES-3) {
193 					VDelLine (1+sline-baseline);
194 					VInsLine (LINES-2);
195 				}
196 				viewline (baseline+LINES-3, basecol, LINES-2);
197 				continue;
198 			case cntrl ('J'):
199 			case cntrl ('M'):       /* insert new line */
200 				editmodflg = 1;
201 				if (viewrec->len <= 0)
202 					RecInsLine (viewrec, 0);
203 				breakline (viewrec, sline, soff);
204 				ccol = 0;
205 				++sline;
206 				if (sline < baseline+LINES-2) {
207 					VDelLine (LINES-2);
208 					if (soff)
209 						VInsLine (1+sline-baseline);
210 					else
211 						VInsLine (sline-baseline);
212 					viewline (sline-1, basecol, sline-baseline);
213 					viewline (sline, basecol, 1+sline-baseline);
214 					continue;
215 				}
216 				++baseline;
217 				VDelLine (1);
218 				VInsLine (LINES-2);
219 				viewline (sline-1, basecol, LINES-3);
220 				viewline (sline, basecol, LINES-2);
221 				continue;
222 			default:                /* insert char */
223 				if ((c<' ' && c!='\t') || c>0377) {
224 					VBeep ();
225 					continue;
226 				}
227 inschar:
228 				if (viewrec->len <= 0)
229 					RecInsLine (viewrec, 0);
230 				RecInsChar (viewrec, sline, soff, c);
231 				editmodflg = 1;
232 				viewline (sline, basecol, sline-baseline+1);
233 				ccol = column (sline, soff+1);
234 				continue;
235 			case meta ('B'):        /* f2 - save */
236 				message (" Save ", "Saving file '%s'...", basename);
237 				RecSave (viewrec, filename);
238 				editmodflg = 0;
239 				endmesg ();
240 				continue;
241 			case meta ('C'):        /* f3 - raw */
242 				viewraw ^= 1;
243 				break;
244 			case meta ('I'):        /* f9 - spaces */
245 				viewtabs ^= 1;
246 				break;
247 			case meta ('H'):        /* f8 - home */
248 				if (sline==baseline && ccol==0)
249 					continue;
250 				sline = baseline;
251 				ccol = 0;
252 				break;
253 			case meta ('E'):        /* f5 - top */
254 				if (sline==0 && baseline==0 && ccol==0)
255 					continue;
256 				sline = baseline = 0;
257 				ccol = 0;
258 				break;
259 			case meta ('F'):        /* f6 - bottom */
260 				if (soff == lastpos (sline) &&
261 				    sline >= viewrec->len - 1)
262 					continue;
263 				baseline = viewrec->len - (LINES-2);
264 				if (baseline < 0)
265 					baseline = 0;
266 				sline = viewrec->len - 1;
267 				if (sline < 0)
268 					sline = 0;
269 				soff = lastpos (sline);
270 				ccol = column (sline, soff);
271 				if (ccol < basecol || ccol >= basecol+80)
272 					basecol = ccol<40 ? 0 : ((ccol - 40) / 40 * 40);
273 				break;
274 			case cntrl ('C'):
275 			case cntrl ('['):
276 			case meta ('J'):        /* f0 - quit */
277 				if (editmodflg) switch (getchoice (1, " Edit ",
278 					"You've made changes since the last save.",
279 					0, " Save ", " Don't save ", " Continue editing ")) {
280 				case 0:
281 					if (RecSave (viewrec, filename) < 0)
282 						continue;
283 				case 1:
284 					break;
285 				default:
286 					continue;
287 				}
288 				VClearBox (1, 0, LINES-2, COLS);
289 				RecClose (viewrec);
290 				return;
291 			case meta ('G'): {      /* f7 - search */
292 				register char *p;
293 
294 				if (! (p = getstring (SEARCHSZ-1, viewsrch, " Search ", "Search for the string")))
295 					continue;
296 				strcpy (viewsrch, p);
297 				if (! search (p, sline, soff+1, &sline, &soff))
298 					continue;
299 				if (baseline > sline || baseline + LINES-2 <= sline)
300 					baseline = sline;
301 				if (baseline > viewrec->len - (LINES-2))
302 					baseline = viewrec->len - (LINES-2);
303 				if (baseline < 0)
304 					baseline = 0;
305 				ccol = column (sline, soff);
306 				basecol = ccol<40 ? 0 : ((ccol + strlen (p) - 41) / 40 * 40);
307 				break;
308 			}
309 			case cntrl ('E'):       /* up */
310 			case meta ('u'):        /* up */
311 				if (sline <= 0)
312 					continue;
313 				--sline;
314 				if (baseline <= sline)
315 					continue;
316 				--baseline;
317 				VDelLine (LINES-2);
318 				VInsLine (1);
319 				viewline (baseline, basecol, 1);
320 				continue;
321 			case cntrl ('X'):       /* down */
322 			case meta ('d'):        /* down */
323 				if (sline >= viewrec->len-1)
324 					continue;
325 				++sline;
326 				if (baseline + (LINES-2) > sline)
327 					continue;
328 				++baseline;
329 				VDelLine (1);
330 				VInsLine (LINES-2);
331 				viewline (baseline+LINES-3, basecol, LINES-2);
332 				continue;
333 			case cntrl ('F'):       /* word right */
334 				soff = wordend (RecGet (viewrec, sline), soff);
335 				ccol = column (sline, soff);
336 				continue;
337 			case cntrl ('W'):       /* word left */
338 				soff = wordbeg (RecGet (viewrec, sline), soff);
339 				ccol = column (sline, soff);
340 				continue;
341 			case cntrl ('D'):
342 			case meta ('r'):        /* right */
343 				if (soff == lastpos (sline)) {
344 					if (sline == viewrec->len-1)
345 						continue;
346 					++sline;
347 					ccol = 0;
348 					if (baseline+LINES-2 <= sline) {
349 						++baseline;
350 						VDelLine (1);
351 						VInsLine (LINES-2);
352 						viewline (baseline+LINES-3, basecol, LINES-2);
353 					}
354 					continue;
355 				}
356 				ccol = column (sline, ++soff);
357 				continue;
358 			case cntrl ('A'):
359 			case cntrl ('S'):
360 			case meta ('l'):        /* left */
361 				if (soff <= 0) {
362 					if (sline <= 0)
363 						continue;
364 					--sline;
365 					soff = lastpos (sline);
366 					ccol = column (sline, soff);
367 					if (ccol < basecol || ccol >= basecol+80) {
368 						basecol = ccol<40 ? 0 : ((ccol - 40) / 40 * 40);
369 						if (baseline > sline)
370 							baseline = sline;
371 						break;
372 					}
373 					if (baseline > sline) {
374 						baseline = sline;
375 						VDelLine (LINES-2);
376 						VInsLine (1);
377 						viewline (baseline, basecol, 1);
378 					}
379 					continue;
380 				}
381 				ccol = column (sline, --soff);
382 				continue;
383 			case cntrl ('B'):
384 			case meta ('n'):        /* next page */
385 				if (baseline >= viewrec->len - (LINES-2))
386 					continue;
387 				baseline += stepud;
388 				sline += stepud;
389 				if (baseline > viewrec->len - (LINES-2)) {
390 					sline -= baseline - (viewrec->len - (LINES-2));
391 					baseline = viewrec->len - (LINES-2);
392 				}
393 				break;
394 			case cntrl ('R'):
395 			case meta ('p'):        /* prev page */
396 				if (baseline <= 0)
397 					continue;
398 				baseline -= stepud;
399 				sline -= stepud;
400 				if (baseline < 0) {
401 					sline -= baseline;
402 					baseline = 0;
403 				}
404 				break;
405 			case meta ('h'):        /* home */
406 				if (! ccol)
407 					continue;
408 				ccol = basecol = 0;
409 				break;
410 			case meta ('e'):        /* end */
411 				c = lastpos (sline);
412 				if (soff == c)
413 					continue;
414 				soff = c;
415 				ccol = column (sline, soff);
416 				if (ccol < basecol || ccol >= basecol+80)
417 					basecol = ccol<40 ? 0 : ((ccol - 40) / 40 * 40);
418 				break;
419 			}
420 			break;
421 		}
422 	}
423 }
424 
clearline(REC * r,int line)425 static void clearline (REC *r, int line)
426 {
427 	register LINE *p;
428 
429 	if (! (p = RecGet (r, line)))
430 		return;
431 	if (p->len <= 0)
432 		return;
433 	free (p->ptr);
434 	p->ptr = "";
435 	RecPut (p, 0);
436 }
437 
joinlines(REC * r,int line)438 static void joinlines (REC *r, int line)
439 {
440 	register LINE *p, *q;
441 	char *s;
442 
443 	if (! (q = RecGet (r, line+1)) || ! q->len)
444 		return;
445 	if (! (p = RecGet (r, line)))
446 		return;
447 	if (! p->len) {
448 		p->ptr = q->ptr;
449 		q->ptr = "";
450 		RecPut (p, q->len);
451 		RecPut (q, 0);
452 		return;
453 	}
454 	s = malloc (p->len + q->len);
455 	memcpy (s, p->ptr, p->len);
456 	memcpy (s+p->len, q->ptr, q->len);
457 	free (p->ptr);
458 	free (q->ptr);
459 	p->ptr = s;
460 	q->ptr = "";
461 	RecPut (p, p->len + q->len);
462 	RecPut (q, 0);
463 }
464 
breakline(REC * r,int line,int off)465 static void breakline (REC *r, int line, int off)
466 {
467 	register LINE *p, *q;
468 	char *s;
469 
470 	if (off <= 0) {
471 		RecInsLine (r, line);
472 		return;
473 	}
474 	if (! (p = RecGet (r, line)))
475 		return;
476 	RecInsLine (r, line+1);
477 	if (off >= p->len)
478 		return;
479 	if (! (q = RecGet (r, line+1)))
480 		return;
481 	q->ptr = malloc (p->len - off);
482 	memcpy (q->ptr, p->ptr + off, p->len - off);
483 	RecPut (q, p->len - off);
484 	s = malloc (off);
485 	memcpy (s, p->ptr, off);
486 	free (p->ptr);
487 	p->ptr = s;
488 	RecPut (p, off);
489 }
490 
cleartoeoln(REC * r,int line,int off)491 static void cleartoeoln (REC *r, int line, int off)
492 {
493 	register LINE *p;
494 	char *s;
495 
496 	if (! (p = RecGet (r, line)))
497 		return;
498 	if (off >= p->len)
499 		return;
500 	if (off <= 0) {
501 		p->ptr = "";
502 		RecPut (p, 0);
503 		return;
504 	}
505 	s = malloc (off);
506 	memcpy (s, p->ptr, off);
507 	free (p->ptr);
508 	p->ptr = s;
509 	RecPut (p, off);
510 }
511 
wordend(LINE * p,int off)512 static int wordend (LINE *p, int off)
513 {
514 	register char *s;
515 
516 	if (off >= p->len)
517 		return (p->len);
518 	s = p->ptr + off;
519 	while (off<p->len && ! ischar (*s))
520 		++s, ++off;
521 	if (off >= p->len)
522 		return (p->len);
523 	while (off<p->len && ischar (*s))
524 		++s, ++off;
525 	return (off);
526 }
527 
wordbeg(LINE * p,int off)528 static int wordbeg (LINE *p, int off)
529 {
530 	register char *s;
531 
532 	if (off <= 0)
533 		return (0);
534 	--off;
535 	s = p->ptr + off;
536 	while (off>0 && ! ischar (*s))
537 		--s, --off;
538 	if (off <= 0)
539 		return (0);
540 	while (off>=0 && ischar (*s))
541 		--s, --off;
542 	if (off < 0)
543 		return (0);
544 	return (off + 1);
545 }
546 
ischar(int c)547 static int ischar (int c)
548 {
549 	c &= 0xff;
550 	if (c>='A' && c<='Z')
551 		return (1);
552 	if (c>='a' && c<='z')
553 		return (1);
554 	if (c>='0' && c<='9')
555 		return (1);
556 	if (c>=0200 && c<=0377)
557 		return (1);
558 	if (c=='_' || c=='$')
559 		return (1);
560 	return (0);
561 }
562