1 /*
2  *	Text editing windows
3  *	Copyright
4  *		(C) 1992 Joseph H. Allen
5  *
6  *	This file is part of JOE (Joe's Own Editor)
7  */
8 #include "types.h"
9 
10 int staen = 0;
11 int staupd = 0;
12 int keepup = 0;
13 int bg_stalin;
14 
15 /* Move text window */
16 
movetw(W * w,ptrdiff_t x,ptrdiff_t y)17 static void movetw(W *w, ptrdiff_t x, ptrdiff_t y)
18 {
19 	BW *bw = (BW *)w->object;
20 	TW *tw = (TW *)bw->object;
21 
22 	if ((y || !staen) && w->h > 1) {
23 		if (!tw->staon) {	/* Scroll down and shrink */
24 			nscrldn(bw->parent->t->t, y, bw->parent->nh + y, 1);
25 		}
26 		bwmove(bw, x + bw->lincols, y + 1);
27 		tw->staon = 1;
28 	} else {
29 		if (tw->staon) {	/* Scroll up and grow */
30 			nscrlup(bw->parent->t->t, y, bw->parent->nh + y, 1);
31 		}
32 		bwmove(bw, x + bw->lincols, y);
33 		tw->staon = 0;
34 	}
35 }
36 
37 /* Resize text window */
38 
resizetw(W * w,ptrdiff_t wi,ptrdiff_t he)39 static void resizetw(W *w, ptrdiff_t wi, ptrdiff_t he)
40 {
41 	BW *bw = (BW *)w->object;
42 	if ((bw->parent->ny || !staen) && he > 1)
43 		bwresz(bw, wi - bw->lincols, he - 1);
44 	else
45 		bwresz(bw, wi - bw->lincols, he);
46 }
47 
48 /* Get current context */
49 
50 /* Use context.jsf to determine context.  The advantage of this vs.  the old
51  * method is that the line attribute cache will help find context line
52  * quickly in large files.
53  */
54 
55 static struct high_syntax *context_syntax;
56 
get_context(BW * bw)57 static const int *get_context(BW *bw)
58 {
59 	static int buf1[SAVED_SIZE*2]; /* Double size because we replace \ with \\ */
60 	const int *src;
61 	P *p;
62 	struct lattr_db *db;
63 	HIGHLIGHT_STATE st;
64 	clear_state(&st);
65 	p = pdup(bw->cursor, "get_context");
66 	p_goto_bol(p);
67 	if (!context_syntax)
68 		context_syntax = load_syntax("context");
69 	if (context_syntax) {
70 		db = find_lattr_db(bw->b, context_syntax);
71 		if (db) {
72 			st = lattr_get(db, context_syntax, p, p->line + 1);
73 			/* Handles last line better */
74 			/* st = parse(context_syntax, p, st, p->b->o.charmap); */
75 		}
76 	}
77 	prm(p);
78 	src = st.saved_s;
79 	buf1[0] = 0;
80 	if (src) {
81 		ptrdiff_t i, j, spc;
82 		/* replace tabs to spaces and remove adjoining spaces */
83 		for (i=0,j=0,spc=0; src[i] && i < SAVED_SIZE-1; i++) {
84 			if (src[i]=='\t' || src[i]==' ') {
85 				if (spc) continue;
86 				spc = 1;
87 			}
88 			else spc = 0;
89 			if (src[i]=='\t')
90 				buf1[j++] = ' ';
91 			else if (src[i]=='\\') {
92 				buf1[j++] = '\\';
93 				buf1[j++] = '\\';
94 			} else if (src[i] != '\r') {
95 				buf1[j++] = src[i];
96 			}
97 		}
98 		buf1[j]= '\0';
99 	}
100 	return buf1;
101 }
102 
103 /* Find first line (going backwards) which has 0 indentation level
104  * and is not a comment, blank, or block structuring line.  This is
105  * likely to be the line with the function name.
106  *
107  * There are actually two possibilities:
108  *
109  * We want the first line-
110  *
111  * int
112  * foo(int x,int y) {
113  *
114  *   }
115  *
116  * We want the last line-
117  *
118  * program foo(input,output);
119  * var a, b, c : real;
120  * begin
121  *
122  */
123 
124 #if 0
125 static char *get_context(BW *bw)
126 {
127 	P *p = pdup(bw->cursor, "get_context");
128 	static char buf1[stdsiz];
129 	int i, j, spc;
130 
131 
132 	buf1[0] = 0;
133 	/* Find first line with 0 indentation which is not a comment line */
134 	do {
135 		p_goto_bol(p);
136 		if (!pisindent(p) && !pisblank(p)) {
137 			/* next: */
138 			brzs(p,stdbuf,stdsiz/8); /* To avoid buffer overruns with my_iconv */
139 			/* Ignore comment and block structuring lines */
140 			if (!(stdbuf[0]=='{' ||
141 			    (stdbuf[0]=='/' && stdbuf[1]=='*') ||
142 			    stdbuf[0]=='\f' ||
143 			    (stdbuf[0]=='/' && stdbuf[1]=='/') ||
144 			    stdbuf[0]=='#' ||
145 			    (stdbuf[0]=='b' && stdbuf[1]=='e' && stdbuf[2]=='g' && stdbuf[3]=='i' && stdbuf[4]=='n') ||
146 			    (stdbuf[0]=='B' && stdbuf[1]=='E' && stdbuf[2]=='G' && stdbuf[3]=='I' && stdbuf[4]=='N') ||
147 			    (stdbuf[0]=='-' && stdbuf[1]=='-') ||
148 			    stdbuf[0]==';')) {
149 			    	/* zlcpy(buf1, SIZEOF(buf1), stdbuf); */
150  				/* replace tabs to spaces and remove adjoining spaces */
151  				for (i=0,j=0,spc=0; stdbuf[i]; i++) {
152  					if (stdbuf[i]=='\t' || stdbuf[i]==' ') {
153  						if (spc) continue;
154  						spc = 1;
155  					}
156  					else spc = 0;
157  					if (stdbuf[i]=='\t')
158  						buf1[j++] = ' ';
159 					else if (stdbuf[i]=='\\') {
160 						buf1[j++] = '\\';
161 						buf1[j++] = '\\';
162 					} else
163 						buf1[j++] = stdbuf[i];
164  				}
165  				buf1[j]= '\0';
166 				/* Uncomment to get the last line instead of the first line (see above)
167 			    	if (pprevl(p)) {
168 			    		p_goto_bol(p);
169 			    		if (!pisindent(p) && !pisblank(p))
170 			    			goto next;
171 			    	}
172 			    	*/
173 			    	break;
174 			}
175 
176 		}
177 	} while (!buf1[0] && pprevl(p));
178 
179 	prm(p);
180 
181 	return buf1;
182 }
183 #endif
184 
duplicate_backslashes(const char * s,ptrdiff_t len)185 char *duplicate_backslashes(const char *s, ptrdiff_t len)
186 {
187 	char *m;
188 	ptrdiff_t x, count;
189 	for (x = count = 0; x != len; ++x)
190 		if (s[x] == '\\')
191 			++count;
192 	m = vsmk(len + count);
193 	for (x = 0; x != len; ++x) {
194 		m = vsadd(m, s[x]);
195 		if (s[x] == '\\')
196 			m = vsadd(m, '\\');
197 	}
198 	return m;
199 }
200 
stagen(char * stalin,BW * bw,const char * s,char fill)201 char *stagen(char *stalin, BW *bw, const char *s, char fill)
202 {
203 	char buf[80];
204 	int x;
205 	int field;
206 	W *w = bw->parent;
207 	time_t n=time(NULL);
208 	struct tm *cas;
209 	cas=localtime(&n);
210 
211 	stalin = vstrunc(stalin, 0);
212 	while (*s) {
213 		if (*s == '%' && s[1]) {
214 			field = 0;
215 			++s;
216 			while (*s >= '0' && *s <= '9' && s[1]) {
217 				field = field * 10 + *s - '0';
218 				++s;
219 			}
220 			switch (*s) {
221 			case 'v': /* Version of JOE */
222 				{
223 					joe_snprintf_1(buf, SIZEOF(buf), "%s", VERSION);
224 					stalin = vsncpy(sv(stalin), sz(buf));
225 				}
226 				break;
227 
228 			case 'x': /* Context (but only if autoindent is enabled) */
229 				{
230 					if (bw->o.title) {
231 						const int *ts = get_context(bw);
232 						if (ts) {
233 							/* We need to translate between file's character set to
234 							   locale */
235 							my_iconv1(stdbuf, SIZEOF(stdbuf), locale_map,ts);
236 							stalin = vsncpy(sv(stalin), sz(stdbuf));
237 						}
238 					}
239 				}
240 				break;
241 
242 			case 'y':
243 				{
244 					if (bw->o.syntax) {
245 						joe_snprintf_1(buf, SIZEOF(buf), "(%s)", bw->o.syntax->name);
246 						stalin = vsncpy(sv(stalin), sz(buf));
247 					}
248 				}
249 				break;
250 			case 't':
251 				{
252 					time_t curtime = time(NULL);
253 					int l;
254 					char *d = ctime(&curtime);
255 
256 					l = (d[11] - '0') * 10 + d[12] - '0';
257 					if (l > 12)
258 						l -= 12;
259 					joe_snprintf_1(buf, SIZEOF(buf), "%2.2d", l);
260 					if (buf[0] == '0')
261 						buf[0] = fill;
262 					stalin = vsncpy(sv(stalin), buf, 2);
263 					stalin = vsncpy(sv(stalin), d + 13, 3);
264 				}
265 				break;
266 			case 'd':
267 				{
268 					if (s[1]) switch (*++s) {
269 						case 'd' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_mday); break;
270 						case 'm' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_mon + 1); break;
271 						case 'y' : joe_snprintf_1(buf, SIZEOF(buf), "%02d",cas->tm_year % 100); break;
272 						case 'Y' : joe_snprintf_1(buf, SIZEOF(buf), "%04d",cas->tm_year + 1900); break;
273 						case 'w' : joe_snprintf_1(buf, SIZEOF(buf), "%d",cas->tm_wday); break;
274 						case 'D' : joe_snprintf_1(buf, SIZEOF(buf), "%03d",cas->tm_yday); break;
275 						default : buf[0]='d'; buf[1]=*s; buf[2]=0;
276 					} else {
277 						buf[0]='d'; buf[1]=0;
278 					}
279 					stalin=vsncpy(sv(stalin),sz(buf));
280 				}
281 				break;
282 
283 			case 'E':
284 				{
285 					char *ch;
286 					int l;
287 					buf[0]=0;
288 					for(l=0;s[l+1] && s[l+1] != '%'; l++) buf[l]=s[l+1];
289 					if (s[l+1]=='%' && buf[0]) {
290 						buf[l]=0;
291 						s+=l+1;
292 						ch=getenv(buf);
293 						if (ch) stalin=vsncpy(sv(stalin),sz(ch));
294 					}
295 				}
296 				break;
297 
298 			case 'Z':
299 				{
300 					const char *ch;
301 					int l;
302 					buf[0]=0;
303 					for(l=0;s[l+1] && s[l+1] != '%'; l++) buf[l]=s[l+1];
304 					if (s[l+1]=='%' && buf[0]) {
305 						buf[l]=0;
306 						s+=l+1;
307 						ch=get_status(bw, buf);
308 						if (ch) stalin=vsncpy(sv(stalin),sz(ch));
309 					}
310 				}
311 				break;
312 
313 			case 'u':
314 				{
315 					time_t curtime = time(NULL);
316 					char *d = ctime(&curtime);
317 
318 					stalin = vsncpy(sv(stalin), d + 11, 5);
319 				}
320 				break;
321 			case 'T':
322 				if (bw->o.overtype)
323 					stalin = vsadd(stalin, 'O');
324 				else
325 					stalin = vsadd(stalin, 'I');
326 				break;
327 			case 'W':
328 				if (bw->o.wordwrap)
329 					stalin = vsadd(stalin, 'W');
330 				else
331 					stalin = vsadd(stalin, fill);
332 				break;
333 			case 'I':
334 				if (bw->o.autoindent)
335 					stalin = vsadd(stalin, 'A');
336 				else
337 					stalin = vsadd(stalin, fill);
338 				break;
339 			case 'X':
340 				if (square)
341 					stalin = vsadd(stalin, 'X');
342 				else
343 					stalin = vsadd(stalin, fill);
344 				break;
345 			case 'n':
346 				{
347 				if (bw->b->name) {
348 					char *tmp = simplify_prefix(bw->b->name);
349 					char *tmp1 = duplicate_backslashes(sv(tmp));
350 					vsrm(tmp);
351 					stalin = vsncpy(sv(stalin), sv(tmp1));
352 					vsrm(tmp1);
353 				} else {
354 					stalin = vsncpy(sv(stalin), sz(joe_gettext(_("Unnamed"))));
355 				}
356 				}
357 				break;
358 			case 'm':
359 				if (bw->b->changed)
360 					stalin = vsncpy(sv(stalin), sz(joe_gettext(_("(Modified)"))));
361 				break;
362 			case 'R':
363 				if (bw->b->rdonly)
364 					stalin = vsncpy(sv(stalin), sz(joe_gettext(_("(Read only)"))));
365 				break;
366 			case '*':
367 				if (bw->b->changed)
368 					stalin = vsadd(stalin, '*');
369 				else
370 					stalin = vsadd(stalin, fill);
371 				break;
372 			case 'r':
373 				if (field)
374 #ifdef HAVE_LONG_LONG
375 					joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)(bw->cursor->line + 1));
376 #else
377 					joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)(bw->cursor->line + 1));
378 #endif
379 				else
380 #ifdef HAVE_LONG_LONG
381 					joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(bw->cursor->line + 1));
382 #else
383 					joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(bw->cursor->line + 1));
384 #endif
385 				for (x = 0; buf[x]; ++x)
386 					if (buf[x] == ' ')
387 						buf[x] = fill;
388 				stalin = vsncpy(sv(stalin), sz(buf));
389 				break;
390 			case 'o':
391 				if (field)
392 #ifdef HAVE_LONG_LONG
393 					joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)bw->cursor->byte);
394 #else
395 					joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)bw->cursor->byte);
396 #endif
397 				else
398 #ifdef HAVE_LONG_LONG
399 					joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)bw->cursor->byte);
400 #else
401 					joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)bw->cursor->byte);
402 #endif
403 				for (x = 0; buf[x]; ++x)
404 					if (buf[x] == ' ')
405 						buf[x] = fill;
406 				stalin = vsncpy(sv(stalin), sz(buf));
407 				break;
408 			case 'O':
409 				if (field)
410 #ifdef HAVE_LONG_LONG
411 					joe_snprintf_1(buf, SIZEOF(buf), "%-4llX", (unsigned long long)bw->cursor->byte);
412 #else
413 					joe_snprintf_1(buf, SIZEOF(buf), "%-4lX", (unsigned long)bw->cursor->byte);
414 #endif
415 				else
416 #ifdef HAVE_LONG_LONG
417 					joe_snprintf_1(buf, SIZEOF(buf), "%llX", (unsigned long long)bw->cursor->byte);
418 #else
419 					joe_snprintf_1(buf, SIZEOF(buf), "%lX", (unsigned long)bw->cursor->byte);
420 #endif
421 				for (x = 0; buf[x]; ++x)
422 					if (buf[x] == ' ')
423 						buf[x] = fill;
424 				stalin = vsncpy(sv(stalin), sz(buf));
425 				break;
426 			case 'a':
427 				if (!piseof(bw->cursor))
428 					joe_snprintf_1(buf, SIZEOF(buf), "%3d", brch(bw->cursor));
429 				else
430 					joe_snprintf_0(buf, SIZEOF(buf), "   ");
431 				for (x = 0; buf[x]; ++x)
432 					if (buf[x] == ' ')
433 						buf[x] = fill;
434 				stalin = vsncpy(sv(stalin), sz(buf));
435 				break;
436 			case 'A':
437 				if (field)
438 					if (!piseof(bw->cursor))
439 						joe_snprintf_1(buf, SIZEOF(buf), "%2.2X", brch(bw->cursor));
440 					else
441 						joe_snprintf_0(buf, SIZEOF(buf), "  ");
442 				else
443 					if (!piseof(bw->cursor))
444 						joe_snprintf_1(buf, SIZEOF(buf), "%x", brch(bw->cursor));
445 					else
446 						joe_snprintf_0(buf, SIZEOF(buf), "");
447 				for (x = 0; buf[x]; ++x)
448 					if (buf[x] == ' ')
449 						buf[x] = fill;
450 				stalin = vsncpy(sv(stalin), sz(buf));
451 				break;
452 			case 'c':
453 				if (field)
454 #ifdef HAVE_LONG_LONG
455 					joe_snprintf_1(buf, SIZEOF(buf), "%-3lld", (long long)(piscol(bw->cursor) + 1));
456 #else
457 					joe_snprintf_1(buf, SIZEOF(buf), "%-3ld", (long)(piscol(bw->cursor) + 1));
458 #endif
459 				else
460 #ifdef HAVE_LONG_LONG
461 					joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(piscol(bw->cursor) + 1));
462 #else
463 					joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(piscol(bw->cursor) + 1));
464 #endif
465 				for (x = 0; buf[x]; ++x)
466 					if (buf[x] == ' ')
467 						buf[x] = fill;
468 				stalin = vsncpy(sv(stalin), sz(buf));
469 				break;
470 			case 'p':
471 				if (bw->b->eof->byte >= 1024*1024)
472 #ifdef HAVE_LONG_LONG
473 					joe_snprintf_1(buf, SIZEOF(buf), "%3lld", ((long long)bw->cursor->byte >> 10) * 100 / ((long long)bw->b->eof->byte >> 10));
474 #else
475 					joe_snprintf_1(buf, SIZEOF(buf), "%3ld", ((long)bw->cursor->byte >> 10) * 100 / ((long)bw->b->eof->byte >> 10));
476 #endif
477 				else if (bw->b->eof->byte)
478 #ifdef HAVE_LONG_LONG
479 					joe_snprintf_1(buf, SIZEOF(buf), "%3lld", (long long)bw->cursor->byte * 100 / (long long)bw->b->eof->byte);
480 #else
481 					joe_snprintf_1(buf, SIZEOF(buf), "%3ld", (long)bw->cursor->byte * 100 / (long)bw->b->eof->byte);
482 #endif
483 				else
484 					joe_snprintf_0(buf, SIZEOF(buf), "100");
485 				for (x = 0; buf[x]; ++x)
486 					if (buf[x] == ' ')
487 						buf[x] = fill;
488 				stalin = vsncpy(sv(stalin), sz(buf));
489 				break;
490 			case 'l':
491 				if (field)
492 #ifdef HAVE_LONG_LONG
493 					joe_snprintf_1(buf, SIZEOF(buf), "%-4lld", (long long)(bw->b->eof->line + 1));
494 #else
495 					joe_snprintf_1(buf, SIZEOF(buf), "%-4ld", (long)(bw->b->eof->line + 1));
496 #endif
497 				else
498 #ifdef HAVE_LONG_LONG
499 					joe_snprintf_1(buf, SIZEOF(buf), "%lld", (long long)(bw->b->eof->line + 1));
500 #else
501 					joe_snprintf_1(buf, SIZEOF(buf), "%ld", (long)(bw->b->eof->line + 1));
502 #endif
503 				for (x = 0; buf[x]; ++x)
504 					if (buf[x] == ' ')
505 						buf[x] = fill;
506 				stalin = vsncpy(sv(stalin), sz(buf));
507 				break;
508 			case 'k':
509 				{
510 					ptrdiff_t i;
511 					char *mycpos = buf;
512 
513 					buf[0] = 0;
514 					if (w->kbd->x && w->kbd->seq[0])
515 						for (i = 0; i != w->kbd->x; ++i) {
516 							char c = w->kbd->seq[i] & 127;
517 
518 							if (c < 32) {
519 								mycpos[0] = '^';
520 								mycpos[1] = (char)(c + '@');
521 								mycpos += 2;
522 							} else if (c == 127) {
523 								mycpos[0] = '^';
524 								mycpos[1] = '?';
525 								mycpos += 2;
526 							} else {
527 								mycpos[0] = c;
528 								mycpos += 1;
529 							}
530 						}
531 					*mycpos++ = fill;
532 					while (mycpos - buf < 4)
533 						*mycpos++ = fill;
534 					stalin = vsncpy(sv(stalin), buf, mycpos - buf);
535 				}
536 				break;
537 			case 'S':
538 				if (bw->b->pid)
539 					stalin = vsncpy(sv(stalin), sz(joe_gettext(_("*SHELL*"))));
540 				break;
541 			case 'M':
542 				if (recmac) {
543 					joe_snprintf_1(buf, SIZEOF(buf), joe_gettext(_("(Macro %d recording...)")), recmac->n);
544 					stalin = vsncpy(sv(stalin), sz(buf));
545 				}
546 				break;
547 			case 'e':
548 				stalin = vsncpy(sv(stalin), sz(bw->b->o.charmap->name));
549 				break;
550 			case 'b':
551 				stalin = vsncpy(sv(stalin), sz(locale_map->name));
552 				break;
553 			case 'w':
554 				if (!piseof(bw->cursor)) {
555 					joe_snprintf_1(buf, SIZEOF(buf), "%d", joe_wcwidth(bw->o.charmap->type, brch(bw->cursor)));
556 					stalin = vsncpy(sv(stalin), sz(buf));
557 				}
558 				break;
559 			default:
560 				stalin = vsadd(stalin, *s);
561 			}
562 		} else
563 			stalin = vsadd(stalin, *s);
564 		++s;
565 	}
566 	return stalin;
567 }
568 
disptw(W * w,int flg)569 static void disptw(W *w, int flg)
570 {
571 	BW *bw = (BW *)w->object;
572 	TW *tw = (TW *)bw->object;
573 	int newcols = calclincols(bw);
574 	int linchg = 0;
575 
576 	if (bw->lincols != newcols) {
577 		bw->lincols = newcols;
578 		resizetw(w, w->w, w->h);
579 		movetw(w, w->x, w->y);
580 		bwfllw(w);
581 		linchg = 1;
582 	}
583 
584 	if (bw->o.hex) {
585 		w->cury = TO_DIFF_OK((bw->cursor->byte-bw->top->byte)/16 + bw->y - w->y);
586 		w->curx = TO_DIFF_OK((bw->cursor->byte-bw->top->byte)%16 + 60 - bw->offset);
587 	} else {
588 		w->cury = TO_DIFF_OK(bw->cursor->line - bw->top->line + bw->y - w->y);
589 		w->curx = TO_DIFF_OK(bw->cursor->xcol - bw->offset + newcols);
590 	}
591 
592 	if ((staupd || keepup || bw->cursor->line != tw->prevline || bw->b->changed != tw->changed || bw->b != tw->prev_b) && (w->y || !staen) && w->h > 1) {
593 		char fill;
594 
595 		tw->prevline = bw->cursor->line;
596 		tw->changed = bw->b->changed;
597 		tw->prev_b = bw->b;
598 		if (bw->o.rmsg[0])
599 			fill = bw->o.rmsg[0];
600 		else
601 			fill = ' ';
602 		tw->stalin = stagen(tw->stalin, bw, bw->o.lmsg, fill);
603 		tw->staright = stagen(tw->staright, bw, bw->o.rmsg, fill);
604 		if (fmtlen(tw->staright) < w->w) {
605 			ptrdiff_t x = fmtpos(tw->stalin, w->w - fmtlen(tw->staright));
606 
607 			if (x > sLEN(tw->stalin))
608 				tw->stalin = vsfill(sv(tw->stalin), fill, x - sLEN(tw->stalin));
609 			tw->stalin = vsncpy(tw->stalin, fmtpos(tw->stalin, w->w - fmtlen(tw->staright)), sv(tw->staright));
610 		}
611 		tw->stalin = vstrunc(tw->stalin, fmtpos(tw->stalin, w->w));
612 		genfmt(w->t->t, w->x, w->y, 0, tw->stalin, bg_stalin, 0, 0);
613 		w->t->t->updtab[w->y] = 0;
614 	}
615 
616 	if (flg) {
617 		if (bw->o.hex)
618 			bwgenh(bw);
619 		else
620 			bwgen(bw, bw->o.linums, linchg);
621 	}
622 }
623 
624 /* Split current window */
625 
iztw(TW * tw,ptrdiff_t y)626 static void iztw(TW *tw, ptrdiff_t y)
627 {
628 	tw->stalin = NULL;
629 	tw->staright = NULL;
630 	tw->changed = -1;
631 	tw->prevline = -1;
632 	tw->staon = (!staen || y);
633 	tw->prev_b = 0;
634 }
635 
usplitw(W * w,int k)636 int usplitw(W *w, int k)
637 {
638 	BW *bw;
639 	ptrdiff_t newh = getgrouph(w);
640 	W *neww;
641 	TW *newtw;
642 	BW *newbw;
643 	WIND_BW(bw, w);
644 
645 	dostaupd = 1;
646 	if (newh / 2 < FITHEIGHT)
647 		return -1;
648 	neww = wcreate(w->t, w->watom, findbotw(w), NULL, w, newh / 2 + (newh & 1), NULL, NULL);
649 	if (!neww)
650 		return -1;
651 //	wfit(neww->t);
652 	neww->object = (void *) (newbw = bwmk(neww, bw->b, 0));
653 	++bw->b->count;
654 	newbw->offset = bw->offset;
655 	newbw->object = (void *) (newtw = (TW *) joe_malloc(SIZEOF(TW)));
656 	iztw(newtw, neww->y);
657 	pset(newbw->top, bw->top);
658 	pset(newbw->cursor, bw->cursor);
659 	newbw->cursor->xcol = bw->cursor->xcol;
660 	neww->t->curwin = neww;
661 	wfit(neww->t);
662 	return 0;
663 }
664 
uduptw(W * w,int k)665 int uduptw(W *w, int k)
666 {
667 	BW *bw;
668 	ptrdiff_t newh = getgrouph(w);
669 	W *neww;
670 	TW *newtw;
671 	BW *newbw;
672 	WIND_BW(bw, w);
673 
674 	dostaupd = 1;
675 	neww = wcreate(w->t, w->watom, findbotw(w), NULL, NULL, newh, NULL, NULL);
676 	if (!neww)
677 		return -1;
678 	if (demotegroup(w))
679 		neww->t->topwin = neww;
680 	neww->object = (void *) (newbw = bwmk(neww, bw->b, 0));
681 	++bw->b->count;
682 	newbw->offset = bw->offset;
683 	newbw->object = (void *) (newtw = (TW *) joe_malloc(SIZEOF(TW)));
684 	iztw(newtw, neww->y);
685 	pset(newbw->top, bw->top);
686 	pset(newbw->cursor, bw->cursor);
687 	newbw->cursor->xcol = bw->cursor->xcol;
688 	neww->t->curwin = neww;
689 	wfit(w->t);
690 	return 0;
691 }
692 
instw(W * w,B * b,off_t l,off_t n,int flg)693 static void instw(W *w, B *b, off_t l, off_t n, int flg)
694 {
695 	BW *bw = (BW *)w->object;
696 	if (b == bw->b)
697 		bwins(bw, l, n, flg);
698 }
699 
deltw(W * w,B * b,off_t l,off_t n,int flg)700 static void deltw(W *w, B *b, off_t l, off_t n, int flg)
701 {
702 	BW *bw = (BW *)w->object;
703 	if (b == bw->b)
704 		bwdel(bw, l, n, flg);
705 }
706 
707 WATOM watomtw = {
708 	"main",
709 	disptw,
710 	bwfllw,
711 	NULL,
712 	rtntw,
713 	utypew,
714 	resizetw,
715 	movetw,
716 	instw,
717 	deltw,
718 	TYPETW
719 };
720 
abortit(W * w,int k)721 int abortit(W *w, int k)
722 {
723 	BW *bw;
724 	TW *tw;
725 	B *b;
726 	WIND_BW(bw, w);
727 	if (bw->parent->watom != &watomtw)
728 		return wabort(bw->parent);
729 	if (bw->b->pid && bw->b->count==1)
730 		return ukillpid(bw->parent, 0);
731 	w = bw->parent;
732 	tw = (TW *) bw->object;
733 	/* If only one main window on the screen... */
734 	if (countmain(w->t) == 1)
735 		/* Replace it with an orphaned buffer if there are any */
736 		if ((b = borphan()) != NULL) {
737 			void *object = bw->object;
738 			/* FIXME: Shouldn't we wabort() and wcreate here to kill
739 			   any prompt windows? */
740 
741 			bwrm(bw);
742 			w->object = (void *) (bw = bwmk(w, b, 0));
743 			wredraw(bw->parent);
744 			bw->object = object;
745 			bw = (BW *)w->object;
746 			bw->cursor->xcol = piscol(bw->cursor);
747 			return 0;
748 		}
749 	bwrm(bw);
750 	vsrm(tw->stalin);
751 	joe_free(tw);
752 	w->object = NULL;
753 	wabort(w);	/* Eliminate this window and it's children */
754 	return 0;
755 }
756 
757 /* User routine for aborting a text window */
758 
naborttw(W * w,int k,void * object,int * notify)759 static int naborttw(W *w, int k, void *object, int *notify)
760 {
761 	BW *bw = (BW *)w->object;
762 	if (notify)
763 		*notify = 1;
764 	if (k != YES_CODE && !yncheck(yes_key, k))
765 		return -1;
766 
767 	if (bw->b->count == 1)
768 		genexmsg(bw, 0, NULL);
769 	return abortit(bw->parent, 0);
770 }
771 
naborttw1(W * w,int k,void * object,int * notify)772 static int naborttw1(W *w, int k, void *object, int *notify)
773 {
774 	BW *bw = (BW *)w->object;
775 	if (notify)
776 		*notify = 1;
777 	if (k != YES_CODE && !yncheck(yes_key, k))
778 		return -1;
779 
780 	if (!exmsg) genexmsg(bw, 0, NULL);
781 	return abortit(bw->parent, 0);
782 }
783 
wpop(BW * bw)784 static B *wpop(BW *bw)
785 {
786 	B *b;
787 	struct bstack *e = bw->parent->bstack;
788 	b = e->b;
789 	if (b->oldcur) prm(b->oldcur);
790 	if (b->oldtop) prm(b->oldtop);
791 	b->oldcur = e->cursor;
792 	b->oldtop = e->top;
793 	bw->parent->bstack = e->next;
794 	free(e);
795 	--b->count;
796 	return b;
797 }
798 
799 /* Pop, or do nothing if no window on stack */
upopabort(W * w,int k)800 int upopabort(W *w, int k)
801 {
802 	BW *bw;
803 	WIND_BW(bw, w);
804 	if (bw->parent->bstack) {
805 		int rtn;
806 		B *b = wpop(bw);
807 		w = bw->parent;
808 		rtn = get_buffer_in_window(bw, b);
809 		bw = (BW *)w->object;
810 		bw->cursor->xcol = piscol(bw->cursor);
811 		return rtn;
812 	} else {
813 		return 0;
814 	}
815 }
816 
817 /* k is last character types which lead to uabort.  If k is -1, it means uabort
818    was called internally, and not by the user: which means uabort will not send
819    Ctrl-C to process */
uabort(W * w,int k)820 int uabort(W *w, int k)
821 {
822 	BW *bw;
823 	if (w->watom != &watomtw)
824 		return wabort(w);
825 	WIND_BW(bw, w);
826 	if (markv(0) && markb->b == bw->b) {
827 		prm(markk);
828 		markk = 0;
829 		updall();
830 		return 0;
831 	}
832 	if (bw->parent->bstack) {
833 		int rtn;
834 		B *b = wpop(bw);
835 		w = bw->parent;
836 		rtn = get_buffer_in_window(bw, b);
837 		bw = (BW *)w->object;
838 		bw->cursor->xcol = piscol(bw->cursor);
839 		return rtn;
840 	}
841 	if (bw->b->pid && bw->b->count==1)
842 		return ukillpid(bw->parent, 0);
843 	if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
844 		if (mkqw(w, sz(joe_gettext(_("Lose changes to this file (y,n,%{abort})? "))), naborttw, NULL, NULL, NULL))
845 			return 0;
846 		else
847 			return -1;
848 	else
849 		return naborttw(bw->parent, YES_CODE, NULL, NULL);
850 }
851 
ucancel(W * w,int k)852 int ucancel(W *w, int k)
853 {
854 	if (w->watom != &watomtw) {
855 		wabort(w);
856 		return 0;
857 	} else
858 		return uabort(w, k);
859 }
860 
861 /* Same as above, but only calls genexmsg if nobody else has */
862 
uabort1(W * w,int k)863 int uabort1(W *w, int k)
864 {
865 	BW *bw;
866 	if (w->watom != &watomtw)
867 		return wabort(w);
868 	bw = (BW *)w->object;
869 	if (bw->b->pid && bw->b->count==1)
870 		return ukillpid(bw->parent, 0);
871 	if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
872 		if (mkqw(w, sz(joe_gettext(_("Lose changes to this file (y,n,%{abort})? "))), naborttw1, NULL, NULL, NULL))
873 			return 0;
874 		else
875 			return -1;
876 	else
877 		return naborttw1(w, YES_CODE, NULL, NULL);
878 }
879 
880 /* Abort buffer without prompting: just fail if this is last window on buffer */
881 
uabortbuf(W * w,int k)882 int uabortbuf(W *w, int k)
883 {
884 	BW *bw;
885 	B *b;
886 
887 	WIND_BW(bw, w);
888 
889 	if (bw->b->pid && bw->b->count==1)
890 		return ukillpid(w, 0);
891 
892 	if (okrepl(bw))
893 		return -1;
894 
895 	if ((b = borphan()) != NULL) {
896 		void *object = bw->object;
897 
898 		bwrm(bw);
899 		w->object = (void *) (bw = bwmk(w, b, 0));
900 		wredraw(bw->parent);
901 		bw->object = object;
902 		return 0;
903 	}
904 
905 	return naborttw(w, YES_CODE, NULL, NULL);
906 }
907 
908 /* Kill current window (orphans buffer) */
909 
utw0(W * w,int k)910 int utw0(W *w, int k)
911 {
912 	BW *bw;
913 	w = w->main;
914 	bw = (BW *)w->object;
915 
916 	if (w->bstack)
917 		return uabort(w, -1);
918 	if (countmain(w->t) == 1)
919 		return -1;
920 	if (bw->b->count == 1)
921 		orphit(bw);
922 	return uabort(w, -1);
923 }
924 
925 /* Kill all other windows (orphans buffers) */
926 
utw1(W * w,int k)927 int utw1(W *w, int k)
928 {
929 	W *starting = w;
930 	W *mainw = starting->main;
931 	Screen *t = mainw->t;
932 	int myyn;
933 
934 	do {
935 		myyn = 0;
936 	      loop:
937 		do {
938 			wnext(t);
939 		} while (t->curwin->main == mainw && t->curwin != starting);
940 		if (t->curwin->main != mainw) {
941 			utw0(t->curwin->main, 0);
942 			myyn = 1;
943 			goto loop;
944 		}
945 	} while (myyn);
946 	return 0;
947 }
948 
setline(B * b,off_t line)949 void setline(B *b, off_t line)
950 {
951 	W *w = maint->curwin;
952 
953 	do {
954 		if (w->watom->what == TYPETW) {
955 			BW *bw = (BW *)w->object;
956 
957 			if (bw->b == b) {
958 				off_t oline = bw->top->line;
959 
960 				/* pline(bw->top, line); */
961 				pline(bw->cursor, line);
962 				if (!bw->b->err)
963 					bw->b->err = pdup(bw->cursor, "setline");
964 				pline(bw->b->err, line);
965 				if (w->y >= 0 && bw->top->line > oline && bw->top->line - oline < bw->h)
966 					nscrlup(w->t->t, bw->y, bw->y + bw->h, (int) (bw->top->line - oline));
967 				else if (w->y >= 0 && bw->top->line < oline && oline - bw->top->line < bw->h)
968 					nscrldn(w->t->t, bw->y, bw->y + bw->h, (int) (oline - bw->top->line));
969 				msetI(bw->t->t->updtab + bw->y, 1, bw->h);
970 			}
971 		}
972 	} while ((w = w->link.next) != maint->curwin);
973 	/* In case error buffer was orphaned */
974 	if (errbuf == b && b->oldcur) {
975 		pline(b->oldcur, line);
976 		if (!b->err)
977 			b->err = pdup(b->oldcur, ("setline1"));
978 		pline(b->err, line);
979 	}
980 }
981 
982 /* Create a text window.  It becomes the last window on the screen */
983 
wmktw(Screen * t,B * b)984 BW *wmktw(Screen *t, B *b)
985 {
986 	W *w;
987 	BW *bw;
988 	TW *tw;
989 
990 	w = wcreate(t, &watomtw, NULL, NULL, NULL, t->h, NULL, NULL);
991 	wfit(w->t);
992 	w->object = (void *) (bw = bwmk(w, b, 0));
993 	bw->object = (void *) (tw = (TW *) joe_malloc(SIZEOF(TW)));
994 	iztw(tw, w->y);
995 	return bw;
996 }
997