LCOV - code coverage report
Current view: top level - preproc/refer - token.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 174 239 72.8 %
Date: 2026-01-16 17:51:41 Functions: 14 19 73.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 1989-2024 Free Software Foundation, Inc.
       2             :      Written by James Clark (jjc@jclark.com)
       3             : 
       4             : This file is part of groff, the GNU roff typesetting system.
       5             : 
       6             : groff is free software; you can redistribute it and/or modify it under
       7             : the terms of the GNU General Public License as published by the Free
       8             : Software Foundation, either version 3 of the License, or
       9             : (at your option) any later version.
      10             : 
      11             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      12             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14             : for more details.
      15             : 
      16             : You should have received a copy of the GNU General Public License
      17             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : #include <config.h>
      21             : #endif
      22             : 
      23             : #include "refer.h"
      24             : #include "token.h"
      25             : 
      26             : #define TOKEN_TABLE_SIZE 1009
      27             : // I believe in Icelandic thorn sorts after z.
      28             : #define THORN_SORT_KEY "{"
      29             : 
      30             : struct token_table_entry {
      31             :   const char *tok;
      32             :   token_info ti;
      33             :   token_table_entry();
      34             : };
      35             : 
      36             : token_table_entry token_table[TOKEN_TABLE_SIZE];
      37             : int ntokens = 0;
      38             : 
      39           4 : static void skip_name(const char **ptr, const char *end)
      40             : {
      41           4 :   if (*ptr < end) {
      42           4 :     switch (*(*ptr)++) {
      43           0 :     case '(':
      44           0 :       if (*ptr < end) {
      45           0 :         *ptr += 1;
      46           0 :         if (*ptr < end)
      47           0 :           *ptr += 1;
      48             :       }
      49           0 :       break;
      50           0 :     case '[':
      51           0 :       while (*ptr < end)
      52           0 :         if (*(*ptr)++ == ']')
      53           0 :           break;
      54           0 :       break;
      55             :     }
      56             :   }
      57           4 : }
      58             : 
      59         189 : bool get_token(const char **ptr, const char *end)
      60             : {
      61         189 :   if (*ptr >= end)
      62           8 :     return false;
      63         181 :   char c = *(*ptr)++;
      64         181 :   if (c == '\\' && *ptr < end) {
      65           4 :     switch (**ptr) {
      66           0 :     default:
      67           0 :       *ptr += 1;
      68           0 :       break;
      69           0 :     case '(':
      70             :     case '[':
      71           0 :       skip_name(ptr, end);
      72           0 :       break;
      73           4 :     case '*':
      74             :     case 'f':
      75           4 :       *ptr += 1;
      76           4 :       skip_name(ptr, end);
      77           4 :       break;
      78             :     }
      79             :   }
      80         181 :   return true;
      81             : }
      82             : 
      83        6060 : token_info::token_info()
      84        6060 : : type(TOKEN_OTHER), sort_key(0), other_case(0)
      85             : {
      86        6060 : }
      87             : 
      88        2118 : void token_info::set(token_type t, const char *sk, const char *oc)
      89             : {
      90        2118 :   assert(oc == 0 || t == TOKEN_UPPER || t == TOKEN_LOWER);
      91        2118 :   type = t;
      92        2118 :   sort_key = sk;
      93        2118 :   other_case = oc;
      94        2118 : }
      95             : 
      96           0 : void token_info::sortify(const char *start, const char *end, string &result)
      97             :      const
      98             : {
      99           0 :   if (sort_key)
     100           0 :     result += sort_key;
     101           0 :   else if (type == TOKEN_UPPER || type == TOKEN_LOWER) {
     102           0 :     for (; start < end; start++)
     103           0 :       if (csalpha(*start))
     104           0 :         result += cmlower(*start);
     105             :   }
     106           0 : }
     107             : 
     108           0 : int token_info::sortify_non_empty(const char *start, const char *end) const
     109             : {
     110           0 :   if (sort_key)
     111           0 :     return *sort_key != '\0';
     112           0 :   if (type != TOKEN_UPPER && type != TOKEN_LOWER)
     113           0 :     return 0;
     114           0 :   for (; start < end; start++)
     115           0 :     if (csalpha(*start))
     116           0 :       return 1;
     117           0 :   return 0;
     118             : }
     119             : 
     120             : 
     121           0 : void token_info::lower_case(const char *start, const char *end,
     122             :                             string &result) const
     123             : {
     124           0 :   if (type != TOKEN_UPPER) {
     125           0 :     while (start < end)
     126           0 :       result += *start++;
     127             :   }
     128           0 :   else if (other_case)
     129           0 :     result += other_case;
     130             :   else {
     131           0 :     while (start < end)
     132           0 :       result += cmlower(*start++);
     133             :   }
     134           0 : }
     135             : 
     136           0 : void token_info::upper_case(const char *start, const char *end,
     137             :                             string &result) const
     138             : {
     139           0 :   if (type != TOKEN_LOWER) {
     140           0 :     while (start < end)
     141           0 :       result += *start++;
     142             :   }
     143           0 :   else if (other_case)
     144           0 :     result += other_case;
     145             :   else {
     146           0 :     while (start < end)
     147           0 :       result += cmupper(*start++);
     148             :   }
     149           0 : }
     150             : 
     151        6054 : token_table_entry::token_table_entry()
     152        6054 : : tok(0)
     153             : {
     154        6054 : }
     155             : 
     156        2112 : static void store_token(const char *tok, token_type typ,
     157             :                         const char *sk = 0, const char *oc = 0)
     158             : {
     159        2112 :   unsigned n = hash_string(tok, strlen(tok)) % TOKEN_TABLE_SIZE;
     160             :   for (;;) {
     161        6330 :     if (token_table[n].tok == 0) {
     162        2100 :       if (++ntokens == TOKEN_TABLE_SIZE)
     163           0 :         assert(0);
     164        2100 :       token_table[n].tok = tok;
     165        2100 :       break;
     166             :     }
     167        4230 :     if (strcmp(tok, token_table[n].tok) == 0)
     168          12 :       break;
     169        4218 :     if (n == 0)
     170           0 :       n = TOKEN_TABLE_SIZE - 1;
     171             :     else
     172        4218 :       --n;
     173             :   }
     174        2112 :   token_table[n].ti.set(typ, sk, oc);
     175        2112 : }
     176             : 
     177             : 
     178             : token_info default_token_info;
     179             : 
     180           0 : const token_info *lookup_token(const char *start, const char *end)
     181             : {
     182           0 :   unsigned n = hash_string(start, end - start) % TOKEN_TABLE_SIZE;
     183             :   for (;;) {
     184           0 :     if (token_table[n].tok == 0)
     185           0 :       break;
     186           0 :     if (strlen(token_table[n].tok) == size_t(end - start)
     187           0 :         && memcmp(token_table[n].tok, start, end - start) == 0)
     188           0 :       return &(token_table[n].ti);
     189           0 :     if (n == 0)
     190           0 :       n = TOKEN_TABLE_SIZE - 1;
     191             :     else
     192           0 :       --n;
     193             :   }
     194           0 :   return &default_token_info;
     195             : }
     196             : 
     197           6 : static void init_ascii()
     198             : {
     199             :   const char *p;
     200         162 :   for (p = "abcdefghijklmnopqrstuvwxyz"; *p; p++) {
     201             :     char buf[2];
     202         156 :     buf[0] = *p;
     203         156 :     buf[1] = '\0';
     204         156 :     store_token(strsave(buf), TOKEN_LOWER);
     205         156 :     buf[0] = cmupper(buf[0]);
     206         156 :     store_token(strsave(buf), TOKEN_UPPER);
     207             :   }
     208          66 :   for (p = "0123456789"; *p; p++) {
     209             :     char buf[2];
     210          60 :     buf[0] = *p;
     211          60 :     buf[1] = '\0';
     212          60 :     const char *s = strsave(buf);
     213          60 :     store_token(s, TOKEN_OTHER, s);
     214             :   }
     215          42 :   for (p = ".,:;?!"; *p; p++) {
     216             :     char buf[2];
     217          36 :     buf[0] = *p;
     218          36 :     buf[1] = '\0';
     219          36 :     store_token(strsave(buf), TOKEN_PUNCT);
     220             :   }
     221           6 :   store_token("-", TOKEN_HYPHEN);
     222           6 : }
     223             : 
     224         732 : static void store_letter(const char *lower, const char *upper,
     225             :                   const char *sort_key = 0)
     226             : {
     227         732 :   store_token(lower, TOKEN_LOWER, sort_key, upper);
     228         732 :   store_token(upper, TOKEN_UPPER, sort_key, lower);
     229         732 : }
     230             : 
     231         180 : static void init_letter(unsigned char uc_code, unsigned char lc_code,
     232             :                  const char *sort_key)
     233             : {
     234             :   char lbuf[2];
     235         180 :   lbuf[0] = lc_code;
     236         180 :   lbuf[1] = 0;
     237             :   char ubuf[2];
     238         180 :   ubuf[0] = uc_code;
     239         180 :   ubuf[1] = 0;
     240         180 :   store_letter(strsave(lbuf), strsave(ubuf), sort_key);
     241         180 : }
     242             : 
     243           6 : static void init_latin1()
     244             : {
     245           6 :   init_letter(0xc0, 0xe0, "a");
     246           6 :   init_letter(0xc1, 0xe1, "a");
     247           6 :   init_letter(0xc2, 0xe2, "a");
     248           6 :   init_letter(0xc3, 0xe3, "a");
     249           6 :   init_letter(0xc4, 0xe4, "a");
     250           6 :   init_letter(0xc5, 0xe5, "a");
     251           6 :   init_letter(0xc6, 0xe6, "ae");
     252           6 :   init_letter(0xc7, 0xe7, "c");
     253           6 :   init_letter(0xc8, 0xe8, "e");
     254           6 :   init_letter(0xc9, 0xe9, "e");
     255           6 :   init_letter(0xca, 0xea, "e");
     256           6 :   init_letter(0xcb, 0xeb, "e");
     257           6 :   init_letter(0xcc, 0xec, "i");
     258           6 :   init_letter(0xcd, 0xed, "i");
     259           6 :   init_letter(0xce, 0xee, "i");
     260           6 :   init_letter(0xcf, 0xef, "i");
     261             : 
     262           6 :   init_letter(0xd0, 0xf0, "d");
     263           6 :   init_letter(0xd1, 0xf1, "n");
     264           6 :   init_letter(0xd2, 0xf2, "o");
     265           6 :   init_letter(0xd3, 0xf3, "o");
     266           6 :   init_letter(0xd4, 0xf4, "o");
     267           6 :   init_letter(0xd5, 0xf5, "o");
     268           6 :   init_letter(0xd6, 0xf6, "o");
     269           6 :   init_letter(0xd8, 0xf8, "o");
     270           6 :   init_letter(0xd9, 0xf9, "u");
     271           6 :   init_letter(0xda, 0xfa, "u");
     272           6 :   init_letter(0xdb, 0xfb, "u");
     273           6 :   init_letter(0xdc, 0xfc, "u");
     274           6 :   init_letter(0xdd, 0xfd, "y");
     275           6 :   init_letter(0xde, 0xfe, THORN_SORT_KEY);
     276             : 
     277           6 :   store_token("\337", TOKEN_LOWER, "ss", "SS");
     278           6 :   store_token("\377", TOKEN_LOWER, "y", "Y");
     279           6 : }
     280             : 
     281         252 : static void init_two_char_letter(char l1, char l2, char u1, char u2,
     282             :                                  const char *sk = 0)
     283             : {
     284             :   char buf[6];
     285         252 :   buf[0] = '\\';
     286         252 :   buf[1] = '(';
     287         252 :   buf[2] = l1;
     288         252 :   buf[3] = l2;
     289         252 :   buf[4] = '\0';
     290         252 :   const char *p = strsave(buf);
     291         252 :   buf[2] = u1;
     292         252 :   buf[3] = u2;
     293         252 :   store_letter(p, strsave(buf), sk);
     294         252 :   buf[1] = '[';
     295         252 :   buf[4] = ']';
     296         252 :   buf[5] = '\0';
     297         252 :   p = strsave(buf);
     298         252 :   buf[2] = l1;
     299         252 :   buf[3] = l2;
     300         252 :   store_letter(strsave(buf), p, sk);
     301             : 
     302         252 : }
     303             : 
     304           6 : static void init_special_chars()
     305             : {
     306             :   const char *p;
     307          36 :   for (p = "':^`~"; *p; p++)
     308         210 :     for (const char *q = "aeiouy"; *q; q++) {
     309             :       // Use a variable to work around bug in gcc 2.0
     310         180 :       char c = cmupper(*q);
     311         180 :       init_two_char_letter(*p, *q, *p, c);
     312             :     }
     313          48 :   for (p = "/l/o~n,coeaeij"; *p; p += 2) {
     314             :     // Use variables to work around bug in gcc 2.0
     315          42 :     char c0 = cmupper(p[0]);
     316          42 :     char c1 = cmupper(p[1]);
     317          42 :     init_two_char_letter(p[0], p[1], c0, c1);
     318             :   }
     319           6 :   init_two_char_letter('v', 's', 'v', 'S', "s");
     320           6 :   init_two_char_letter('v', 'z', 'v', 'Z', "z");
     321           6 :   init_two_char_letter('o', 'a', 'o', 'A', "a");
     322           6 :   init_two_char_letter('T', 'p', 'T', 'P', THORN_SORT_KEY);
     323           6 :   init_two_char_letter('-', 'd', '-', 'D');
     324             : 
     325           6 :   store_token("\\(ss", TOKEN_LOWER, 0, "SS");
     326           6 :   store_token("\\[ss]", TOKEN_LOWER, 0, "SS");
     327             : 
     328           6 :   store_token("\\(Sd", TOKEN_LOWER, "d", "\\(-D");
     329           6 :   store_token("\\[Sd]", TOKEN_LOWER, "d", "\\[-D]");
     330           6 :   store_token("\\(hy", TOKEN_HYPHEN);
     331           6 :   store_token("\\[hy]", TOKEN_HYPHEN);
     332           6 :   store_token("\\(en", TOKEN_RANGE_SEP);
     333           6 :   store_token("\\[en]", TOKEN_RANGE_SEP);
     334           6 : }
     335             : 
     336           6 : static void init_strings()
     337             : {
     338             :   char buf[6];
     339           6 :   buf[0] = '\\';
     340           6 :   buf[1] = '*';
     341          84 :   for (const char *p = "'`^^,:~v_o./;"; *p; p++) {
     342          78 :     buf[2] = *p;
     343          78 :     buf[3] = '\0';
     344          78 :     store_token(strsave(buf), TOKEN_ACCENT);
     345          78 :     buf[2] = '[';
     346          78 :     buf[3] = *p;
     347          78 :     buf[4] = ']';
     348          78 :     buf[5] = '\0';
     349          78 :     store_token(strsave(buf), TOKEN_ACCENT);
     350             :   }
     351             : 
     352             :   // -ms special letters
     353           6 :   store_letter("\\*(th", "\\*(Th", THORN_SORT_KEY);
     354           6 :   store_letter("\\*[th]", "\\*[Th]", THORN_SORT_KEY);
     355           6 :   store_letter("\\*(d-", "\\*(D-");
     356           6 :   store_letter("\\*[d-]", "\\*[D-]");
     357           6 :   store_letter("\\*(ae", "\\*(Ae", "ae");
     358           6 :   store_letter("\\*[ae]", "\\*[Ae]", "ae");
     359           6 :   store_letter("\\*(oe", "\\*(Oe", "oe");
     360           6 :   store_letter("\\*[oe]", "\\*[Oe]", "oe");
     361             : 
     362           6 :   store_token("\\*3", TOKEN_LOWER, "y", "Y");
     363           6 :   store_token("\\*8", TOKEN_LOWER, "ss", "SS");
     364           6 :   store_token("\\*q", TOKEN_LOWER, "o", "O");
     365           6 : }
     366             : 
     367             : struct token_initer {
     368             :   token_initer();
     369             : };
     370             : 
     371             : static token_initer the_token_initer;
     372             : 
     373           6 : token_initer::token_initer()
     374             : {
     375           6 :   init_ascii();
     376           6 :   init_latin1();
     377           6 :   init_special_chars();
     378           6 :   init_strings();
     379           6 :   default_token_info.set(TOKEN_OTHER);
     380           6 : }
     381             : 
     382             : // Local Variables:
     383             : // fill-column: 72
     384             : // mode: C++
     385             : // End:
     386             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14