reg: restore color after inserting diverted text
[neatroff.git] / ren.c
blobdf80c201b8dd397b1556b8aaa1b7e8d20e75c031
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "roff.h"
7 #define cadj env_adj() /* line buffer */
8 #define RENWB(wb) ((wb) == &ren_wb) /* is ren_wb */
10 /* diversions */
11 struct div {
12 struct sbuf sbuf; /* diversion output */
13 int reg; /* diversion register */
14 int tpos; /* diversion trap position */
15 int treg; /* diversion trap register */
16 int dl; /* diversion width */
17 int prev_d; /* previous \(.d value */
18 int prev_h; /* previous \(.h value */
19 int prev_mk; /* previous .mk internal register */
20 int prev_ns; /* previous .ns value */
22 static struct div divs[NPREV]; /* diversion stack */
23 static struct div *cdiv; /* current diversion */
24 static int ren_div; /* rendering a diversion */
25 static int trap_em = -1; /* end macro */
27 static struct wb ren_wb; /* the main ren.c word buffer */
28 static int ren_nl; /* just after newline */
29 static int ren_cnl; /* current char is a newline */
30 static int ren_unbuf[8]; /* ren_back() buffer */
31 static int ren_un;
32 static int ren_fillreq; /* \p request */
34 static int bp_first = 1; /* prior to the first page */
35 static int bp_next = 1; /* next page number */
36 static int bp_count; /* number of pages so far */
37 static int bp_ejected; /* current ejected page */
38 static int bp_final; /* 1: executing em, 2: the final page, 3: the 2nd final page */
40 static int c_fa; /* field delimiter */
41 static char c_fb[GNLEN]; /* field padding */
43 static int ren_next(void)
45 return ren_un > 0 ? ren_unbuf[--ren_un] : tr_next();
48 static void ren_back(int c)
50 ren_unbuf[ren_un++] = c;
53 void tr_di(char **args)
55 if (args[1]) {
56 cdiv = cdiv ? cdiv + 1 : divs;
57 memset(cdiv, 0, sizeof(*cdiv));
58 sbuf_init(&cdiv->sbuf);
59 cdiv->reg = map(args[1]);
60 cdiv->treg = -1;
61 if (args[0][2] == 'a' && str_get(cdiv->reg)) /* .da */
62 sbuf_append(&cdiv->sbuf, str_get(cdiv->reg));
63 sbuf_printf(&cdiv->sbuf, "%c%s\n", c_cc, TR_DIVBEG);
64 cdiv->prev_d = n_d;
65 cdiv->prev_h = n_h;
66 cdiv->prev_mk = n_mk;
67 cdiv->prev_ns = n_ns;
68 n_d = 0;
69 n_h = 0;
70 n_mk = 0;
71 n_ns = 0;
72 } else if (cdiv) {
73 sbuf_putnl(&cdiv->sbuf);
74 sbuf_printf(&cdiv->sbuf, "%c%s\n", c_cc, TR_DIVEND);
75 str_set(cdiv->reg, sbuf_buf(&cdiv->sbuf));
76 sbuf_done(&cdiv->sbuf);
77 n_dl = cdiv->dl;
78 n_dn = n_d;
79 n_d = cdiv->prev_d;
80 n_h = cdiv->prev_h;
81 n_mk = cdiv->prev_mk;
82 n_ns = cdiv->prev_ns;
83 cdiv = cdiv > divs ? cdiv - 1 : NULL;
87 int f_divreg(void)
89 return cdiv ? cdiv->reg : -1;
92 int f_hpos(void)
94 return adj_wid(cadj) + wb_wid(&ren_wb);
97 void tr_divbeg(char **args)
99 odiv_beg();
100 ren_div++;
103 void tr_divend(char **args)
105 odiv_end();
106 ren_div--;
109 static int trap_reg(int pos);
110 static int trap_pos(int pos);
111 static void trap_exec(int reg);
113 static void ren_page(int pg, int force)
115 if (!force && bp_final >= 2)
116 return;
117 n_nl = 0;
118 n_d = 0;
119 n_h = 0;
120 n_pg = pg;
121 bp_next = n_pg + 1;
122 bp_count++;
123 out("p%d\n", pg);
124 out("V%d\n", 0);
125 if (trap_pos(-1) == 0)
126 trap_exec(trap_reg(-1));
129 static void ren_first(void)
131 if (bp_first && !cdiv) {
132 bp_first = 0;
133 ren_page(bp_next, 1);
137 /* when nodiv, do not append .sp to diversions */
138 static void ren_sp(int n, int nodiv)
140 ren_first();
141 /* ignore .sp without arguments when reading diversions */
142 if (!n && ren_div && !n_u)
143 return;
144 n_d += n ? n : n_v;
145 if (n_d > n_h)
146 n_h = n_d;
147 if (cdiv && !nodiv) {
148 sbuf_putnl(&cdiv->sbuf);
149 sbuf_printf(&cdiv->sbuf, "%csp %du\n", c_cc, n ? n : n_v);
150 } else {
151 n_nl = n_d;
155 static void trap_exec(int reg)
157 if (str_get(reg))
158 in_pushnl(str_get(reg), NULL);
161 static int detect_traps(int beg, int end)
163 int pos = trap_pos(beg);
164 return pos >= 0 && (cdiv || pos < n_p) && pos <= end;
167 /* return 1 if executed a trap */
168 static int ren_traps(int beg, int end, int dosp)
170 int pos = trap_pos(beg);
171 if (detect_traps(beg, end)) {
172 if (dosp && pos > beg)
173 ren_sp(pos - beg, 0);
174 trap_exec(trap_reg(beg));
175 return 1;
177 return 0;
180 static int detect_pagelimit(int ne)
182 return !cdiv && n_nl + ne >= n_p;
185 /* start a new page if needed */
186 static int ren_pagelimit(int ne)
188 if (detect_pagelimit(ne)) {
189 ren_page(bp_next, 0);
190 return 1;
192 return 0;
195 static void down(int n)
197 if (!ren_traps(n_d, n_d + (n ? n : n_v), 1)) {
198 ren_sp(n, 0);
199 ren_pagelimit(0);
203 /* flush the given line and send it to out.c */
204 static void ren_line(char *s, int w, int ad, int ll, int li, int lt)
206 int ljust = lt >= 0 ? lt : li;
207 int llen = ll - ljust;
208 n_n = w;
209 if (ad == AD_C)
210 ljust += llen > w ? (llen - w) / 2 : 0;
211 if (ad == AD_R)
212 ljust += llen - w;
213 if (cdiv) {
214 if (cdiv->dl < w)
215 cdiv->dl = w;
216 if (ljust)
217 sbuf_printf(&cdiv->sbuf, "%ch'%du'", c_ec, ljust);
218 sbuf_append(&cdiv->sbuf, s);
219 } else {
220 out("H%d\n", n_o + ljust);
221 out("V%d\n", n_d);
222 out_line(s);
226 static void ren_transparent(char *s)
228 if (cdiv)
229 sbuf_printf(&cdiv->sbuf, "%s\n", s);
230 else
231 out("%s\n", s);
234 /* return 1 if triggered a trap */
235 static int ren_bradj(struct adj *adj, int fill, int ad)
237 char cmd[16];
238 struct sbuf sbuf;
239 int ll, li, lt, els_neg, els_pos;
240 int w, prev_d, lspc;
241 ren_first();
242 if (!adj_empty(adj, fill)) {
243 sbuf_init(&sbuf);
244 w = adj_fill(adj, ad == AD_B, fill, n_hy, &sbuf,
245 &ll, &li, &lt, &els_neg, &els_pos);
246 prev_d = n_d;
247 if (els_neg)
248 ren_sp(-els_neg, 1);
249 if (!n_ns || !sbuf_empty(&sbuf) || els_neg || els_pos) {
250 ren_sp(0, 0);
251 ren_line(sbuf_buf(&sbuf), w, ad, ll, li, lt);
252 n_ns = 0;
254 sbuf_done(&sbuf);
255 if (els_pos)
256 ren_sp(els_pos, 1);
257 n_a = els_pos;
258 lspc = MAX(1, n_L) * n_v - n_v;
259 if (detect_traps(prev_d, n_d) || detect_pagelimit(lspc)) {
260 sprintf(cmd, "%c&", c_ec);
261 if (!ren_cnl) /* prevent unwanted newlines */
262 in_push(cmd, NULL);
263 if (!ren_traps(prev_d, n_d, 0))
264 ren_pagelimit(lspc);
265 return 1;
267 if (lspc)
268 down(lspc);
270 return 0;
273 /* return 1 if triggered a trap */
274 static int ren_br(int force)
276 return ren_bradj(cadj, !force && !n_ce && n_u,
277 n_ce ? AD_C : (n_u && !n_na && (n_j != AD_B || !force) ? n_j : AD_L));
280 void tr_br(char **args)
282 if (args[0][0] == c_cc)
283 ren_br(1);
286 void tr_sp(char **args)
288 int traps = 0;
289 int n = args[1] ? eval(args[1], 'v') : n_v;
290 if (args[0][0] == c_cc)
291 traps = ren_br(1);
292 if (n && !n_ns && !traps)
293 down(n);
296 void tr_sv(char **args)
298 int n = eval(args[1], 'v');
299 n_sv = 0;
300 if (n_d + n < f_nexttrap())
301 down(n);
302 else
303 n_sv = n;
306 void tr_ns(char **args)
308 n_ns = 1;
311 void tr_rs(char **args)
313 n_ns = 0;
316 void tr_os(char **args)
318 if (n_sv)
319 down(n_sv);
320 n_sv = 0;
323 void tr_mk(char **args)
325 if (args[1])
326 num_set(map(args[1]), n_d);
327 else
328 n_mk = n_d;
331 void tr_rt(char **args)
333 int n = args[1] ? eval_re(args[1], n_d, 'v') : n_mk;
334 if (n >= 0 && n < n_d)
335 ren_sp(n - n_d, 0);
338 void tr_ne(char **args)
340 int n = args[1] ? eval(args[1], 'v') : n_v;
341 if (!ren_traps(n_d, n_d + n - 1, 1))
342 ren_pagelimit(n);
345 static void push_eject(void)
347 char buf[32];
348 bp_ejected = bp_count;
349 sprintf(buf, "%c%s %d\n", c_cc, TR_EJECT, bp_ejected);
350 in_pushnl(buf, NULL);
353 static void push_br(void)
355 char br[8] = {c_cc, 'b', 'r', '\n'};
356 in_pushnl(br, NULL);
359 static void ren_eject(int id)
361 if (id == bp_ejected && id == bp_count && !cdiv) {
362 if (detect_traps(n_d, n_p)) {
363 push_eject();
364 ren_traps(n_d, n_p, 1);
365 } else {
366 bp_ejected = 0;
367 ren_page(bp_next, 0);
372 void tr_eject(char **args)
374 ren_eject(atoi(args[1]));
377 void tr_bp(char **args)
379 if (!cdiv && (args[1] || !n_ns)) {
380 if (bp_ejected != bp_count)
381 push_eject();
382 if (args[0][0] == c_cc)
383 push_br();
384 if (args[1])
385 bp_next = eval_re(args[1], n_pg, 0);
389 void tr_pn(char **args)
391 if (args[1])
392 bp_next = eval_re(args[1], n_pg, 0);
395 static void ren_ps(char *s)
397 int ps = !s || !*s || !strcmp("0", s) ? n_s0 : eval_re(s, n_s, 0);
398 n_s0 = n_s;
399 n_s = MAX(1, ps);
402 void tr_ps(char **args)
404 ren_ps(args[1]);
407 void tr_ll(char **args)
409 int ll = args[1] ? eval_re(args[1], n_l, 'm') : n_l0;
410 n_l0 = n_l;
411 n_l = MAX(0, ll);
412 adj_ll(cadj, n_l);
415 void tr_in(char **args)
417 int in = args[1] ? eval_re(args[1], n_i, 'm') : n_i0;
418 if (args[0][0] == c_cc)
419 ren_br(1);
420 n_i0 = n_i;
421 n_i = MAX(0, in);
422 adj_in(cadj, n_i);
423 adj_ti(cadj, -1);
426 void tr_ti(char **args)
428 if (args[0][0] == c_cc)
429 ren_br(1);
430 if (args[1])
431 adj_ti(cadj, eval_re(args[1], n_i, 'm'));
434 static void ren_ft(char *s)
436 int fn = !s || !*s || !strcmp("P", s) ? n_f0 : dev_pos(s);
437 if (fn >= 0) {
438 n_f0 = n_f;
439 n_f = fn;
443 void tr_ft(char **args)
445 ren_ft(args[1]);
448 void tr_fp(char **args)
450 if (!args[2])
451 return;
452 if (dev_mnt(atoi(args[1]), args[2], args[3] ? args[3] : args[2]) < 0)
453 errmsg("troff: failed to mount %s\n", args[2]);
456 void tr_nf(char **args)
458 if (args[0][0] == c_cc)
459 ren_br(1);
460 n_u = 0;
463 void tr_fi(char **args)
465 if (args[0][0] == c_cc)
466 ren_br(1);
467 n_u = 1;
470 void tr_ce(char **args)
472 if (args[0][0] == c_cc)
473 ren_br(1);
474 n_ce = args[1] ? atoi(args[1]) : 1;
477 void tr_fc(char **args)
479 if (args[1]) {
480 c_fa = args[1][0];
481 strcpy(c_fb, args[2] ? args[2] : " ");
482 } else {
483 c_fa = -1;
484 c_fb[0] = '\0';
488 static void ren_m(char *s)
490 int m = !s || !*s ? n_m0 : clr_get(s);
491 n_m0 = n_m;
492 n_m = m;
495 static void escarg_ren(char *d, int cmd, int (*next)(void), void (*back)(int))
497 char delim[GNLEN];
498 int c;
499 if (strchr(ESC_P, cmd)) {
500 c = next();
501 if (cmd == 's' && (c == '-' || c == '+')) {
502 *d++ = c;
503 c = next();
505 if (c == '(') {
506 *d++ = next();
507 *d++ = next();
508 } else if (!n_cp && c == '[') {
509 c = next();
510 while (c > 0 && c != '\n' && c != ']') {
511 *d++ = c;
512 c = next();
514 } else {
515 *d++ = c;
516 if (cmd == 's' && c >= '1' && c <= '3') {
517 c = next();
518 if (isdigit(c))
519 *d++ = c;
520 else
521 back(c);
525 if (strchr(ESC_Q, cmd)) {
526 schar_read(delim, next);
527 while (schar_jump(delim, next, back)) {
528 if ((c = next()) < 0)
529 break;
530 *d++ = c;
533 *d = '\0';
536 static int nextchar(char *s, int (*next)(void))
538 int c = next();
539 int l = utf8len(c);
540 int i;
541 if (c < 0)
542 return 0;
543 s[0] = c;
544 for (i = 1; i < l; i++)
545 s[i] = next();
546 s[l] = '\0';
547 return l;
550 static void ren_cmd(struct wb *wb, int c, char *arg)
552 struct glyph *g;
553 switch (c) {
554 case ' ':
555 wb_hmov(wb, charwid(dev_spacewid(), n_s));
556 break;
557 case 'b':
558 ren_bracket(wb, arg);
559 break;
560 case 'c':
561 wb_setpart(wb);
562 break;
563 case 'D':
564 ren_draw(wb, arg);
565 break;
566 case 'd':
567 wb_vmov(wb, SC_EM / 2);
568 break;
569 case 'f':
570 ren_ft(arg);
571 break;
572 case 'h':
573 wb_hmov(wb, eval(arg, 'm'));
574 break;
575 case 'k':
576 num_set(map(arg), RENWB(wb) ? f_hpos() - n_lb : wb_wid(wb));
577 break;
578 case 'L':
579 ren_vline(wb, arg);
580 break;
581 case 'l':
582 ren_hline(wb, arg);
583 break;
584 case 'm':
585 ren_m(arg);
586 break;
587 case 'o':
588 ren_over(wb, arg);
589 break;
590 case 'p':
591 if (RENWB(wb))
592 ren_fillreq = 1;
593 break;
594 case 'r':
595 wb_vmov(wb, -SC_EM);
596 break;
597 case 's':
598 ren_ps(arg);
599 break;
600 case 'u':
601 wb_vmov(wb, -SC_EM / 2);
602 break;
603 case 'v':
604 wb_vmov(wb, eval(arg, 'v'));
605 break;
606 case 'X':
607 wb_etc(wb, arg);
608 break;
609 case 'x':
610 wb_els(wb, eval(arg, 'v'));
611 break;
612 case '0':
613 g = dev_glyph("0", n_f);
614 wb_hmov(wb, charwid(g ? g->wid : SC_DW, n_s));
615 break;
616 case '|':
617 wb_hmov(wb, SC_EM / 6);
618 break;
619 case '&':
620 wb_hmov(wb, 0);
621 break;
622 case '^':
623 wb_hmov(wb, SC_EM / 12);
624 break;
625 case '{':
626 case '}':
627 break;
631 static void ren_field(struct wb *wb, int (*next)(void), void (*back)(int));
633 /* read one character and place it inside wb buffer */
634 void ren_char(struct wb *wb, int (*next)(void), void (*back)(int))
636 char c[GNLEN * 4];
637 char arg[ILNLEN];
638 char *s;
639 int w, n, l;
640 nextchar(c, next);
641 if (c[0] == ' ' || c[0] == '\n') {
642 wb_put(wb, c);
643 return;
645 if (c[0] == '\t' || c[0] == '\x01') {
646 n = RENWB(wb) ? f_hpos() : wb_wid(wb);
647 wb_hmov(wb, tab_next(n) - n);
648 return;
650 if (c[0] == c_fa) {
651 ren_field(wb, next, back);
652 return;
654 if (c[0] == c_ec) {
655 nextchar(c + 1, next);
656 if (c[1] == '(') {
657 l = nextchar(c + 2, next);
658 l += nextchar(c + 2 + l, next);
659 c[2 + l] = '\0';
660 } else if (!n_cp && c[1] == '[') {
661 l = 0;
662 n = next();
663 while (n >= 0 && n != '\n' && n != ']' && l < GNLEN - 1) {
664 c[l++] = n;
665 n = next();
667 c[l] = '\0';
668 } else if (c[1] == 'z') {
669 w = wb_wid(wb);
670 ren_char(wb, next, back);
671 wb_hmov(wb, w - wb_wid(wb));
672 return;
673 } else if (c[1] == '!') {
674 if (ren_nl && next == ren_next) {
675 s = arg;
676 n = next();
677 while (n >= 0 && n != '\n') {
678 *s++ = n;
679 n = next();
681 *s = '\0';
682 ren_transparent(arg);
684 return;
685 } else if (strchr(" bCcDdfhkLlmoprsuvXxz0^|{}&", c[1])) {
686 escarg_ren(arg, c[1], next, back);
687 if (c[1] != 'C') {
688 ren_cmd(wb, c[1], arg);
689 return;
691 strcpy(c, arg);
694 if (c[0] == c_ni)
695 nextchar(c + 1, next);
696 if (!n_lg || wb_lig(wb, c)) {
697 if (n_kn)
698 wb_kern(wb, c);
699 wb_put(wb, c);
703 /* read the argument of \w and push its width */
704 int ren_wid(int (*next)(void), void (*back)(int))
706 char delim[GNLEN];
707 int c, n;
708 struct wb wb;
709 wb_init(&wb);
710 schar_read(delim, next);
711 odiv_beg();
712 c = next();
713 while (c >= 0 && c != '\n') {
714 back(c);
715 if (!schar_jump(delim, next, back))
716 break;
717 ren_char(&wb, next, back);
718 c = next();
720 odiv_end();
721 n = wb_wid(&wb);
722 wb_wconf(&wb, &n_ct, &n_st, &n_sb);
723 wb_done(&wb);
724 return n;
727 /* return 1 if the ending character (ec) was read */
728 static int ren_until(struct wb *wb, char *delim, int ec,
729 int (*next)(void), void (*back)(int))
731 int c;
732 c = next();
733 while (c >= 0 && c != '\n' && c != ec) {
734 back(c);
735 if (!schar_jump(delim, next, back))
736 break;
737 ren_char(wb, next, back);
738 c = next();
740 if (c == '\n')
741 back(c);
742 return c == ec;
745 static void wb_cpy(struct wb *dst, struct wb *src, int left)
747 wb_hmov(dst, left - wb_wid(dst));
748 wb_cat(dst, src);
751 void ren_tl(int (*next)(void), void (*back)(int))
753 struct adj *adj;
754 struct wb wb, wb2;
755 char delim[GNLEN];
756 adj = adj_alloc();
757 wb_init(&wb);
758 wb_init(&wb2);
759 schar_read(delim, next);
760 /* the left-adjusted string */
761 ren_until(&wb2, delim, '\n', next, back);
762 wb_cpy(&wb, &wb2, 0);
763 /* the centered string */
764 ren_until(&wb2, delim, '\n', next, back);
765 wb_cpy(&wb, &wb2, (n_lt - wb_wid(&wb2)) / 2);
766 /* the right-adjusted string */
767 ren_until(&wb2, delim, '\n', next, back);
768 wb_cpy(&wb, &wb2, n_lt - wb_wid(&wb2));
769 /* flushing the line */
770 adj_ll(adj, n_lt);
771 adj_wb(adj, &wb);
772 adj_nl(adj);
773 ren_bradj(adj, 0, AD_L);
774 adj_free(adj);
775 wb_done(&wb2);
776 wb_done(&wb);
779 static void ren_field(struct wb *wb, int (*next)(void), void (*back)(int))
781 struct wb wbs[NFIELDS];
782 int i, n = 0;
783 int wid = 0;
784 int left, right, cur_left;
785 int pad, rem;
786 while (n < LEN(wbs)) {
787 wb_init(&wbs[n]);
788 if (ren_until(&wbs[n++], c_fb, c_fa, next, back))
789 break;
791 left = RENWB(wb) ? f_hpos() : wb_wid(wb);
792 right = tab_next(left);
793 for (i = 0; i < n; i++)
794 wid += wb_wid(&wbs[i]);
795 pad = (right - left - wid) / (n > 1 ? n - 1 : 1);
796 rem = (right - left - wid) % (n > 1 ? n - 1 : 1);
797 for (i = 0; i < n; i++) {
798 if (i == 0)
799 cur_left = left;
800 else if (i == n - 1)
801 cur_left = right - wb_wid(&wbs[i]);
802 else
803 cur_left = wb_wid(wb) + pad + (i + rem >= n);
804 wb_cpy(wb, &wbs[i], cur_left);
805 wb_done(&wbs[i]);
809 /* read characters from in.c and pass rendered lines to out.c */
810 void render(void)
812 struct wb *wb = &ren_wb;
813 int fillreq;
814 int c;
815 n_nl = -1;
816 wb_init(wb);
817 tr_first();
818 ren_first(); /* transition to the first page */
819 c = ren_next();
820 while (1) {
821 if (c < 0) {
822 if (bp_final >= 2)
823 break;
824 if (bp_final == 0 && trap_em >= 0) {
825 trap_exec(trap_em);
826 bp_final = 1;
827 } else {
828 bp_final = 2;
829 push_eject();
830 push_br();
832 c = ren_next();
833 continue;
835 ren_cnl = c == '\n';
836 fillreq = 0;
837 /* add wb (the current word) to cadj */
838 if (c == ' ' || c == '\n') {
839 adj_swid(cadj, charwid(dev_spacewid(), n_s));
840 if (!wb_part(wb)) { /* not after a \c */
841 adj_wb(cadj, wb);
842 fillreq = ren_fillreq;
843 ren_fillreq = 0;
844 if (c == '\n')
845 adj_nl(cadj);
846 else
847 adj_sp(cadj);
850 while ((fillreq && !n_ce && n_u) || adj_full(cadj, !n_ce && n_u)) {
851 ren_br(0);
852 fillreq = 0;
854 if (c == '\n' || ren_nl) /* end or start of input line */
855 n_lb = f_hpos();
856 if (c == '\n' && !wb_part(wb))
857 n_ce = MAX(0, n_ce - 1);
858 if (c != ' ') {
859 ren_back(c);
860 ren_char(wb, ren_next, ren_back);
861 if (c != '\n' && wb_empty(wb))
862 adj_nonl(cadj);
864 ren_nl = c == '\n';
865 c = ren_next();
867 bp_final = 3;
868 if (!adj_empty(cadj, 0))
869 ren_page(bp_next, 1);
870 ren_br(1);
871 wb_done(wb);
874 /* trap handling */
876 #define tposval(i) (tpos[i] < 0 ? n_p + tpos[i] : tpos[i])
878 static int tpos[NTRAPS]; /* trap positions */
879 static int treg[NTRAPS]; /* trap registers */
880 static int ntraps;
882 static int trap_first(int pos)
884 int best = -1;
885 int i;
886 for (i = 0; i < ntraps; i++)
887 if (treg[i] >= 0 && tposval(i) > pos)
888 if (best < 0 || tposval(i) < tposval(best))
889 best = i;
890 return best;
893 static int trap_byreg(int reg)
895 int i;
896 for (i = 0; i < ntraps; i++)
897 if (treg[i] == reg)
898 return i;
899 return -1;
902 static int trap_bypos(int reg, int pos)
904 int i;
905 for (i = 0; i < ntraps; i++)
906 if (treg[i] >= 0 && tposval(i) == pos)
907 if (reg == -1 || treg[i] == reg)
908 return i;
909 return -1;
912 void tr_wh(char **args)
914 int reg, pos, id;
915 if (!args[1])
916 return;
917 pos = eval(args[1], 'v');
918 id = trap_bypos(-1, pos);
919 if (!args[2]) {
920 if (id >= 0)
921 treg[id] = -1;
922 return;
924 reg = map(args[2]);
925 if (id < 0)
926 id = trap_byreg(-1);
927 if (id < 0)
928 id = ntraps++;
929 tpos[id] = pos;
930 treg[id] = reg;
933 void tr_ch(char **args)
935 int reg;
936 int id;
937 if (!args[1])
938 return;
939 reg = map(args[1]);
940 id = trap_byreg(reg);
941 if (id >= 0)
942 tpos[id] = args[2] ? eval(args[2], 'v') : -1;
945 void tr_dt(char **args)
947 if (!cdiv)
948 return;
949 if (args[2]) {
950 cdiv->tpos = eval(args[1], 'v');
951 cdiv->treg = map(args[2]);
952 } else {
953 cdiv->treg = -1;
957 void tr_em(char **args)
959 trap_em = args[1] ? map(args[1]) : -1;
962 static int trap_pos(int pos)
964 int ret = trap_first(pos);
965 if (bp_final >= 3)
966 return -1;
967 if (cdiv)
968 return cdiv->treg && cdiv->tpos > pos ? cdiv->tpos : -1;
969 return ret >= 0 ? tposval(ret) : -1;
972 static int trap_reg(int pos)
974 int ret = trap_first(pos);
975 if (cdiv)
976 return cdiv->treg && cdiv->tpos > pos ? cdiv->treg : -1;
977 return ret >= 0 ? treg[ret] : -1;
980 int f_nexttrap(void)
982 int pos = trap_pos(n_d);
983 if (cdiv)
984 return pos >= 0 ? pos : 0x7fffffff;
985 return (pos >= 0 && pos < n_p ? pos : n_p) - n_d;