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