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