another update from CVS HEAD, for QA
[alioth/jupp.git] / bw.c
1 /*
2  *      Edit buffer window generation
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/bw.c,v 1.33 2017/12/08 02:28:04 tg Exp $");
12
13 #include <string.h>
14 #include <stdlib.h>
15 #include <limits.h>
16
17 #ifdef HAVE_BSD_STRING_H
18 #include <bsd/string.h>
19 #endif
20
21 #include "b.h"
22 #include "bw.h"
23 #include "blocks.h"
24 #include "kbd.h"
25 #include "rc.h"
26 #include "scrn.h"
27 #include "ublock.h"
28 #include "utils.h"
29 #include "syntax.h"
30 #include "charmap.h"
31 #include "w.h"
32
33 /* Display modes */
34 int dspasis = 0;
35 int marking = 0;
36 extern int staen;
37 extern SCREEN *maint;
38
39 static P *getto(P *p, P *cur, P *top, long int line)
40 {
41
42         if (p == NULL) {
43                 P *best = cur;
44                 long dist = LONG_MAX;
45                 long d;
46
47                 d = (line >= cur->line ? line - cur->line : cur->line - line);
48                 if (d < dist) {
49                         dist = d;
50                         best = cur;
51                 }
52                 d = (line >= top->line ? line - top->line : top->line - line);
53                 if (d < dist) {
54                         /* dead store: dist = d; */
55                         best = top;
56                 }
57                 p = pdup(best);
58                 p_goto_bol(p);
59         }
60         while (line > p->line)
61                 if (!pnextl(p))
62                         break;
63         if (line < p->line) {
64                 while (line < p->line)
65                         pprevl(p);
66                 p_goto_bol(p);
67         }
68         return p;
69 }
70
71 /* Scroll window to follow cursor */
72
73 int mid = 0;
74
75 /* For hex */
76
77 static void bwfllwh(BW *w)
78 {
79         /* Top must be a muliple of 16 bytes */
80         if (w->top->byte%16) {
81                 pbkwd(w->top,w->top->byte%16);
82         }
83
84         /* Move backward */
85         if (w->cursor->byte < w->top->byte) {
86                 long new_top = w->cursor->byte/16;
87                 if (mid) {
88                         if (new_top >= w->h / 2)
89                                 new_top -= w->h / 2;
90                         else
91                                 new_top = 0;
92                 }
93                 if (w->top->byte/16 - new_top < w->h)
94                         nscrldn(w->t->t, w->y, w->y + w->h, (int) (w->top->byte/16 - new_top));
95                 else
96                         msetI(w->t->t->updtab + w->y, 1, w->h);
97                 pgoto(w->top,new_top*16);
98         }
99
100         /* Move forward */
101         if (w->cursor->byte >= w->top->byte+(w->h*16)) {
102                 long new_top;
103                 if (mid) {
104                         new_top = w->cursor->byte/16 - w->h / 2;
105                 } else {
106                         new_top = w->cursor->byte/16 - (w->h - 1);
107                 }
108                 if (new_top - w->top->byte/16 < w->h)
109                         nscrlup(w->t->t, w->y, w->y + w->h, (int) (new_top - w->top->byte/16));
110                 else {
111                         msetI(w->t->t->updtab + w->y, 1, w->h);
112                 }
113                 pgoto(w->top, new_top*16);
114         }
115
116         /* Adjust scroll offset */
117         if (w->cursor->byte%16+60 < w->offset) {
118                 w->offset = w->cursor->byte%16+60;
119                 msetI(w->t->t->updtab + w->y, 1, w->h);
120         } else if (w->cursor->byte%16+60 >= w->offset + w->w) {
121                 w->offset = w->cursor->byte%16+60 - (w->w - 1);
122                 msetI(w->t->t->updtab + w->y, 1, w->h);
123         }
124 }
125
126 /* For text */
127
128 static void bwfllwt(BW *w)
129 {
130         P *newtop;
131
132         if (w->cursor->line < w->top->line) {
133                 newtop = pdup(w->cursor);
134                 p_goto_bol(newtop);
135                 if (mid) {
136                         if (newtop->line >= w->h / 2)
137                                 pline(newtop, newtop->line - w->h / 2);
138                         else
139                                 pset(newtop, newtop->b->bof);
140                 }
141                 if (w->top->line - newtop->line < w->h)
142                         nscrldn(w->t->t, w->y, w->y + w->h, (int) (w->top->line - newtop->line));
143                 else {
144                         msetI(w->t->t->updtab + w->y, 1, w->h);
145                         msetI(w->t->t->syntab + w->y, -1, w->h);
146                 }
147                 pset(w->top, newtop);
148                 prm(newtop);
149         } else if (w->cursor->line >= w->top->line + w->h) {
150                 pdup(w->top);
151                 newtop = getto(NULL, w->cursor, w->top, w->cursor->line -
152                     (mid ? (w->h / 2) : (w->h - 1)));
153                 if (newtop->line - w->top->line < w->h)
154                         nscrlup(w->t->t, w->y, w->y + w->h, (int) (newtop->line - w->top->line));
155                 else {
156                         msetI(w->t->t->updtab + w->y, 1, w->h);
157                         msetI(w->t->t->syntab + w->y, -1, w->h);
158                 }
159                 pset(w->top, newtop);
160                 prm(newtop);
161         }
162
163 /* Adjust column */
164         if (w->cursor->xcol < w->offset) {
165                 w->offset = w->cursor->xcol;
166                 msetI(w->t->t->updtab + w->y, 1, w->h);
167         } else if (w->cursor->xcol >= w->offset + w->w) {
168                 w->offset = w->cursor->xcol - (w->w - 1);
169                 msetI(w->t->t->updtab + w->y, 1, w->h);
170         }
171 }
172
173 /* For either */
174
175 void bwfllw(jobject jO)
176 {
177         BW *w = jO.bw;
178         if (w->o.hex)
179                 bwfllwh(w);
180         else
181                 bwfllwt(w);
182 }
183
184 /* Determine highlighting state of a particular line on the window.
185    If the state is not known, it is computed and the state for all
186    of the remaining lines of the window are also recalculated. */
187
188 static int
189 get_highlight_state(BW *w, int line)
190 {
191         P *tmp = 0;
192         int state;
193
194         /* Screen y position of requested line */
195         int y = line-w->top->line+w->y;
196
197         if(!w->o.highlight || !w->o.syntax)
198                 return -1;
199
200         /* If we know the state, just return it */
201         if (w->parent->t->t->syntab[y]>=0)
202                 return w->parent->t->t->syntab[y];
203
204         /* Scan upwards until we have a line with known state or
205            we're on the first line */
206         while (y > w->y && w->parent->t->t->syntab[y] < 0) --y;
207
208         /* If we don't have state for this line, calculate by going 100 lines back */
209         if (w->parent->t->t->syntab[y]<0) {
210                 /* We must be on the top line */
211                 state = 0;
212                 tmp = pdup(w->top);
213                 if(w->o.syntax->sync_lines >= 0 && tmp->line > w->o.syntax->sync_lines)
214                         pline(tmp, tmp->line-w->o.syntax->sync_lines);
215                 else
216                         p_goto_bof(tmp);
217                 while(tmp->line!=y-w->y+w->top->line)
218                         state = parse(w->o.syntax,tmp,state);
219                 w->parent->t->t->syntab[y] = state;
220                 w->parent->t->t->updtab[y] = 1;
221                 prm(tmp);
222         }
223
224         /* Color to end of screen */
225         tmp = pdup(w->top);
226         pline(tmp, y-w->y+w->top->line);
227         state = w->parent->t->t->syntab[y];
228         while(tmp->line!=w->top->line+w->h-1 && !piseof(tmp)) {
229                 state = parse(w->o.syntax,tmp,state);
230                 w->parent->t->t->syntab[++y] = state;
231                 w->parent->t->t->updtab[y] = 1; /* This could be smarter: update only if we changed what was there before */
232                 }
233         prm(tmp);
234         while(y<w->y+w->h-1) {
235                 w->parent->t->t->syntab[++y] = state;
236                 }
237
238         /* Line after window */
239         /* state = parse_c(state,syn,tmp); */
240
241         /* If we changed, fix other windows */
242         /* w->state = state; */
243
244         /* Return state of requested line */
245         y = line - w->top->line + w->y;
246         return w->parent->t->t->syntab[y];
247 }
248
249 /* Scroll a buffer window after an insert occurred.  'flg' is set to 1 if
250  * the first line was split
251  */
252
253 void bwins(BW *w, long int l, long int n, int flg)
254 {
255         if (l + flg + n < w->top->line + w->h && l + flg >= w->top->line && l + flg <= w->b->eof->line) {
256                 if (flg)
257                         w->t->t->sary[w->y + l - w->top->line] = w->t->t->li;
258                 nscrldn(w->t->t, (int) (w->y + l + flg - w->top->line), w->y + w->h, (int) n);
259         }
260         if (l < w->top->line + w->h && l >= w->top->line) {
261                 if (n >= w->h - (l - w->top->line)) {
262                         msetI(w->t->t->updtab + w->y + l - w->top->line, 1, w->h - (int) (l - w->top->line));
263                         msetI(w->t->t->syntab + w->y + l - w->top->line, -1, w->h - (int) (l - w->top->line));
264                 } else {
265                         msetI(w->t->t->updtab + w->y + l - w->top->line, 1, (int) n + 1);
266                         msetI(w->t->t->syntab + w->y + l - w->top->line, -1, (int) n + 1);
267                 }
268         }
269 }
270
271 /* Scroll current windows after a delete */
272
273 void bwdel(BW *w, long int l, long int n, int flg)
274 {
275 /* Update the line where the delete began */
276         if (l < w->top->line + w->h && l >= w->top->line)
277                 w->t->t->updtab[w->y + l - w->top->line] = 1;
278
279 /* Update highlight for line after first one which changed */
280         if ((l+1) < w->top->line + w->h && (l+1) >= w->top->line) {
281                 w->t->t->syntab[w->y + (l+1) - w->top->line] = -1;
282                 w->t->t->updtab[w->y + (l+1) - w->top->line] = 1;
283                 }
284
285 /* Update the line where the delete ended */
286         if (l + n < w->top->line + w->h && l + n >= w->top->line)
287                 w->t->t->updtab[w->y + l + n - w->top->line] = 1;
288
289         if (l < w->top->line + w->h && (l + n >= w->top->line + w->h || (l + n == w->b->eof->line && w->b->eof->line >= w->top->line + w->h))) {
290                 if (l >= w->top->line)
291                         /* Update window from l to end */
292                         msetI(w->t->t->updtab + w->y + l - w->top->line, 1, w->h - (int) (l - w->top->line));
293                 else
294                         /* Update entire window */
295                         msetI(w->t->t->updtab + w->y, 1, w->h);
296         } else if (l < w->top->line + w->h && l + n == w->b->eof->line && w->b->eof->line < w->top->line + w->h) {
297                 if (l >= w->top->line)
298                         /* Update window from l to end of file */
299                         msetI(w->t->t->updtab + w->y + l - w->top->line, 1, (int) n);
300                 else
301                         /* Update from beginning of window to end of file */
302                         msetI(w->t->t->updtab + w->y, 1, (int) (w->b->eof->line - w->top->line));
303         } else if (l + n < w->top->line + w->h && l + n > w->top->line && l + n < w->b->eof->line) {
304                 if (l + flg >= w->top->line)
305                         nscrlup(w->t->t, (int) (w->y + l + flg - w->top->line), w->y + w->h, (int) n);
306                 else
307                         nscrlup(w->t->t, w->y, w->y + w->h, (int) (l + n - w->top->line));
308         }
309 }
310
311 /* Update a single line */
312
313 static int lgen(SCRN *t, int y, int *screen, int *attr, int x, int w, P *p, long int scr, long int from, long int to,int st,BW *bw)
314
315
316                                 /* Screen line address */
317                                 /* Window */
318                                 /* Buffer pointer */
319                                 /* Starting column to display */
320                                 /* Range for marked block */
321 {
322         int ox = x;
323         int tach, tach1;
324         int done = 1;
325         long col = 0;
326         long byte = p->byte;
327         unsigned char *bp;      /* Buffer pointer, 0 if not set */
328         int amnt;               /* Amount left in this segment of the buffer */
329         int c, ta, c1;
330         unsigned char bc;
331         int ungetit = -1;
332
333         struct utf8_sm utf8_sm;
334
335         int *syn = NULL;
336         P *tmp;
337         int idx=0;
338         int atr = 0;
339
340         utf8_init(&utf8_sm);
341
342         if(st!=-1) {
343                 tmp=pdup(p);
344                 p_goto_bol(tmp);
345                 parse(bw->o.syntax,tmp,st);
346                 syn = attr_buf;
347                 prm(tmp);
348         }
349
350 /* Initialize bp and amnt from p */
351         if (p->ofst >= p->hdr->hole) {
352                 bp = p->ptr + p->hdr->ehole + p->ofst - p->hdr->hole;
353                 amnt = SEGSIZ - p->hdr->ehole - (p->ofst - p->hdr->hole);
354         } else {
355                 bp = p->ptr + p->ofst;
356                 amnt = p->hdr->hole - p->ofst;
357         }
358
359         if (col == scr)
360                 goto loop;
361  lp:
362         /* Display next character */
363         if (amnt)
364                 do {
365                         if (ungetit== -1)
366                                 bc = *bp++;
367                         else {
368                                 bc = ungetit;
369                                 ungetit = -1;
370                         }
371                         if(st!=-1)
372                                 atr = syn[idx++];
373                         if (p->b->o.crlf && bc == '\r') {
374                                 ++byte;
375                                 if (!--amnt) {
376  pppl:
377                                         if (bp == p->ptr + SEGSIZ) {
378                                                 if (pnext(p)) {
379                                                         bp = p->ptr;
380                                                         amnt = p->hdr->hole;
381                                                 } else
382                                                         goto nnnl;
383                                         } else {
384                                                 bp = p->ptr + p->hdr->ehole;
385                                                 amnt = SEGSIZ - p->hdr->ehole;
386                                                 if (!amnt)
387                                                         goto pppl;
388                                         }
389                                 }
390                                 if (*bp == '\n') {
391                                         ++bp;
392                                         ++byte;
393                                         ++amnt;
394                                         goto eobl;
395                                 }
396  nnnl:
397                                 --byte;
398                                 ++amnt;
399                         }
400                         if (square)
401                                 if (bc == '\t') {
402                                         long tcol = col + p->b->o.tab - col % p->b->o.tab;
403
404                                         if (tcol > from && tcol <= to)
405                                                 c1 = INVERSE;
406                                         else
407                                                 c1 = 0;
408                                 } else if (col >= from && col < to)
409                                         c1 = INVERSE;
410                                 else
411                                         c1 = 0;
412                         else if (byte >= from && byte < to)
413                                 c1 = INVERSE;
414                         else
415                                 c1 = 0;
416                         ++byte;
417                         if (bc == '\t') {
418                                 ta = p->b->o.tab - col % p->b->o.tab;
419                                 if (ta + col > scr) {
420                                         ta -= scr - col;
421                                         goto dota_tab;
422                                 }
423                                 if ((col += ta) == scr) {
424                                         --amnt;
425                                         goto loop;
426                                 }
427                         } else if (bc == '\n')
428                                 goto eobl;
429                         else {
430                                 int wid = 1;
431                                 if (p->b->o.charmap->type) {
432                                         c = utf8_decode(&utf8_sm,bc);
433
434                                         if (c>=0) /* Normal decoded character */
435                                                 wid = joe_wcwidth(1,c);
436                                         else if(c== -1) /* Character taken */
437                                                 wid = -1;
438                                         else if(c== -2) { /* Incomplete sequence */
439                                                 wid = 1;
440                                                 ungetit = c;
441                                                 ++amnt;
442                                                 --byte;
443                                         }
444                                         else if(c== -3) /* Control character 128-191, 254, 255 */
445                                                 wid = 1;
446                                 }
447
448                                 if (wid >= 0) {
449                                         col += wid;
450                                         if (col == scr) {
451                                                 --amnt;
452                                                 goto loop;
453                                         } else if (col > scr) {
454                                                 ta = col - scr;
455                                                 tach1 = tach = '<';
456                                                 goto dota_gen;
457                                         }
458                                 } else
459                                         --idx;  /* Get highlighting character again.. */
460                         }
461                 } while (--amnt);
462         if (bp == p->ptr + SEGSIZ) {
463                 if (pnext(p)) {
464                         bp = p->ptr;
465                         amnt = p->hdr->hole;
466                         goto lp;
467                 }
468         } else {
469                 bp = p->ptr + p->hdr->ehole;
470                 amnt = SEGSIZ - p->hdr->ehole;
471                 goto lp;
472         }
473         goto eof;
474  loop:
475         /* Display next character */
476         if (amnt)
477                 do {
478                         if (ungetit== -1)
479                                 bc = *bp++;
480                         else {
481                                 bc = ungetit;
482                                 ungetit = -1;
483                         }
484                         if(st!=-1)
485                                 atr=syn[idx++];
486                         if (p->b->o.crlf && bc == '\r') {
487                                 ++byte;
488                                 if (!--amnt) {
489  ppl:
490                                         if (bp == p->ptr + SEGSIZ) {
491                                                 if (pnext(p)) {
492                                                         bp = p->ptr;
493                                                         amnt = p->hdr->hole;
494                                                 } else
495                                                         goto nnl;
496                                         } else {
497                                                 bp = p->ptr + p->hdr->ehole;
498                                                 amnt = SEGSIZ - p->hdr->ehole;
499                                                 if (!amnt)
500                                                         goto ppl;
501                                         }
502                                 }
503                                 if (*bp == '\n') {
504                                         ++bp;
505                                         ++byte;
506                                         ++amnt;
507                                         goto eobl;
508                                 }
509  nnl:
510                                 --byte;
511                                 ++amnt;
512                         }
513                         if (square)
514                                 if (bc == '\t') {
515                                         long tcol = scr + x - ox + p->b->o.tab - (scr + x - ox) % p->b->o.tab;
516
517                                         if (tcol > from && tcol <= to)
518                                                 c1 = INVERSE;
519                                         else
520                                                 c1 = 0;
521                                 } else if (scr + x - ox >= from && scr + x - ox < to)
522                                         c1 = INVERSE;
523                                 else
524                                         c1 = 0;
525                         else if (byte >= from && byte < to)
526                                 c1 = INVERSE;
527                         else
528                                 c1 = 0;
529                         ++byte;
530                         if (bc == '\t') {
531                                 ta = p->b->o.tab - ((x - ox + scr) % p->b->o.tab);
532  dota_tab:
533                                 tach1 = tach = ' ';
534                                 if (bw->o.vispace)
535                                         tach = 0x2192;
536  dota_gen:
537                                 do {
538                                         outatr(utf8_map, t, screen + x, attr + x, x, y, tach, c1|atr);
539                                         tach = tach1;
540                                         if (have)
541                                                 goto bye;
542                                         if (++x == w)
543                                                 goto eosl;
544                                 } while (--ta);
545                         } else if (bc == '\n') {
546                                 if (utf8_sm.state)
547                                         goto unget_cch;
548                                 goto eobl;
549                         } else {
550                                 int wid = -1;
551                                 int utf8_char;
552                                 if (p->b->o.charmap->type) { /* UTF-8 */
553
554                                         utf8_char = utf8_decode(&utf8_sm,bc);
555
556                                         if (utf8_char >= 0) { /* Normal decoded character */
557                                                 wid = joe_wcwidth(1,utf8_char);
558                                         } else if(utf8_char== -1) { /* Character taken */
559                                                 wid = -1;
560                                         } else if(utf8_char== -2) { /* Incomplete sequence (FIXME: do something better here) */
561  unget_cch:
562                                                 ungetit = bc;
563                                                 ++amnt;
564                                                 --byte;
565                                                 utf8_char = 0x1000FFFE;
566                                                 wid = utf8_sm.ptr;
567                                                 utf8_init(&utf8_sm);
568                                         } else if(utf8_char== -3) { /* Invalid UTF-8 start character 128-191, 254, 255 */
569                                                 /* Show as control character */
570                                                 wid = 1;
571                                                 utf8_char = 0x1000FFFE;
572                                         }
573                                 } else { /* Regular */
574                                         utf8_char = bc;
575                                         wid = 1;
576                                 }
577
578                                 if(wid>=0) {
579                                         if (x+wid > w) {
580                                                 /* If character hits right most column, don't display it */
581                                                 while (x < w) {
582                                                         outatr(bw->b->o.charmap, t, screen + x, attr + x, x, y, '>', c1|atr);
583                                                         x++;
584                                                 }
585                                         } else if (utf8_char == 0x1000FFFE) while (wid--) {
586                                                 outatr(bw->b->o.charmap, t, screen + x, attr + x, x, y, 0xFFFD, (c1|atr|UNDERLINE)^INVERSE);
587                                                 x++;
588                                         } else if (bw->o.vispace && (utf8_char == 0x20)) {
589                                                 outatr(utf8_map, t, screen + x, attr + x, x, y, 0xB7, c1|atr);
590                                                 x += wid;
591                                         } else {
592                                                 outatr(bw->b->o.charmap, t, screen + x, attr + x, x, y, utf8_char, c1|atr);
593                                                 x += wid;
594                                         }
595                                 } else
596                                         --idx;
597
598                                 if (have)
599                                         goto bye;
600                                 if (x >= w)
601                                         goto eosl;
602                         }
603                 } while (--amnt);
604         if (bp == p->ptr + SEGSIZ) {
605                 if (pnext(p)) {
606                         bp = p->ptr;
607                         amnt = p->hdr->hole;
608                         goto loop;
609                 }
610         } else {
611                 bp = p->ptr + p->hdr->ehole;
612                 amnt = SEGSIZ - p->hdr->ehole;
613                 goto loop;
614         }
615         goto eof;
616  eobl:
617         /* End of buffer line found.  Erase to end of screen line */
618         ++p->line;
619  eof:
620         if (x != w)
621                 done = eraeol(t, x, y);
622         else
623                 done = 0;
624
625 /* Set p to bp/amnt */
626  bye:
627         if (bp - p->ptr <= p->hdr->hole)
628                 p->ofst = bp - p->ptr;
629         else
630                 p->ofst = bp - p->ptr - (p->hdr->ehole - p->hdr->hole);
631         p->byte = byte;
632         return done;
633
634  eosl:
635         if (bp - p->ptr <= p->hdr->hole)
636                 p->ofst = bp - p->ptr;
637         else
638                 p->ofst = bp - p->ptr - (p->hdr->ehole - p->hdr->hole);
639         p->byte = byte;
640         pnextl(p);
641         return 0;
642 }
643
644 static void gennum(BW *w, int *screen, int *attr, SCRN *t, int y, int *comp)
645 {
646         unsigned char buf[12];
647         int z;
648         int lin = w->top->line + y - w->y;
649
650         if (lin <= w->b->eof->line)
651                 joe_snprintf_1((char *)buf, sizeof(buf), "%5ld ", w->top->line + y - w->y + 1);
652         else
653                 strlcpy((char *)buf, "      ",12);
654         for (z = 0; buf[z]; ++z) {
655                 outatr(w->b->o.charmap, t, screen + z, attr + z, z, y, buf[z], 0);
656                 if (have)
657                         return;
658                 comp[z] = buf[z];
659         }
660 }
661
662 void bwgenh(BW *w)
663 {
664         int *screen;
665         int *attr;
666         P *q = pdup(w->top);
667         int bot = w->h + w->y;
668         int y;
669         SCRN *t = w->t->t;
670         int flg = 0;
671         long from;
672         long to;
673         int dosquare = 0;
674
675         from = to = 0;
676
677         if (markv(0) && markk->b == w->b)
678                 if (square) {
679                         from = markb->xcol;
680                         to = markk->xcol;
681                         dosquare = 1;
682                 } else {
683                         from = markb->byte;
684                         to = markk->byte;
685                 }
686         else if (marking && w == maint->curwin->object.bw && markb && markb->b == w->b && w->cursor->byte != markb->byte && !from) {
687                 if (square) {
688                         from = long_min(w->cursor->xcol, markb->xcol);
689                         to = long_max(w->cursor->xcol, markb->xcol);
690                         dosquare = 1;
691                 } else {
692                         from = long_min(w->cursor->byte, markb->byte);
693                         to = long_max(w->cursor->byte, markb->byte);
694                 }
695         }
696
697         if (marking && w == maint->curwin->object.bw)
698                 msetI(t->updtab + w->y, 1, w->h);
699
700         if (dosquare) {
701                 from = 0;
702                 to = 0;
703         }
704
705         y=w->y;
706         attr = t->attr + y*w->t->w;
707         for (screen = t->scrn + y * w->t->w; y != bot; ++y, (screen += w->t->w), (attr += w->t->w)) {
708                 unsigned char txt[80];
709                 int fmt[80];
710                 unsigned char bf[16];
711                 int x;
712                 memset(txt,' ',76);
713                 msetI(fmt, /* BG_COLOR(bg_text) */ 0,76);
714                 txt[76]=0;
715                 if (!flg) {
716 #if SIZEOF_LONG_LONG && SIZEOF_LONG_LONG == SIZEOF_OFF_T
717                         joe_snprintf_1((char *)bf,sizeof(bf),"%8llX ",(unsigned long long)q->byte);
718 #else
719                         joe_snprintf_1((char *)bf,sizeof(bf),"%8lX ",(unsigned long)q->byte);
720 #endif
721                         memcpy(txt,bf,9);
722                         for (x=0; x!=8; ++x) {
723                                 int c;
724                                 if (q->byte==w->cursor->byte && !flg) {
725                                         fmt[10+x*3] |= INVERSE;
726                                         fmt[10+x*3+1] |= INVERSE;
727                                 }
728                                 if (q->byte>=from && q->byte<to && !flg) {
729                                         fmt[10+x*3] |= UNDERLINE;
730                                         fmt[10+x*3+1] |= UNDERLINE;
731                                         fmt[60+x] |= INVERSE;
732                                 }
733                                 c = pgetb(q);
734                                 if (c >= 0) {
735                                         joe_snprintf_1((char *)bf,sizeof(bf),"%2.2X",c);
736                                         txt[10+x*3] = bf[0];
737                                         txt[10+x*3+1] = bf[1];
738                                         if (c >= 0x20 && c <= 0x7E)
739                                                 txt[60+x] = c;
740                                         else
741                                                 txt[60+x] = '.';
742                                 } else
743                                         flg = 1;
744                         }
745                         for (x=8; x!=16; ++x) {
746                                 int c;
747                                 if (q->byte==w->cursor->byte && !flg) {
748                                         fmt[11+x*3] |= INVERSE;
749                                         fmt[11+x*3+1] |= INVERSE;
750                                 }
751                                 if (q->byte>=from && q->byte<to && !flg) {
752                                         fmt[11+x*3] |= UNDERLINE;
753                                         fmt[11+x*3+1] |= UNDERLINE;
754                                         fmt[60+x] |= INVERSE;
755                                 }
756                                 c = pgetb(q);
757                                 if (c >= 0) {
758                                         joe_snprintf_1((char *)bf,sizeof(bf),"%2.2X",c);
759                                         txt[11+x*3] = bf[0];
760                                         txt[11+x*3+1] = bf[1];
761                                         if (c >= 0x20 && c <= 0x7E)
762                                                 txt[60+x] = c;
763                                         else
764                                                 txt[60+x] = '.';
765                                 } else
766                                         flg = 1;
767                         }
768                 }
769                 genfield(t, screen, attr, 0, y, w->offset, txt, 76, 0, w->w, 1, fmt);
770         }
771         prm(q);
772 }
773
774 void bwgen(BW *w, int linums)
775 {
776         int *screen;
777         int *attr;
778         P *p = NULL;
779         P *q = pdup(w->cursor);
780         int bot = w->h + w->y;
781         int y;
782         int dosquare = 0;
783         long from, to;
784         long fromline, toline;
785         SCRN *t = w->t->t;
786
787         fromline = toline = from = to = 0;
788
789         if (markv(0) && markk->b == w->b)
790                 if (square) {
791                         from = markb->xcol;
792                         to = markk->xcol;
793                         dosquare = 1;
794                         fromline = markb->line;
795                         toline = markk->line;
796                 } else {
797                         from = markb->byte;
798                         to = markk->byte;
799                 }
800         else if (marking && w == maint->curwin->object.bw && markb && markb->b == w->b && w->cursor->byte != markb->byte && !from) {
801                 if (square) {
802                         from = long_min(w->cursor->xcol, markb->xcol);
803                         to = long_max(w->cursor->xcol, markb->xcol);
804                         fromline = long_min(w->cursor->line, markb->line);
805                         toline = long_max(w->cursor->line, markb->line);
806                         dosquare = 1;
807                 } else {
808                         from = long_min(w->cursor->byte, markb->byte);
809                         to = long_max(w->cursor->byte, markb->byte);
810                 }
811         }
812
813         if (marking && w == maint->curwin->object.bw)
814                 msetI(t->updtab + w->y, 1, w->h);
815
816         y = w->cursor->line - w->top->line + w->y;
817         attr = t->attr + y*w->t->w;
818         for (screen = t->scrn + y * w->t->w; y != bot; ++y, (screen += w->t->w), (attr += w->t->w)) {
819                 if (have && !linums)
820                         break;
821                 if (linums)
822                         gennum(w, screen, attr, t, y, t->compose);
823                 if (t->updtab[y]) {
824                         p = getto(p, w->cursor, w->top, w->top->line + y - w->y);
825 /*                      if (t->insdel && !w->x) {
826                                 pset(q, p);
827                                 if (dosquare)
828                                         if (w->top->line + y - w->y >= fromline && w->top->line + y - w->y <= toline)
829                                                 lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, from, to);
830                                         else
831                                                 lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, 0L, 0L);
832                                 else
833                                         lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, from, to);
834                                 magic(t, y, screen, attr, t->compose, (int) (w->cursor->xcol - w->offset + w->x));
835                         } */
836                         if (dosquare)
837                                 if (w->top->line + y - w->y >= fromline && w->top->line + y - w->y <= toline)
838                                         t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, from, to, get_highlight_state(w,w->top->line+y-w->y),w);
839                                 else
840                                         t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, 0L, 0L, get_highlight_state(w,w->top->line+y-w->y),w);
841                         else
842                                 t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, from, to, get_highlight_state(w,w->top->line+y-w->y),w);
843                 }
844         }
845
846         y = w->y;
847         attr = t->attr + w->y * w->t->w;
848         for (screen = t->scrn + w->y * w->t->w; y != w->y + w->cursor->line - w->top->line; ++y, (screen += w->t->w), (attr += w->t->w)) {
849                 if (have && !linums)
850                         break;
851                 if (linums)
852                         gennum(w, screen, attr, t, y, t->compose);
853                 if (t->updtab[y]) {
854                         p = getto(p, w->cursor, w->top, w->top->line + y - w->y);
855 /*                      if (t->insdel && !w->x) {
856                                 pset(q, p);
857                                 if (dosquare)
858                                         if (w->top->line + y - w->y >= fromline && w->top->line + y - w->y <= toline)
859                                                 lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, from, to);
860                                         else
861                                                 lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, 0L, 0L);
862                                 else
863                                         lgena(t, y, t->compose, w->x, w->x + w->w, q, w->offset, from, to);
864                                 magic(t, y, screen, attr, t->compose, (int) (w->cursor->xcol - w->offset + w->x));
865                         } */
866                         if (dosquare)
867                                 if (w->top->line + y - w->y >= fromline && w->top->line + y - w->y <= toline)
868                                         t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, from, to, get_highlight_state(w,w->top->line+y-w->y),w);
869                                 else
870                                         t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, 0L, 0L, get_highlight_state(w,w->top->line+y-w->y),w);
871                         else
872                                 t->updtab[y] = lgen(t, y, screen, attr, w->x, w->x + w->w, p, w->offset, from, to, get_highlight_state(w,w->top->line+y-w->y),w);
873                 }
874         }
875         prm(q);
876         if (p)
877                 prm(p);
878 }
879
880 void bwmove(BW *w, int x, int y)
881 {
882         w->x = x;
883         w->y = y;
884 }
885
886 void bwresz(BW *w, int wi, int he)
887 {
888         if (he > w->h && w->y != -1) {
889                 msetI(w->t->t->updtab + w->y + w->h, 1, he - w->h);
890                 msetI(w->t->t->syntab + w->y + w->h, -1, he - w->h);
891                 }
892         w->w = wi;
893         w->h = he;
894 }
895
896 BW *bwmk(W *window, B *b, int prompt)
897 {
898         BW *w = malloc(sizeof(BW));
899
900         w->parent = window;
901         w->b = b;
902         if (prompt || (!window->y && staen)) {
903                 w->y = window->y;
904                 w->h = window->h;
905         } else {
906                 w->y = window->y + 1;
907                 w->h = window->h - 1;
908         }
909         if (b->oldcur) {
910                 w->top = b->oldtop;
911                 b->oldtop = NULL;
912                 w->top->owner = NULL;
913                 w->cursor = b->oldcur;
914                 b->oldcur = NULL;
915                 w->cursor->owner = NULL;
916         } else {
917                 w->top = pdup(b->bof);
918                 w->cursor = pdup(b->bof);
919         }
920         w->t = window->t;
921         w->object = NULL;
922         w->offset = 0;
923         w->o = w->b->o;
924         if ((w->linums = w->o.linums)) {
925                 w->x = window->x + LINCOLS;
926                 w->w = window->w - LINCOLS;
927         } else {
928                 w->x = window->x;
929                 w->w = window->w;
930         }
931         if (window == window->main) {
932                 rmkbd(window->kbd);
933                 window->kbd = mkkbd(kmap_getcontext(w->o.context, 1));
934         }
935         w->top->xcol = 0;
936         w->cursor->xcol = 0;
937         w->top_changed = 1;
938         return w;
939 }
940
941 void bwrm(BW *w)
942 {
943         prm(w->top);
944         prm(w->cursor);
945         brm(w->b);
946         free(w);
947 }
948
949 int ustat_j(BW *bw)
950 {
951         static unsigned char buf[80];
952         int c = brch(bw->cursor);
953
954         if (c == NO_MORE_DATA)
955                 joe_snprintf_4((char *)buf, sizeof(buf), "** Line %ld  Col %ld  Offset %ld(0x%lX) **", bw->cursor->line + 1, piscol(bw->cursor) + 1, bw->cursor->byte, bw->cursor->byte);
956         else
957                 joe_snprintf_9((char *)buf, sizeof(buf), "** Line %ld  Col %ld  Offset %ld(0x%lX)  %s %d(0%o/0x%X) Width %d **", bw->cursor->line + 1, piscol(bw->cursor) + 1, bw->cursor->byte, bw->cursor->byte, bw->b->o.charmap->name, c, c, c, joe_wcwidth(bw->o.charmap->type,c));
958         msgnw(bw->parent, buf);
959         return 0;
960 }
961
962 int ucrawlr(BW *bw)
963 {
964         int amnt = bw->w / 2;
965
966         pcol(bw->cursor, bw->cursor->xcol + amnt);
967         bw->cursor->xcol += amnt;
968         bw->offset += amnt;
969         updall();
970         return 0;
971 }
972
973 int ucrawll(BW *bw)
974 {
975         int amnt = bw->w / 2;
976         int curamnt = bw->w / 2;
977
978         if (amnt > bw->offset) {
979                 amnt = bw->offset;
980                 curamnt = bw->offset;
981         }
982         if (!bw->offset)
983                 curamnt = bw->cursor->xcol;
984         if (!curamnt)
985                 return -1;
986         pcol(bw->cursor, bw->cursor->xcol - curamnt);
987         bw->cursor->xcol -= curamnt;
988         bw->offset -= amnt;
989         updall();
990         return 0;
991 }
992
993 void orphit(BW *bw)
994 {
995         ++bw->b->count;
996         bw->b->orphan = 1;
997         pdupown(bw->cursor, &bw->b->oldcur);
998         pdupown(bw->top, &bw->b->oldtop);
999 }