LCOV - code coverage report
Current view: top level - preproc/eqn - script.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 98 147 66.7 %
Date: 2026-01-16 17:51:41 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright 1989-2023 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 <assert.h>
      24             : 
      25             : #include "eqn.h"
      26             : #include "pbox.h"
      27             : 
      28             : class script_box : public pointer_box {
      29             : private:
      30             :   box *sub;
      31             :   box *sup;
      32             : public:
      33             :   script_box(box *, box *, box *);
      34             :   ~script_box();
      35             :   int compute_metrics(int);
      36             :   void output();
      37             :   void debug_print();
      38             :   int left_is_italic();
      39             :   void hint(unsigned);
      40             :   void diagnose_tab_stop_usage(int);
      41             : };
      42             : 
      43             : /* The idea is that the script should attach to the rightmost box
      44             : of a list. For example, given '2x sup 3', the superscript should
      45             : attach to 'x' rather than '2x'. */
      46             : 
      47         223 : box *make_script_box(box *nuc, box *sub, box *sup)
      48             : {
      49         223 :   list_box *b = nuc->to_list_box();
      50         223 :   if (b != 0) {
      51          58 :     b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
      52             :                                                sub,
      53             :                                                sup);
      54          58 :     return b;
      55             :   }
      56             :   else
      57         165 :     return new script_box(nuc, sub, sup);
      58             : }
      59             : 
      60         165 : script_box::script_box(box *pp, box *qq, box *rr)
      61         165 : : pointer_box(pp), sub(qq), sup(rr)
      62             : {
      63         165 : }
      64             : 
      65         330 : script_box::~script_box()
      66             : {
      67         165 :   delete sub;
      68         165 :   delete sup;
      69         330 : }
      70             : 
      71         107 : int script_box::left_is_italic()
      72             : {
      73         107 :   return p->left_is_italic();
      74             : }
      75             : 
      76         165 : int script_box::compute_metrics(int style)
      77             : {
      78         165 :   int res = p->compute_metrics(style);
      79         165 :   p->compute_subscript_kern();
      80         165 :   printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
      81         165 :   if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
      82         165 :     set_script_size();
      83         165 :   printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
      84         165 :   if (sub != 0)
      85         147 :     sub->compute_metrics(cramped_style(script_style(style)));
      86         165 :   if (sup != 0)
      87          18 :     sup->compute_metrics(script_style(style));
      88             :   // 18a
      89         165 :   if (p->is_char()) {
      90         165 :     printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
      91         165 :     printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
      92             :   }
      93             :   else {
      94           0 :     printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
      95           0 :            uid, p->uid, get_param("sup_drop"));
      96           0 :     printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
      97           0 :            uid, p->uid, get_param("sub_drop"));
      98             :   }
      99         165 :   printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
     100         165 :   if (sup == 0) {
     101         147 :     assert(sub != 0);
     102             :     // 18b
     103         147 :     printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
     104             :            HEIGHT_FORMAT "]-(%dM*4/5))\n",
     105         147 :            uid, uid, get_param("sub1"), sub->uid,
     106             :            get_param("x_height"));
     107             :   }
     108             :   else {
     109             :     // sup != 0
     110             :     // 18c
     111             :     int pos;
     112          18 :     if (style == DISPLAY_STYLE)
     113          10 :       pos = get_param("sup1");
     114           8 :     else if (style & 1)             // not cramped
     115           0 :       pos = get_param("sup2");
     116             :     else
     117           8 :       pos = get_param("sup3");
     118          18 :     printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
     119             :            "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
     120          18 :            uid, uid, pos, sup->uid, get_param("x_height"));
     121             :     // 18d
     122          18 :     if (sub != 0) {
     123           0 :       printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
     124           0 :              uid, uid, get_param("sub2"));
     125             :       // 18e
     126           0 :       printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
     127             :              SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
     128             :              SUB_LOWER_FORMAT "]+(4*%dM)\n",
     129           0 :              sup->uid, uid, sub->uid, uid,
     130             :              get_param("default_rule_thickness"));
     131           0 :       printf(".if \\n[" TEMP_REG "] \\{");
     132           0 :       printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
     133           0 :       printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
     134             :              "]+\\n[" DEPTH_FORMAT "]>?0\n",
     135           0 :              get_param("x_height"), uid, sup->uid);
     136           0 :       printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
     137           0 :       printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
     138           0 :       printf(".\\}\n");
     139             :     }
     140             :   }
     141         165 :   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
     142         165 :   if (sub != 0 && sup != 0)
     143           0 :     printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
     144             :            WIDTH_FORMAT "])+%dM)>?0\n",
     145           0 :            sub->uid, p->uid, sup->uid, get_param("script_space"));
     146         165 :   else if (sub != 0)
     147         147 :     printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
     148         147 :            sub->uid, p->uid, get_param("script_space"));
     149          18 :   else if (sup != 0)
     150          18 :     printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid,
     151             :            get_param("script_space"));
     152             :   else
     153           0 :     printf("\n");
     154         165 :   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
     155         165 :          uid, p->uid);
     156         165 :   if (sup != 0)
     157          18 :     printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
     158          18 :            uid, sup->uid);
     159         165 :   if (sub != 0)
     160         147 :     printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
     161         147 :            uid, sub->uid);
     162         165 :   printf("\n");
     163         165 :   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
     164         165 :          uid, p->uid);
     165         165 :   if (sub != 0)
     166         147 :     printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
     167         147 :            uid, sub->uid);
     168         165 :   if (sup != 0)
     169          18 :     printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
     170          18 :            uid, sup->uid);
     171         165 :   printf("\n");
     172         165 :   return res;
     173             : }
     174             : 
     175         165 : void script_box::output()
     176             : {
     177         165 :   if (output_format == troff) {
     178         165 :     p->output();
     179         165 :     if (sup != 0) {
     180          18 :       printf("\\Z" DELIMITER_CHAR);
     181          18 :       printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
     182          18 :       printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
     183          18 :       sup->output();
     184          18 :       printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
     185          18 :       printf(DELIMITER_CHAR);
     186             :     }
     187         165 :     if (sub != 0) {
     188         147 :       printf("\\Z" DELIMITER_CHAR);
     189         147 :       printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
     190         147 :       printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
     191         147 :       printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
     192         147 :       sub->output();
     193         147 :       printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
     194         147 :       printf(DELIMITER_CHAR);
     195             :     }
     196         165 :     printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
     197         165 :            uid, p->uid);
     198             :   }
     199           0 :   else if (output_format == mathml) {
     200           0 :     if (sup != 0 && sub != 0) {
     201           0 :       printf("<msubsup>");
     202           0 :       p->output();
     203           0 :       sub->output();
     204           0 :       sup->output();
     205           0 :       printf("</msubsup>");
     206             :     }
     207           0 :     else if (sup != 0) {
     208           0 :       printf("<msup>");
     209           0 :       p->output();
     210           0 :       sup->output();
     211           0 :       printf("</msup>");
     212             :   }
     213           0 :   else if (sub != 0) {
     214           0 :       printf("<msub>");
     215           0 :       p->output();
     216           0 :       sub->output();
     217           0 :       printf("</msub>");
     218             :     }
     219             :   }
     220         165 : }
     221             : 
     222          62 : void script_box::hint(unsigned flags)
     223             : {
     224          62 :   p->hint(flags & ~HINT_NEXT_IS_ITALIC);
     225          62 : }
     226             : 
     227           0 : void script_box::debug_print()
     228             : {
     229           0 :   fprintf(stderr, "{ ");
     230           0 :   p->debug_print();
     231           0 :   fprintf(stderr, " }");
     232           0 :   if (sub) {
     233           0 :     fprintf(stderr, " sub { ");
     234           0 :     sub->debug_print();
     235           0 :     fprintf(stderr, " }");
     236             :   }
     237           0 :   if (sup) {
     238           0 :     fprintf(stderr, " sup { ");
     239           0 :     sup->debug_print();
     240           0 :     fprintf(stderr, " }");
     241             :   }
     242           0 : }
     243             : 
     244         165 : void script_box::diagnose_tab_stop_usage(int level)
     245             : {
     246         165 :   if (sup)
     247          18 :     sup->diagnose_tab_stop_usage(level + 1);
     248         165 :   if (sub)
     249         147 :     sub->diagnose_tab_stop_usage(level + 1);
     250         165 :   p->diagnose_tab_stop_usage(level);
     251         165 : }
     252             : 
     253             : // Local Variables:
     254             : // fill-column: 72
     255             : // mode: C++
     256             : // End:
     257             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14