1 /* $Id: term_tab.c,v 1.9 2025/07/16 14:33:08 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2017, 2021, 2025 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 [BU]. */ 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 basic units. */ 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_hspan(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_hspan(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 size_t 95 term_tab_next(size_t prev) 96 { 97 size_t i, j; 98 99 for (i = 0;; i++) { 100 if (i == tabs.a.n) { 101 if (tabs.p.n == 0) 102 return prev; 103 tabs.a.n += tabs.p.n; 104 if (tabs.a.s < tabs.a.n) { 105 tabs.a.s = tabs.a.n; 106 tabs.a.t = mandoc_reallocarray(tabs.a.t, 107 tabs.a.s, sizeof(*tabs.a.t)); 108 } 109 for (j = 0; j < tabs.p.n; j++) 110 tabs.a.t[i + j] = tabs.p.t[j] + 111 (i ? tabs.a.t[i - 1] : 0); 112 } 113 if (prev < tabs.a.t[i]) 114 return tabs.a.t[i]; 115 } 116 } 117 118 void 119 term_tab_free(void) 120 { 121 free(tabs.a.t); 122 free(tabs.p.t); 123 memset(&tabs, 0, sizeof(tabs)); 124 tabs.r = &tabs.a; 125 } 126