1 /* $OpenBSD: term.c,v 1.119 2017/01/08 18:08:44 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/types.h> 18 19 #include <stddef.h> 20 21 #include "mandoc_aux.h" 22 #include "out.h" 23 #include "term.h" 24 25 struct tablist { 26 size_t *t; /* Allocated array of tab positions. */ 27 size_t s; /* Allocated number of positions. */ 28 size_t n; /* Currently used number of positions. */ 29 }; 30 31 static struct { 32 struct tablist a; /* All tab positions for lookup. */ 33 struct tablist p; /* Periodic tab positions to add. */ 34 size_t d; /* Default tab width in units of n. */ 35 } tabs; 36 37 38 void 39 term_tab_set(const struct termp *p, const char *arg) 40 { 41 static int recording_period; 42 43 struct roffsu su; 44 struct tablist *tl; 45 size_t pos; 46 int add; 47 48 /* Special arguments: clear all tabs or switch lists. */ 49 50 if (arg == NULL) { 51 tabs.a.n = tabs.p.n = 0; 52 recording_period = 0; 53 if (tabs.d == 0) { 54 a2roffsu(".8i", &su, SCALE_IN); 55 tabs.d = term_hen(p, &su); 56 } 57 return; 58 } 59 if (arg[0] == 'T' && arg[1] == '\0') { 60 recording_period = 1; 61 return; 62 } 63 64 /* Parse the sign, the number, and the unit. */ 65 66 if (*arg == '+') { 67 add = 1; 68 arg++; 69 } else 70 add = 0; 71 if (a2roffsu(arg, &su, SCALE_EM) == NULL) 72 return; 73 74 /* Select the list, and extend it if it is full. */ 75 76 tl = recording_period ? &tabs.p : &tabs.a; 77 if (tl->n >= tl->s) { 78 tl->s += 8; 79 tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t)); 80 } 81 82 /* Append the new position. */ 83 84 pos = term_hen(p, &su); 85 tl->t[tl->n] = pos; 86 if (add && tl->n) 87 tl->t[tl->n] += tl->t[tl->n - 1]; 88 tl->n++; 89 } 90 91 /* 92 * Simplified version without a parser, 93 * never incremental, never periodic, for use by tbl(7). 94 */ 95 void 96 term_tab_iset(size_t inc) 97 { 98 if (tabs.a.n >= tabs.a.s) { 99 tabs.a.s += 8; 100 tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s, 101 sizeof(*tabs.a.t)); 102 } 103 tabs.a.t[tabs.a.n++] = inc; 104 } 105 106 size_t 107 term_tab_next(size_t prev) 108 { 109 size_t i, j; 110 111 for (i = 0;; i++) { 112 if (i == tabs.a.n) { 113 if (tabs.p.n == 0) 114 return prev; 115 tabs.a.n += tabs.p.n; 116 if (tabs.a.s < tabs.a.n) { 117 tabs.a.s = tabs.a.n; 118 tabs.a.t = mandoc_reallocarray(tabs.a.t, 119 tabs.a.s, sizeof(*tabs.a.t)); 120 } 121 for (j = 0; j < tabs.p.n; j++) 122 tabs.a.t[i + j] = tabs.p.t[j] + 123 (i ? tabs.a.t[i - 1] : 0); 124 } 125 if (prev < tabs.a.t[i]) 126 return tabs.a.t[i]; 127 } 128 } 129