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