we’ll need to distinguish these for sarge/etch as well
[alioth/jupp.git] / tw.c
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 "config.h"
9 #include "types.h"
10
11 __RCSID("$MirOS: contrib/code/jupp/tw.c,v 1.13 2017/12/02 02:07:33 tg Exp $");
12
13 #include <stdlib.h>
14 #include <string.h>
15 #ifdef HAVE_TIME_H
16 #include <time.h>
17 #endif
18
19 #ifdef HAVE_BSD_STRING_H
20 #include <bsd/string.h>
21 #endif
22
23 #include "b.h"
24 #include "bw.h"
25 #include "macro.h"
26 #include "main.h"
27 #include "qw.h"
28 #include "scrn.h"
29 #include "uedit.h"
30 #include "ufile.h"
31 #include "ushell.h"
32 #include "utils.h"
33 #include "vs.h"
34 #include "syntax.h"
35 #include "charmap.h"
36 #include "w.h"
37
38 #if !HAVE_DECL_CTIME
39 char *ctime(const time_t *);
40 #endif
41
42 extern int square;
43 int staen = 0;
44 int staupd = 0;
45 int keepup = 0;
46
47 /* Move text window */
48
49 static void movetw(BW *bw, int x, int y)
50 {
51         TW *tw = (TW *) bw->object;
52
53         if (y || !staen) {
54                 if (!tw->staon) {       /* Scroll down and shrink */
55                         nscrldn(bw->parent->t->t, y, bw->parent->nh + y, 1);
56                 }
57                 bwmove(bw, x + (bw->o.linums ? LINCOLS : 0), y + 1);
58                 tw->staon = 1;
59         } else {
60                 if (tw->staon) {        /* Scroll up and grow */
61                         nscrlup(bw->parent->t->t, y, bw->parent->nh + y, 1);
62                 }
63                 bwmove(bw, x + (bw->o.linums ? LINCOLS : 0), y);
64                 tw->staon = 0;
65         }
66 }
67
68 /* Resize text window */
69
70 static void resizetw(BW *bw, int wi, int he)
71 {
72         if (bw->parent->ny || !staen)
73                 bwresz(bw, wi - (bw->o.linums ? LINCOLS : 0), he - 1);
74         else
75                 bwresz(bw, wi - (bw->o.linums ? LINCOLS : 0), he);
76 }
77
78 /* Get current context */
79
80 /* Find first line (going backwards) which has 0 indentation level
81  * and is not a comment, blank, or block structuring line.  This is
82  * likely to be the line with the function name.
83  *
84  * There are actually two possibilities:
85  *
86  * We want the first line- 
87  *
88  * int
89  * foo(int x,int y) {
90  *
91  *   }
92  *
93  * We want the last line-
94  *
95  * program foo(input,output);
96  * var a, b, c : real;
97  * begin
98  *
99  */
100
101 unsigned char *get_context(BW *bw)
102 {
103         P *p = pdup(bw->cursor);
104         static unsigned char buf1[stdsiz];
105
106
107         buf1[0] = 0;
108         /* Find first line with 0 indentation which is not a comment line */
109         do {
110                 p_goto_bol(p);
111                 if (!pisindent(p) && !pisblank(p)) {
112                         /* Uncomment to get the last line instead of the first line (see above)
113                         next:
114                         */
115                         brzs(p,stdbuf,stdsiz-1);
116                         /* Ignore comment and block structuring lines */
117                         if (!(stdbuf[0]=='{' ||
118                             (stdbuf[0]=='/' && stdbuf[1]=='*') ||
119                             (stdbuf[0]=='\f') ||
120                             (stdbuf[0]=='/' && stdbuf[1]=='/') ||
121                             (stdbuf[0]=='#') ||
122                             (stdbuf[0]=='b' && stdbuf[1]=='e' && stdbuf[2]=='g' && stdbuf[3]=='i' && stdbuf[4]=='n') ||
123                             (stdbuf[0]=='B' && stdbuf[1]=='E' && stdbuf[2]=='G' && stdbuf[3]=='I' && stdbuf[4]=='N') ||
124                             (stdbuf[0]=='-' && stdbuf[1]=='-') ||
125                             stdbuf[0]==';')) {
126                                 strlcpy(buf1,stdbuf,stdsiz);
127                                 /* Uncomment to get the last line instead of the first line (see above)
128                                 if (pprevl(p)) {
129                                         p_goto_bol(p);
130                                         if (!pisindent(p) && !pisblank(p))
131                                                 goto next;
132                                 }
133                                 */
134                                 break;
135                         }
136                         
137                 }
138         } while (!buf1[0] && pprevl(p));
139
140         prm(p);
141
142         return buf1;
143 }
144
145 static unsigned char *stagen(unsigned char *stalin, BW *bw, unsigned char *s, int fill)
146 {
147         unsigned char *cp, *cp2, uc;
148         unsigned char buf[80];
149         int x;
150         W *w = bw->parent;
151         time_t tt;
152         int special_aA = 0;
153
154         cp = s;
155         while ((cp2 = strstr(cp, "%a")) != NULL) {
156                 cp2 += /* %a */ 2;
157                 if (cp2[1] == '%')
158                         ++cp2;
159                 if (cp2[0] == '%' && cp2[1] == 'A') {
160                         special_aA = 1;
161                         break;
162                 }
163         }
164         if (!special_aA) while ((cp2 = strstr(cp, "%A")) != NULL) {
165                 cp2 += /* %A */ 2;
166                 if (cp2[1] == '%')
167                         ++cp2;
168                 if (cp2[0] == '%' && cp2[1] == 'a') {
169                         special_aA = 1;
170                         break;
171                 }
172         }
173
174         stalin = vstrunc(stalin, 0);
175         while (*s) {
176                 if (*s == '%' && s[1]) {
177                         switch (*++s) {
178                         case 'x':
179                                 /* Context (but only if autoindent is enabled) */
180                                 if (bw->o.autoindent) {
181                                         cp = get_context(bw);
182                                         stalin = vsncpy(sv(stalin), sz(cp));
183                                 }
184                                 break;
185
186                         case 'y':
187                                 if (bw->o.syntax) {
188                                         joe_snprintf_1((char *)buf, sizeof(buf), "(%s)", bw->o.syntax->name);
189                                         stalin = vsncpy(sv(stalin), sz(buf));
190                                 }
191                                 break;
192                         case 't':
193                                 tt = time(NULL);
194                                 cp = (unsigned char *)ctime(&tt);
195
196                                 x = (cp[11] - '0') * 10 + cp[12] - '0';
197                                 if (x > 12)
198                                         x -= 12;
199                                 joe_snprintf_1((char *)buf, sizeof(buf), "%2.2d", x);
200                                 if (buf[0] == '0')
201                                         buf[0] = fill;
202                                 stalin = vsncpy(sv(stalin), buf, 2);
203                                 stalin = vsncpy(sv(stalin), cp + 13, 3);
204                                 break;
205                         case 'u':
206                                 tt = time(NULL);
207                                 cp = (unsigned char *)ctime(&tt);
208                                 stalin = vsncpy(sv(stalin), cp + 11, 5);
209                                 break;
210                         case 'T':
211                                 if (bw->o.overtype)
212                                         stalin = vsadd(stalin, 'O');
213                                 else
214                                         stalin = vsadd(stalin, 'I');
215                                 break;
216                         case 'W':
217                                 if (bw->o.wordwrap)
218                                         stalin = vsadd(stalin, 'W');
219                                 else
220                                         stalin = vsadd(stalin, fill);
221                                 break;
222                         case 'I':
223                                 if (bw->o.autoindent)
224                                         stalin = vsadd(stalin, 'A');
225                                 else
226                                         stalin = vsadd(stalin, fill);
227                                 break;
228                         case 'X':
229                                 if (square)
230                                         stalin = vsadd(stalin, 'X');
231                                 else
232                                         stalin = vsadd(stalin, fill);
233                                 break;
234                         case 'n':
235                                 if (!bw->b->name) {
236                                         stalin = vsncpy(sv(stalin), sc("Unnamed"));
237                                         break;
238                                 }
239                                 cp = bw->b->name;
240  escape_loop:
241                                 switch ((uc = *cp++)) {
242                                 case '\\':
243                                         stalin = vsadd(stalin, uc);
244                                         /* FALLTHROUGH */
245                                 default:
246                                         stalin = vsadd(stalin, uc);
247                                         goto escape_loop;
248                                 case '\0':
249                                         break;
250                                 }
251                                 break;
252                         case 'm':
253                                 if (bw->b->changed)
254                                         stalin = vsncpy(sv(stalin), sc("(Modified)"));
255                                 break;
256                         case 'R':
257                                 if (bw->b->rdonly)
258                                         stalin = vsncpy(sv(stalin), sc("(Read only)"));
259                                 break;
260                         case '*':
261                                 if (bw->b->changed)
262                                         stalin = vsadd(stalin, '*');
263                                 else
264                                         stalin = vsadd(stalin, fill);
265                                 break;
266                         case 'r':
267                                 joe_snprintf_1((char *)buf, sizeof(buf), "%-4ld", bw->cursor->line + 1);
268                                 for (x = 0; buf[x]; ++x)
269                                         if (buf[x] == ' ')
270                                                 buf[x] = fill;
271                                 stalin = vsncpy(sv(stalin), sz(buf));
272                                 break;
273                         case 'o':
274                                 joe_snprintf_1((char *)buf, sizeof(buf), "%-4ld", bw->cursor->byte);
275                                 for (x = 0; buf[x]; ++x)
276                                         if (buf[x] == ' ')
277                                                 buf[x] = fill;
278                                 stalin = vsncpy(sv(stalin), sz(buf));
279                                 break;
280                         case 'O':
281                                 joe_snprintf_1((char *)buf, sizeof(buf), "%-4lX", bw->cursor->byte);
282                                 for (x = 0; buf[x]; ++x)
283                                         if (buf[x] == ' ')
284                                                 buf[x] = fill;
285                                 stalin = vsncpy(sv(stalin), sz(buf));
286                                 break;
287                         case 'a':
288                                 if (bw->b->o.charmap->type && !(special_aA && brch(bw->cursor) == 0x1000FFFE)) {
289                                         /* UTF-8: don't display decimal value */
290                                         buf[0] = 'u';
291                                         buf[1] = 0;
292                                 } else {
293                                         if (!piseof(bw->cursor))
294                                                 joe_snprintf_1((char *)buf, sizeof(buf), "%3d", 255 & brc(bw->cursor));
295                                         else
296                                                 joe_snprintf_0((char *)buf, sizeof(buf), "   ");
297                                         for (x = 0; buf[x]; ++x)
298                                                 if (buf[x] == ' ')
299                                                         buf[x] = fill;
300                                 }
301                                 stalin = vsncpy(sv(stalin), sz(buf));
302                                 break;
303                         case 'A':
304                                 if (bw->b->o.charmap->type) {
305                                         /* UTF-8, display UCS-2 value */
306                                         if (!piseof(bw->cursor)) {
307                                                 int uch = brch(bw->cursor);
308                                                 if (uch == 0x1000FFFE)
309                                                         joe_snprintf_1((char *)buf, sizeof(buf), special_aA ? "%02X" : "  %02X", 255 & brc(bw->cursor));
310                                                 else if (uch == 0x1000FFFF)
311                                                         joe_snprintf_0((char *)buf, sizeof(buf), "<-2>");
312                                                 else
313                                                         joe_snprintf_1((char *)buf, sizeof(buf), "%04X", uch);
314                                         } else
315                                                 joe_snprintf_0((char *)buf, sizeof(buf), "    ");
316                                 } else {
317                                         if (!piseof(bw->cursor))
318                                                 joe_snprintf_1((char *)buf, sizeof(buf), "%2.2X", 255 & brc(bw->cursor));
319                                         else
320                                                 joe_snprintf_0((char *)buf, sizeof(buf), "  ");
321                                 }
322                                 for (x = 0; buf[x]; ++x)
323                                         if (buf[x] == ' ')
324                                                 buf[x] = fill;
325                                 stalin = vsncpy(sv(stalin), sz(buf));
326                                 break;
327                         case 'c':
328                                 joe_snprintf_1((char *)buf, sizeof(buf), "%-3ld", piscol(bw->cursor) + 1);
329                                 for (x = 0; buf[x]; ++x)
330                                         if (buf[x] == ' ')
331                                                 buf[x] = fill;
332                                 stalin = vsncpy(sv(stalin), sz(buf));
333                                 break;
334                         case 'p':
335                                 if (bw->b->eof->byte)
336                                         joe_snprintf_1((char *)buf, sizeof(buf), "%3ld", bw->cursor->byte * 100 / bw->b->eof->byte);
337                                 else
338                                         joe_snprintf_0((char *)buf, sizeof(buf), "100");
339                                 for (x = 0; buf[x]; ++x)
340                                         if (buf[x] == ' ')
341                                                 buf[x] = fill;
342                                 stalin = vsncpy(sv(stalin), sz(buf));
343                                 break;
344                         case 'l':
345                                 joe_snprintf_1((char *)buf, sizeof(buf), "%-4ld", bw->b->eof->line + 1);
346                                 for (x = 0; buf[x]; ++x)
347                                         if (buf[x] == ' ')
348                                                 buf[x] = fill;
349                                 stalin = vsncpy(sv(stalin), sz(buf));
350                                 break;
351                         case 'k':
352                                 cp = buf;
353                                 buf[0] = 0;
354                                 if (w->kbd->x && w->kbd->seq[0])
355                                         for (x = 0; x != w->kbd->x; ++x) {
356                                                 uc = w->kbd->seq[x] & 127;
357
358                                                 if (uc < 32) {
359                                                         cp[0] = '^';
360                                                         cp[1] = uc + '@';
361                                                         cp += 2;
362                                                 } else if (uc == 127) {
363                                                         cp[0] = '^';
364                                                         cp[1] = '?';
365                                                         cp += 2;
366                                                 } else {
367                                                         cp[0] = uc;
368                                                         cp += 1;
369                                                 }
370                                         }
371                                 *cp++ = fill;
372                                 while (cp - buf < 4)
373                                         *cp++ = fill;
374                                 stalin = vsncpy(sv(stalin), buf, cp - buf);
375                                 break;
376                         case 'S':
377                                 if (bw->b->pid)
378                                         stalin = vsncpy(sv(stalin), sc("*SHELL*"));
379                                 break;
380                         case 'M':
381                                 if (recmac) {
382                                         joe_snprintf_1((char *)buf, sizeof(buf), "(Macro %d recording...)", recmac->n);
383                                         stalin = vsncpy(sv(stalin), sz(buf));
384                                 }
385                                 break;
386                         default:
387                                 stalin = vsadd(stalin, *s);
388                         }
389                 } else
390                         stalin = vsadd(stalin, *s);
391                 ++s;
392         }
393         return stalin;
394 }
395
396 static void disptw(BW *bw, int flg)
397 {
398         W *w = bw->parent;
399         TW *tw = (TW *) bw->object;
400
401         if (bw->o.linums != bw->linums) {
402                 bw->linums = bw->o.linums;
403                 resizetw(bw, w->w, w->h);
404                 movetw(bw, w->x, w->y);
405                 bwfllw(bw);
406         }
407
408         if (bw->o.hex) {
409                 w->cury = (bw->cursor->byte-bw->top->byte)/16 + bw->y - w->y;
410                 w->curx = (bw->cursor->byte-bw->top->byte)%16 + 60 - bw->offset;
411         } else {
412                 w->cury = bw->cursor->line - bw->top->line + bw->y - w->y;
413                 w->curx = bw->cursor->xcol - bw->offset + (bw->o.linums ? LINCOLS : 0);
414         }
415
416         if ((staupd || keepup || bw->cursor->line != tw->prevline || bw->b->changed != tw->changed || bw->b != tw->prev_b) && (w->y || !staen)) {
417                 int fill;
418
419                 tw->prevline = bw->cursor->line;
420                 tw->changed = bw->b->changed;
421                 tw->prev_b = bw->b;
422                 if (bw->o.rmsg[0])
423                         fill = bw->o.rmsg[0];
424                 else
425                         fill = ' ';
426                 tw->stalin = stagen(tw->stalin, bw, bw->o.lmsg, fill);
427                 tw->staright = stagen(tw->staright, bw, bw->o.rmsg, fill);
428                 if (fmtlen(tw->staright) < w->w) {
429                         int x = fmtpos(tw->stalin, w->w - fmtlen(tw->staright));
430
431                         if (x > sLEN(tw->stalin))
432                                 tw->stalin = vsfill(sv(tw->stalin), fill, x - sLEN(tw->stalin));
433                         tw->stalin = vsncpy(tw->stalin, fmtpos(tw->stalin, w->w - fmtlen(tw->staright)), sv(tw->staright));
434                 }
435                 tw->stalin = vstrunc(tw->stalin, fmtpos(tw->stalin, w->w));
436                 genfmt(w->t->t, w->x, w->y, 0, tw->stalin, 0);
437                 w->t->t->updtab[w->y] = 0;
438         }
439
440         if (flg) {
441                 if (bw->o.hex)
442                         bwgenh(bw);
443                 else
444                         bwgen(bw, bw->o.linums);
445         }
446 }
447
448 /* Split current window */
449
450 static void iztw(TW *tw, int y)
451 {
452         tw->stalin = NULL;
453         tw->staright = NULL;
454         tw->changed = -1;
455         tw->prevline = -1;
456         tw->staon = (!staen || y);
457         tw->prev_b = 0;
458 }
459
460 extern int dostaupd;
461
462 int usplitw(BW *bw)
463 {
464         W *w = bw->parent;
465         int newh = getgrouph(w);
466         W *new;
467         TW *newtw;
468         BW *newbw;
469
470         dostaupd = 1;
471         if (newh / 2 < FITHEIGHT)
472                 return -1;
473         new = wcreate(w->t, w->watom, findbotw(w), NULL, w, newh / 2 + (newh & 1), NULL, NULL);
474         if (!new)
475                 return -1;
476         wfit(new->t);
477         new->object = (void *) (newbw = bwmk(new, bw->b, 0));
478         ++bw->b->count;
479         newbw->offset = bw->offset;
480         newbw->object = (void *) (newtw = (TW *) joe_malloc(sizeof(TW)));
481         iztw(newtw, new->y);
482         pset(newbw->top, bw->top);
483         pset(newbw->cursor, bw->cursor);
484         newbw->cursor->xcol = bw->cursor->xcol;
485         new->t->curwin = new;
486         return 0;
487 }
488
489 int uduptw(BW *bw)
490 {
491         W *w = bw->parent;
492         int newh = getgrouph(w);
493         W *new;
494         TW *newtw;
495         BW *newbw;
496
497         dostaupd = 1;
498         new = wcreate(w->t, w->watom, findbotw(w), NULL, NULL, newh, NULL, NULL);
499         if (!new)
500                 return -1;
501         if (demotegroup(w))
502                 new->t->topwin = new;
503         new->object = (void *) (newbw = bwmk(new, bw->b, 0));
504         ++bw->b->count;
505         newbw->offset = bw->offset;
506         newbw->object = (void *) (newtw = (TW *) joe_malloc(sizeof(TW)));
507         iztw(newtw, new->y);
508         pset(newbw->top, bw->top);
509         pset(newbw->cursor, bw->cursor);
510         newbw->cursor->xcol = bw->cursor->xcol;
511         new->t->curwin = new;
512         wfit(w->t);
513         return 0;
514 }
515
516 static void instw(BW *bw, B *b, long int l, long int n, int flg)
517 {
518         if (b == bw->b)
519                 bwins(bw, l, n, flg);
520 }
521
522 static void deltw(BW *bw, B *b, long int l, long int n, int flg)
523 {
524         if (b == bw->b)
525                 bwdel(bw, l, n, flg);
526 }
527
528 WATOM watomtw = {
529         US "main",
530         disptw,
531         bwfllw,
532         NULL,
533         rtntw,
534         utypebw,
535         resizetw,
536         movetw,
537         instw,
538         deltw,
539         TYPETW
540 };
541
542 int abortit(BW *bw)
543 {
544         W *w;
545         TW *tw;
546         B *b;
547         if (bw->parent->watom != &watomtw)
548                 return wabort(bw->parent);
549         if (bw->b->pid && bw->b->count==1)
550                 return ukillpid(bw);
551         w = bw->parent;
552         tw = (TW *) bw->object;
553         /* If only one main window on the screen... */
554         if (countmain(w->t) == 1)
555                 /* Replace it with an orphaned buffer if there are any */
556                 if ((b = borphan()) != NULL) {
557                         void *object = bw->object;
558                         /* FIXME: Shouldn't we wabort() and wcreate here to kill
559                            any prompt windows? */
560
561                         bwrm(bw);
562                         w->object = (void *) (bw = bwmk(w, b, 0));
563                         wredraw(bw->parent);
564                         bw->object = object;
565                         return 0;
566                 }
567         bwrm(bw);
568         vsrm(tw->stalin);
569         joe_free(tw);
570         w->object = NULL;
571         wabort(w);      /* Eliminate this window and it's children */
572         return 0;
573 }
574
575 /* User routine for aborting a text window */
576
577 static int naborttw(BW *bw, int k, void *object, int *notify)
578 {
579         if (notify)
580                 *notify = 1;
581         if (k != 'y' && k != 'Y')
582                 return -1;
583
584         genexmsg(bw, 0, NULL);
585         return abortit(bw);
586 }
587
588 static int naborttw1(BW *bw, int k, void *object, int *notify)
589 {
590         if (notify)
591                 *notify = 1;
592         if (k != 'y' && k != 'Y')
593                 return -1;
594
595         if (!exmsg) genexmsg(bw, 0, NULL);
596         return abortit(bw);
597 }
598
599 /* k is last character types which lead to uabort.  If k is -1, it means uabort
600    was called internally, and not by the user: which means uabort will not send
601    Ctrl-C to process */
602 int uabort(BW *bw, int k)
603 {
604         if (bw->parent->watom != &watomtw)
605                 return wabort(bw->parent);
606         if (bw->b->pid && bw->b->count==1)
607                 return ukillpid(bw);
608         if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
609                 if (mkqw(bw->parent, sc("Lose changes to this file (y,n,^C)? "), naborttw, NULL, NULL, NULL))
610                         return 0;
611                 else
612                         return -1;
613         else
614                 return naborttw(bw, 'y', NULL, NULL);
615 }
616
617 int ucancel(BW *bw, int k)
618 {
619         if (bw->parent->watom != &watomtw) {
620                 wabort(bw->parent);
621                 return 0;
622         } else
623                 return uabort(bw,k);
624 }
625
626 /* Same as above, but only calls genexmsg if nobody else has */
627
628 int uabort1(BW *bw, int k)
629 {
630         if (bw->parent->watom != &watomtw)
631                 return wabort(bw->parent);
632         if (bw->b->pid && bw->b->count==1)
633                 return ukillpid(bw);
634         if (bw->b->changed && bw->b->count == 1 && !bw->b->scratch)
635                 if (mkqw(bw->parent, sc("Lose changes to this file (y,n,^C)? "), naborttw1, NULL, NULL, NULL))
636                         return 0;
637                 else
638                         return -1;
639         else
640                 return naborttw1(bw, 'y', NULL, NULL);
641 }
642
643 /* Abort buffer without prompting: just fail if this is last window on buffer */
644
645 int uabortbuf(BW *bw)
646 {
647         W *w = bw->parent;
648         B *b;
649
650         if (bw->b->pid && bw->b->count==1)
651                 return ukillpid(bw);
652
653         if (okrepl(bw))
654                 return -1;
655
656         if ((b = borphan()) != NULL) {
657                 void *object = bw->object;
658
659                 bwrm(bw);
660                 w->object = (void *) (bw = bwmk(w, b, 0));
661                 wredraw(bw->parent);
662                 bw->object = object;
663                 return 0;
664         }
665
666         return naborttw(bw, 'y', NULL, NULL);
667 }
668
669 /* Kill current window (orphans buffer) */
670
671 int utw0(BASE *b)
672 {
673         BW *bw = b->parent->main->object;
674
675         if (countmain(b->parent->t) == 1)
676                 return -1;
677         if (bw->b->count == 1)
678                 orphit(bw);
679         return uabort(bw, -1);
680 }
681
682 /* Kill all other windows (orphans buffers) */
683
684 int utw1(BASE *b)
685 {
686         W *starting = b->parent;
687         W *mainw = starting->main;
688         SCREEN *t = mainw->t;
689         int yn;
690
691         do {
692                 yn = 0;
693               loop:
694                 do {
695                         wnext(t);
696                 } while (t->curwin->main == mainw && t->curwin != starting);
697                 if (t->curwin->main != mainw) {
698                         BW *bw = t->curwin->main->object;
699                         utw0((BASE *)bw);
700                         yn = 1;
701                         goto loop;
702                 }
703         } while (yn);
704         return 0;
705 }
706
707 void setline(B *b, long int line)
708 {
709         W *w = maint->curwin;
710
711         do {
712                 if (w->watom->what == TYPETW) {
713                         BW *bw = w->object;
714
715                         if (bw->b == b) {
716                                 long oline = bw->top->line;
717
718                                 pline(bw->top, line);
719                                 pline(bw->cursor, line);
720                                 if (w->y >= 0 && bw->top->line > oline && bw->top->line - oline < bw->h)
721                                         nscrlup(w->t->t, bw->y, bw->y + bw->h, (int) (bw->top->line - oline));
722                                 else if (w->y >= 0 && bw->top->line < oline && oline - bw->top->line < bw->h)
723                                         nscrldn(w->t->t, bw->y, bw->y + bw->h, (int) (oline - bw->top->line));
724                         }
725                 }
726         } while ((w = w->link.next) != maint->curwin);
727 }
728
729 /* Create a text window.  It becomes the last window on the screen */
730
731 BW *wmktw(SCREEN *t, B *b)
732 {
733         W *w;
734         BW *bw;
735         TW *tw;
736
737         w = wcreate(t, &watomtw, NULL, NULL, NULL, t->h, NULL, NULL);
738         wfit(w->t);
739         w->object = (void *) (bw = bwmk(w, b, 0));
740         bw->object = (void *) (tw = (TW *) joe_malloc(sizeof(TW)));
741         iztw(tw, w->y);
742         return bw;
743 }