1 /* $OpenBSD: term_tab.c,v 1.5 2021/10/04 18:56:24 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2017, 2021 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 #include <stdlib.h> 21 #include <string.h> 22 23 #include "mandoc_aux.h" 24 #include "out.h" 25 #include "term.h" 26 27 struct tablist { 28 size_t *t; /* Allocated array of tab positions. */ 29 size_t s; /* Allocated number of positions. */ 30 size_t n; /* Currently used number of positions. */ 31 }; 32 33 static struct { 34 struct tablist a; /* All tab positions for lookup. */ 35 struct tablist p; /* Periodic tab positions to add. */ 36 struct tablist *r; /* Tablist currently being recorded. */ 37 size_t d; /* Default tab width in units of n. */ 38 } tabs; 39 40 41 void 42 term_tab_set(const struct termp *p, const char *arg) 43 { 44 struct roffsu su; 45 struct tablist *tl; 46 size_t pos; 47 int add; 48 49 /* Special arguments: clear all tabs or switch lists. */ 50 51 if (arg == NULL) { 52 tabs.a.n = tabs.p.n = 0; 53 tabs.r = &tabs.a; 54 if (tabs.d == 0) { 55 a2roffsu(".8i", &su, SCALE_IN); 56 tabs.d = term_hen(p, &su); 57 } 58 return; 59 } 60 if (arg[0] == 'T' && arg[1] == '\0') { 61 tabs.r = &tabs.p; 62 return; 63 } 64 65 /* Parse the sign, the number, and the unit. */ 66 67 if (*arg == '+') { 68 add = 1; 69 arg++; 70 } else 71 add = 0; 72 if (a2roffsu(arg, &su, SCALE_EM) == NULL) 73 return; 74 75 /* Select the list, and extend it if it is full. */ 76 77 tl = tabs.r; 78 if (tl->n >= tl->s) { 79 tl->s += 8; 80 tl->t = mandoc_reallocarray(tl->t, tl->s, sizeof(*tl->t)); 81 } 82 83 /* Append the new position. */ 84 85 pos = term_hen(p, &su); 86 tl->t[tl->n] = pos; 87 if (add && tl->n) 88 tl->t[tl->n] += tl->t[tl->n - 1]; 89 tl->n++; 90 } 91 92 /* 93 * Simplified version without a parser, 94 * never incremental, never periodic, for use by tbl(7). 95 */ 96 void 97 term_tab_iset(size_t inc) 98 { 99 if (tabs.a.n >= tabs.a.s) { 100 tabs.a.s += 8; 101 tabs.a.t = mandoc_reallocarray(tabs.a.t, tabs.a.s, 102 sizeof(*tabs.a.t)); 103 } 104 tabs.a.t[tabs.a.n++] = inc; 105 } 106 107 size_t 108 term_tab_next(size_t prev) 109 { 110 size_t i, j; 111 112 for (i = 0;; i++) { 113 if (i == tabs.a.n) { 114 if (tabs.p.n == 0) 115 return prev; 116 tabs.a.n += tabs.p.n; 117 if (tabs.a.s < tabs.a.n) { 118 tabs.a.s = tabs.a.n; 119 tabs.a.t = mandoc_reallocarray(tabs.a.t, 120 tabs.a.s, sizeof(*tabs.a.t)); 121 } 122 for (j = 0; j < tabs.p.n; j++) 123 tabs.a.t[i + j] = tabs.p.t[j] + 124 (i ? tabs.a.t[i - 1] : 0); 125 } 126 if (prev < tabs.a.t[i]) 127 return tabs.a.t[i]; 128 } 129 } 130 131 void 132 term_tab_free(void) 133 { 134 free(tabs.a.t); 135 free(tabs.p.t); 136 memset(&tabs, 0, sizeof(tabs)); 137 tabs.r = &tabs.a; 138 } 139