LCOV - code coverage report
Current view: top level - devices/grolbp - lbp.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 121 404 30.0 %
Date: 2026-01-16 17:51:41 Functions: 19 26 73.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 1994-2025 Free Software Foundation, Inc.
       2             :      Written by Francisco Andrés Verdú <pandres@dragonet.es> with many
       3             :      ideas taken from the other groff drivers.
       4             : 
       5             : This file is part of groff, the GNU roff typesetting system.
       6             : 
       7             : groff is free software; you can redistribute it and/or modify it under
       8             : the terms of the GNU General Public License as published by the Free
       9             : Software Foundation, either version 3 of the License, or
      10             : (at your option) any later version.
      11             : 
      12             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      13             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15             : for more details.
      16             : 
      17             : You should have received a copy of the GNU General Public License
      18             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      19             : 
      20             : /*
      21             : TODO
      22             : 
      23             :  - Add X command to include bitmaps
      24             : */
      25             : 
      26             : #ifdef HAVE_CONFIG_H
      27             : #include <config.h>
      28             : #endif
      29             : 
      30             : #include <assert.h>
      31             : #include <errno.h>
      32             : #include <limits.h> // INT_MAX
      33             : #include <math.h> // fabs(), sqrt()
      34             : #include <stdcountof.h>
      35             : #include <stdlib.h> // abs(), EXIT_SUCCESS, exit(), strtol()
      36             : #include <string.h> // strcmp(), strcpy(), strlen(), strncpy()
      37             : #include <strings.h> // strcasecmp()
      38             : 
      39             : #include <getopt.h> // getopt_long()
      40             : 
      41             : #include "nonposix.h"
      42             : 
      43             : #include "charset.h"
      44             : #include "driver.h"
      45             : #include "lbp.h"
      46             : #include "lib.h" // strsave()
      47             : #include "paper.h"
      48             : 
      49             : extern "C" const char *Version_string;
      50             : 
      51             : static int user_papersize = -1;
      52             : static int orientation = -1;
      53             : 
      54             : // custom paper format
      55             : static double user_paperlength = 0;
      56             : static double user_paperwidth = 0;
      57             : 
      58             : static int ncopies = 1;
      59             : 
      60             : #define DEFAULT_LINEWIDTH_FACTOR 40     // 0.04em
      61             : static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR;
      62             : 
      63             : static int set_papersize(const char *paperformat);
      64             : 
      65             : class lbp_font : public font {
      66             : public:
      67             :   ~lbp_font();
      68             :   void handle_unknown_font_command(const char * /* command */,
      69             :                                    const char * /* arg */,
      70             :                                    const char * /* fn */,
      71             :                                    int /* lineno */);
      72             :   static lbp_font *load_lbp_font(const char * /* s */);
      73             :   char *lbpname;
      74             :   char is_scalable;
      75             : private:
      76             :   lbp_font(const char *);
      77             : };
      78             : 
      79             : class lbp_printer : public printer {
      80             : public:
      81             :   lbp_printer(int, double, double);
      82             :   ~lbp_printer();
      83             :   void set_char(glyph * /* g */, font * /* f */,
      84             :                 const environment * /* env */, int /* w */,
      85             :                 const char * /* UNUSED */);
      86             :   void draw(int /* code */, int * /* p */, int /* np */,
      87             :             const environment * /* env */);
      88             :   void begin_page(int /* UNUSED */);
      89             :   void end_page(int /* page_length */);
      90             :   font *make_font(const char * /* nm */);
      91             :   void end_of_line();
      92             : private:
      93             :   void set_line_thickness(int /* size */,
      94             :                           const environment * /* env */);
      95             :   void vdmstart();
      96             :   void vdmflush(); // the name vdmend was already used in lbp.h
      97             :   void setfillmode(int /* mode */);
      98             :   void polygon(int /* hpos */, int /* vpos */, int /* np */,
      99             :                int * /* p */);
     100             :   char *font_name(const lbp_font * /* f */, const int /* siz */);
     101             : 
     102             :   int fill_pattern;
     103             :   int fill_mode;
     104             :   int cur_hpos;
     105             :   int cur_vpos;
     106             :   lbp_font *cur_font;
     107             :   int cur_size;
     108             :   unsigned short cur_symbol_set;
     109             :   int line_thickness;
     110             :   int req_linethickness; // requested line thickness
     111             :   // custom paper format
     112             :   int papersize;
     113             :   int paperlength;
     114             :   int paperwidth;
     115             : };
     116             : 
     117           1 : lbp_font::lbp_font(const char *nm)
     118           1 : : font(nm)
     119             : {
     120           1 : }
     121             : 
     122           2 : lbp_font::~lbp_font()
     123             : {
     124           2 : }
     125             : 
     126           1 : lbp_font *lbp_font::load_lbp_font(const char *s)
     127             : {
     128           1 :   lbp_font *f = new lbp_font(s);
     129           1 :   f->lbpname = 0 /* nullptr */;
     130           1 :   f->is_scalable = 1; // Default is that fonts are scalable
     131           1 :   if (!f->load()) {
     132           0 :     delete f;
     133           0 :     return 0;
     134             :   }
     135           1 :   return f;
     136             : }
     137             : 
     138             : 
     139           1 : void lbp_font::handle_unknown_font_command(const char *command,
     140             :                                            const char *arg,
     141             :                                            const char *fn, int lineno)
     142             : {
     143           1 :   if (strcmp(command, "lbpname") == 0) {
     144           1 :     if (arg == 0)
     145           0 :       fatal_with_file_and_line(fn, lineno,
     146             :                                "'%1' command requires an argument",
     147           0 :                                command);
     148           1 :     this->lbpname = new char[strlen(arg) + 1];
     149           1 :     strcpy(this->lbpname, arg);
     150             :     // we recognize bitmapped fonts by the first character of its name
     151           1 :     if (arg[0] == 'N')
     152           0 :       this->is_scalable = 0;
     153             :     // fprintf(stderr, "Loading font \"%s\" \n", arg);
     154             :   }
     155             :   // fprintf(stderr, "Loading font  %s \"%s\" in %s at %d\n",
     156             :   //         command, arg, fn, lineno);
     157           1 : }
     158             : 
     159           1 : static void wp54charset()
     160             : {
     161             :   unsigned int i;
     162           1 :   lbpputs("\033[714;100;29;0;32;120.}");
     163         715 :   for (i = 0; i < sizeof symset; i++)
     164         714 :     lbpputc(symset[i]);
     165           1 :   lbpputs("\033[100;0 D");
     166           1 :   return;
     167             : }
     168             : 
     169           1 : lbp_printer::lbp_printer(int ps, double pw, double pl)
     170             : : fill_pattern(1),
     171             :   fill_mode(0),
     172             :   cur_hpos(-1),
     173             :   cur_font(0),
     174             :   cur_size(0),
     175             :   cur_symbol_set(0),
     176           1 :   req_linethickness(-1)
     177             : {
     178             :   SET_BINARY(fileno(stdout));
     179           1 :   lbpinit(stdout);
     180           1 :   lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
     181           1 :   wp54charset(); // Define the new symbol set
     182           1 :   lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
     183             :   // Paper format handling
     184           1 :   if (orientation < 0)
     185           0 :     orientation = 0;    // Default orientation is portrait
     186           1 :   papersize = 14;       // Default paper format is A4
     187           1 :   if (font::papersize) {
     188           1 :     papersize = set_papersize(font::papersize);
     189           1 :     paperlength = font::paperlength;
     190           1 :     paperwidth = font::paperwidth;
     191             :   }
     192           1 :   if (ps >= 0) {
     193           0 :     papersize = ps;
     194           0 :     paperlength = int(pl * font::res + 0.5);
     195           0 :     paperwidth = int(pw * font::res + 0.5);
     196             :   }
     197           1 :   if (papersize < 80)        // standard paper
     198           1 :     lbpprintf("\033[%dp", (papersize | orientation));
     199             :   else                  // Custom paper
     200           0 :     lbpprintf("\033[%d;%d;%dp", (papersize | orientation),
     201             :               paperlength, paperwidth);
     202             :   // Number of copies
     203           1 :   lbpprintf("\033[%dv\n", ncopies);
     204           1 :   lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
     205           1 :   lbpmoveabs(0, 0);
     206           1 :   lbpputs("\033[0t\033[2t");
     207           1 :   lbpputs("\033('$2\033)' 1");        // Primary symbol set IBML
     208             :                                 // Secondary symbol set IBMR1
     209           1 :   cur_symbol_set = 0;
     210           1 : }
     211             : 
     212           2 : lbp_printer::~lbp_printer()
     213             : {
     214           1 :   current_lineno = 0; // At this point, we've read all the input.
     215           1 :   lbpputs("\033P1y\033\\");
     216           1 :   lbpputs("\033c\033<");
     217           2 : }
     218             : 
     219           1 : inline void lbp_printer::set_line_thickness(int size,
     220             :                                             const environment *env)
     221             : {
     222           1 :       if (size == 0)
     223           0 :         line_thickness = 1;
     224             :       else {
     225           1 :         if (size < 0)
     226             :                 // line_thickness =
     227             :                 //   (env->size * (font::res/72)) * (linewidth_factor/1000)
     228             :                 // we ought to check for overflow
     229           1 :                 line_thickness =
     230           1 :                   env->size * linewidth_factor * font::res / 72000;
     231             :         else // size > 0
     232           0 :                 line_thickness = size;
     233             :       } // else from if (size == 0)
     234           1 :       if (line_thickness < 1)
     235           0 :         line_thickness = 1;
     236           1 :       if (vdminited())
     237           0 :         vdmlinewidth(line_thickness);
     238           1 :       req_linethickness = size; // an size requested
     239             :       /*  fprintf(stderr, "thickness: %d == %d, size %d, %d \n",
     240             :         size, line_thickness, env->size,req_linethickness); */
     241           1 :    return;
     242             : } // lbp_printer::set_line_thickness
     243             : 
     244           1 : void lbp_printer::begin_page(int)
     245             : {
     246           1 : }
     247             : 
     248           1 : void lbp_printer::end_page(int)
     249             : {
     250           1 :   if (vdminited())
     251           0 :     vdmflush();
     252           1 :   lbpputc('\f');
     253           1 :   cur_hpos = -1;
     254           1 : }
     255             : 
     256           1 : void lbp_printer::end_of_line()
     257             : {
     258           1 :   cur_hpos = -1;                // force absolute motion
     259           1 : }
     260             : 
     261           0 : char *lbp_printer::font_name(const lbp_font *f, const int siz)
     262             : {
     263             :   static char bfont_name[255];  // The resulting font name
     264             :   char type,    // Italic, Roman, Bold
     265             :        ori,     // Normal or Rotated
     266             :        *nam;    // The font name without other data.
     267             :   int cpi;      // The font size in characters per inch
     268             :                 // (bitmapped fonts are monospaced).
     269             :   /* Bitmap font selection is ugly in this printer, so don't expect
     270             :      this function to be elegant. */
     271           0 :   bfont_name[0] = 0x00;
     272           0 :   if (orientation)      // Landscape
     273           0 :     ori = 'R';
     274             :   else                  // Portrait
     275           0 :     ori = 'N';
     276           0 :   type = f->lbpname[strlen(f->lbpname) - 1];
     277           0 :   nam = new char[strlen(f->lbpname) - 2];
     278           0 :   strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2);
     279           0 :   nam[strlen(f->lbpname) - 2] = 0x00;
     280             :   // fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori);
     281             :   /* Since these fonts are available only at certain sizes,
     282             :      10 and 17 cpi for courier,  12 and 17 cpi for elite,
     283             :      we adjust the resulting size. */
     284           0 :   cpi = 17;
     285             :   // Fortunately there are only two bitmapped fonts shipped with the printer.
     286           0 :   if (!strcasecmp(nam, "courier")) {
     287             :     // Courier font
     288           0 :     if (siz >= 12)
     289           0 :       cpi = 10;
     290           0 :     else cpi = 17;
     291             :   }
     292           0 :   if (!strcasecmp(nam, "elite")) {
     293           0 :     if (siz >= 10)
     294           0 :       cpi = 12;
     295           0 :     else cpi = 17;
     296             :   }
     297             :   // Now that we have all the data, let's generate the font name.
     298           0 :   if ((type != 'B') && (type != 'I')) // Roman font
     299           0 :     sprintf(bfont_name, "%c%s%d", ori, nam, cpi);
     300             :   else
     301           0 :     sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type);
     302           0 :   return bfont_name;
     303             : }
     304             : 
     305          12 : void lbp_printer::set_char(glyph *g, font *f, const environment *env,
     306             :                            int w, const char *)
     307             : {
     308          12 :   int code = f->get_code(g);
     309          12 :   unsigned char ch = code & 0xff;
     310          12 :   unsigned short symbol_set = code >> 8;
     311          12 :   if (f != cur_font) {
     312           1 :     lbp_font *psf = (lbp_font *)f;
     313             :     // fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size);
     314           1 :     if (psf->is_scalable) {
     315             :       // Scalable font selection is different from bitmaped
     316           1 :       lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname,
     317           1 :                 (int)((env->size * font::res) / 72));
     318             :     }
     319             :     else
     320             :       // bitmapped font
     321           0 :       lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size));
     322           1 :     lbpputs("\033)' 1");      // Select IBML and IBMR1 symbol set
     323           1 :     cur_font = psf;
     324           1 :     cur_symbol_set = 0;
     325             :      // Update the line thickness if needed
     326           1 :     if ((req_linethickness < 0 ) && (env->size != cur_size))
     327           1 :         set_line_thickness(req_linethickness,env);
     328           1 :     cur_size = env->size;
     329             :   }
     330          12 :   if (symbol_set != cur_symbol_set) {
     331           0 :     if (cur_symbol_set == 3)
     332             :       // if current symbol set is Symbol we must restore the font
     333           0 :       lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname,
     334           0 :                 (int)((env->size * font::res) / 72));
     335           0 :     switch (symbol_set) {
     336           0 :     case 0:
     337           0 :       lbpputs("\033('$2\033)' 1");    // Select IBML and IBMR1 symbol sets
     338           0 :       break;
     339           0 :     case 1:
     340           0 :       lbpputs("\033(d\033)' 1");      // Select wp54 symbol set
     341           0 :       break;
     342           0 :     case 2:
     343           0 :       lbpputs("\033('$2\033)'!0");    // Select IBMP symbol set
     344           0 :       break;
     345           0 :     case 3:
     346           0 :       lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",
     347           0 :                 (int)((env->size * font::res) / 72));
     348           0 :       lbpputs("\033(\"!!0\033)\"!!1");      // Select symbol font
     349           0 :       break;
     350           0 :     case 4:
     351           0 :       lbpputs("\033)\"! 1\033(\"!$2");      // Select PS symbol set
     352           0 :       break;
     353             :     }
     354           0 :     cur_symbol_set = symbol_set;
     355             :   }
     356          12 :   if (env->size != cur_size) {
     357           0 :     if (!cur_font->is_scalable)
     358           0 :       lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size));
     359             :     else
     360           0 :       lbpprintf("\033[%d C", (int)((env->size * font::res) / 72));
     361           0 :     cur_size = env->size;
     362             :      // Update the line thickness if needed
     363           0 :     if (req_linethickness < 0 ) 
     364           0 :         set_line_thickness(req_linethickness,env);
     365             :   }
     366          12 :   if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) {
     367             :     // lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos);
     368           2 :     lbpmoveabs(env->hpos - 64, env->vpos - 64);
     369           2 :     cur_vpos = env->vpos;
     370           2 :     cur_hpos = env->hpos;
     371             :   }
     372          12 :   if ((ch & 0x7F) < 32)
     373           0 :     lbpputs("\033[1.v");
     374          12 :   lbpputc(ch);
     375          12 :   cur_hpos += w;
     376          12 : }
     377             : 
     378           0 : void lbp_printer::vdmstart()
     379             : {
     380             :   FILE *f;
     381             :   static int changed_origin = 0;
     382           0 :   errno = 0;
     383           0 :   f = tmpfile();
     384             :   // f = fopen("/tmp/gtmp","w+");
     385           0 :   if (0 /* nullptr */ == f)
     386           0 :     perror("Opening temporary file");
     387           0 :   vdminit(f);
     388           0 :   if (!changed_origin) {        // we should change the origin only one time
     389           0 :     changed_origin = 1;
     390           0 :     vdmorigin(-63, 0);
     391             :   }
     392           0 :   vdmlinewidth(line_thickness);
     393           0 : }
     394             : 
     395             : void
     396           0 : lbp_printer::vdmflush()
     397             : {
     398             :   char buffer[1024];
     399           0 :   int bytes_read = 1;
     400           0 :   vdmend();
     401           0 :   fflush(lbpoutput);
     402             :   /* let's copy the vdm code to the output */
     403           0 :   rewind(vdmoutput);
     404           0 :   do {
     405           0 :     bytes_read = fread(buffer, 1, sizeof buffer, vdmoutput);
     406           0 :     bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput);
     407           0 :   } while (bytes_read == sizeof buffer);
     408           0 :   fclose(vdmoutput);    // This will also delete the file,
     409             :                         // since it is created by tmpfile()
     410           0 :   vdmoutput = 0 /* nullptr */;
     411           0 : }
     412             : 
     413           0 : inline void lbp_printer::setfillmode(int mode)
     414             : {
     415           0 :   if (mode != fill_mode) {
     416           0 :     if (mode != 1)
     417           0 :       vdmsetfillmode(mode, 1, 0);
     418             :     else
     419             :       // To get black, we must use white inverted.
     420           0 :       vdmsetfillmode(mode, 1, 1);
     421             : 
     422           0 :     fill_mode = mode;
     423             :   }
     424           0 : }
     425             : 
     426           0 : inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p)
     427             : {
     428             :   int *points, i;
     429           0 :   points = new int[np + 2];
     430           0 :   points[0] = hpos;
     431           0 :   points[1] = vpos;
     432             :   // fprintf(stderr, "Polygon (%d,%d) ", points[0], points[1]);
     433           0 :   for (i = 0; i < np; i++)
     434           0 :     points[i + 2] = p[i];
     435             :   // for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]);
     436             :   // fprintf(stderr, "\n");
     437           0 :   vdmpolygon((np /2) + 1, points);
     438           0 : }
     439             : 
     440           0 : void lbp_printer::draw(int code, int *p, int np, const environment *env)
     441             : {
     442           0 :   if ((req_linethickness < 0 ) && (env->size != cur_size))
     443           0 :                 set_line_thickness(req_linethickness,env);
     444             : 
     445           0 :   switch (code) {
     446           0 :   case 't':
     447           0 :     if (np == 0)
     448           0 :       line_thickness = 1;
     449             :     else { // troff gratuitously adds an extra 0
     450           0 :       if (np != 1 && np != 2) {
     451           0 :         error("0 or 1 argument required for thickness");
     452           0 :         break;
     453             :       }
     454           0 :     set_line_thickness(p[0],env);
     455             :     }
     456           0 :     break;
     457           0 :   case 'l':     // Line
     458           0 :     if (np != 2) {
     459           0 :       error("2 arguments required for line");
     460           0 :       break;
     461             :     }
     462           0 :     if (!vdminited())
     463           0 :       vdmstart();
     464           0 :     vdmline(env->hpos, env->vpos, p[0], p[1]);
     465             : /*     fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n",
     466             :              env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],
     467             :              env->vpos -64 + p[1], env->size, line_thickness);*/
     468           0 :     break;
     469           0 :   case 'R':     // Rule
     470           0 :     if (np != 2) {
     471           0 :       error("2 arguments required for Rule");
     472           0 :       break;
     473             :     }
     474           0 :     if (vdminited()) {
     475           0 :       setfillmode(fill_pattern); // Solid Rule
     476           0 :       vdmrectangle(env->hpos, env->vpos, p[0], p[1]);
     477             :     }
     478             :     else {
     479           0 :       lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]);
     480           0 :       cur_vpos = p[1];
     481           0 :       cur_hpos = p[0];
     482             :     }
     483             :     // fprintf(stderr, "\nrule: thickness %d == %d\n",
     484             :     //         env->size, line_thickness);
     485           0 :     break;
     486           0 :   case 'P':     // Filled Polygon
     487           0 :     if (!vdminited())
     488           0 :       vdmstart();
     489           0 :     setfillmode(fill_pattern);
     490           0 :     polygon(env->hpos, env->vpos, np, p);
     491           0 :     break;
     492           0 :   case 'p':     // Empty Polygon
     493           0 :     if (!vdminited())
     494           0 :       vdmstart();
     495           0 :     setfillmode(0);
     496           0 :     polygon(env->hpos, env->vpos, np, p);
     497           0 :     break;
     498           0 :   case 'C':     // Filled Circle
     499           0 :     if (!vdminited())
     500           0 :       vdmstart();
     501             :     // fprintf(stderr, "Circle (%d,%d) Fill %d\n",
     502             :     //         env->hpos, env->vpos, fill_pattern);
     503           0 :     setfillmode(fill_pattern);
     504           0 :     vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
     505           0 :     break;
     506           0 :   case 'c':     // Empty Circle
     507           0 :     if (!vdminited())
     508           0 :       vdmstart();
     509           0 :     setfillmode(0);
     510           0 :     vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
     511           0 :     break;
     512           0 :   case 'E':     // Filled Ellipse
     513           0 :     if (!vdminited())
     514           0 :       vdmstart();
     515           0 :     setfillmode(fill_pattern);
     516           0 :     vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
     517           0 :     break;
     518           0 :   case 'e':      // Empty Ellipse
     519           0 :     if (!vdminited())
     520           0 :       vdmstart();
     521           0 :     setfillmode(0);
     522           0 :     vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
     523           0 :     break;
     524           0 :   case 'a':     // Arc
     525           0 :     if (!vdminited())
     526           0 :       vdmstart();
     527           0 :     setfillmode(0);
     528             :     // VDM draws arcs clockwise and pic counterclockwise
     529             :     // We must compensate for that, exchanging the starting and
     530             :     // ending points
     531           0 :     vdmvarc(env->hpos + p[0], env->vpos+p[1],
     532           0 :             int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))),
     533           0 :             p[2], p[3],
     534           0 :             (-p[0]), (-p[1]), 1, 2);
     535           0 :     break;
     536           0 :   case '~':     // Spline
     537           0 :     if (!vdminited())
     538           0 :       vdmstart();
     539           0 :     setfillmode(0);
     540           0 :     vdmspline(np/2, env->hpos, env->vpos, p);
     541           0 :     break;
     542           0 :   case 'f':
     543           0 :     if (np != 1 && np != 2) {
     544           0 :       error("1 argument required for fill");
     545           0 :       break;
     546             :     }
     547             :     // fprintf(stderr, "Fill %d\n", p[0]);
     548           0 :     if ((p[0] == 1) || (p[0] >= 1000)) { // Black
     549           0 :       fill_pattern = 1;
     550           0 :       break;
     551             :     }
     552           0 :     if (p[0] == 0) { // White
     553           0 :       fill_pattern = 0;
     554           0 :       break;
     555             :     }
     556           0 :     if ((p[0] > 1) && (p[0] < 1000))
     557             :       {
     558           0 :         if (p[0] >= 990)  fill_pattern = -23;
     559           0 :         else if (p[0] >= 700)  fill_pattern = -28;
     560           0 :         else if (p[0] >= 500)  fill_pattern = -27;
     561           0 :         else if (p[0] >= 400)  fill_pattern = -26;
     562           0 :         else if (p[0] >= 300)  fill_pattern = -25;
     563           0 :         else if (p[0] >= 200)  fill_pattern = -22;
     564           0 :         else if (p[0] >= 100)  fill_pattern = -24;
     565           0 :         else fill_pattern = -21;
     566             :       }
     567           0 :     break;
     568           0 :   case 'F':
     569             :     // not implemented yet
     570           0 :     break;
     571           0 :   default:
     572           0 :     error("unrecognised drawing command '%1'", char(code));
     573           0 :     break;
     574             :   }
     575           0 :   return;
     576             : }
     577             : 
     578           1 : font *lbp_printer::make_font(const char *nm)
     579             : {
     580           1 :   return lbp_font::load_lbp_font(nm);
     581             : }
     582             : 
     583           1 : printer *make_printer()
     584             : {
     585           1 :   return new lbp_printer(user_papersize, user_paperwidth, user_paperlength);
     586             : }
     587             : 
     588             : static struct lbp_paper_size {
     589             :   const char *name;
     590             :   int code;
     591             : } lbp_papersizes[] =
     592             :   {{ "A4", 14 },
     593             :    { "letter", 30 },
     594             :    { "legal", 32 },
     595             :    { "executive", 40 },
     596             :   };
     597             : 
     598           1 : static int set_papersize(const char *paperformat)
     599             : {
     600             :   unsigned int i;
     601             :   // First, test for a standard (i.e. supported directly by the printer)
     602             :   // paper format.
     603           2 :   for (i = 0 ; i < countof(lbp_papersizes); i++)
     604             :   {
     605           2 :     if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0)
     606           1 :       return lbp_papersizes[i].code;
     607             :   }
     608             :   // Otherwise, we assume a custom paper format.
     609           0 :   return 82; // XXX: magic number
     610             : }
     611             : 
     612           3 : static void handle_unknown_desc_command(const char *command, const char *arg,
     613             :                                         const char *fn, int lineno)
     614             : {
     615             :   // orientation command
     616           3 :   if (strcasecmp(command, "orientation") == 0) {
     617             :     // We give priority to command-line options
     618           1 :     if (orientation > 0)
     619           0 :       return;
     620           1 :     if (arg == 0)
     621           0 :       error_with_file_and_line(fn, lineno,
     622             :                                "'orientation' command requires an argument");
     623             :     else {
     624           1 :       if (strcasecmp(arg, "portrait") == 0)
     625           1 :         orientation = 0;
     626             :       else {
     627           0 :         if (strcasecmp(arg, "landscape") == 0)
     628           0 :           orientation = 1;
     629             :         else
     630           0 :           error_with_file_and_line(fn, lineno,
     631             :                                    "invalid argument to 'orientation' command");
     632             :       }
     633             :     }
     634             :   }
     635             : }
     636             : 
     637             : static struct option long_options[] = {
     638             :   { "orientation", required_argument, 0 /* nullptr */, 'o' },
     639             :   { "version", no_argument, 0 /* nullptr */, 'v' },
     640             :   { "copies", required_argument, 0 /* nullptr */, 'c' },
     641             :   { "landscape", no_argument, 0 /* nullptr */, 'l' },
     642             :   { "papersize", required_argument, 0 /* nullptr */, 'p' },
     643             :   { "linewidth", required_argument, 0 /* nullptr */, 'w' },
     644             :   { "fontdir", required_argument, 0 /* nullptr */, 'F' },
     645             :   { "help", no_argument, 0 /* nullptr */, 'h' },
     646             :   { 0 /* nullptr */, 0, 0 /* nullptr */, 0 }
     647             : };
     648             : 
     649           0 : static void usage(FILE *stream)
     650             : {
     651           0 :   fprintf(stream,
     652             : "usage: %s [-l] [-c num-copies] [-F font-directory] [-o orientation]"
     653             : " [-p paper-format] [-w width] [file ...]\n"
     654             : "usage: %s {-v | --version}\n"
     655             : "usage: %s {-h | --help}\n",
     656             :           program_name, program_name, program_name);
     657           0 :   if (stdout == stream)
     658           0 :     fputs("\n"
     659             : "Translate the output of troff(1) into a CaPSL and VDM format suitable"
     660             : "\n"
     661             : "for Canon LBP-4 and LBP-8 printers.  See the grolbp(1) manual page.\n",
     662             :           stream);
     663           0 : }
     664             : 
     665           1 : int main(int argc, char **argv)
     666             : {
     667           1 :   if (0 /* nullptr */ == program_name)
     668           1 :     program_name = strsave(argv[0]);
     669           1 :   font::set_unknown_desc_command_handler(handle_unknown_desc_command);
     670             :   // command line parsing
     671             :   int c;
     672           1 :   while ((c = getopt_long(argc, argv, ":c:F:hI:lo:p:vw:", long_options,
     673             :                           0 /* nullptr */))
     674           1 :          != EOF)
     675           0 :     switch (c) {
     676           0 :     case 'F':
     677           0 :       font::command_line_font_dir(optarg);
     678           0 :       break;
     679           0 :     case 'I':
     680             :       // ignore include path arguments
     681           0 :       break;
     682           0 :     case 'p':
     683             :       {
     684             :         const char *s;
     685           0 :         if (!font::scan_papersize(optarg, &s,
     686             :                                   &user_paperlength, &user_paperwidth))
     687           0 :           error("ignoring invalid paper format '%1'", optarg);
     688             :         else
     689           0 :           user_papersize = set_papersize(s);
     690           0 :         break;
     691             :       }
     692           0 :     case 'l':
     693           0 :       orientation = 1;
     694           0 :       break;
     695           0 :     case 'v':
     696           0 :       printf("GNU grolbp (groff) version %s\n", Version_string);
     697           0 :       exit(EXIT_SUCCESS);
     698             :       break;
     699           0 :     case 'o':
     700           0 :       if (strcasecmp(optarg, "portrait") == 0)
     701           0 :         orientation = 0;
     702             :       else {
     703           0 :         if (strcasecmp(optarg, "landscape") == 0)
     704           0 :           orientation = 1;
     705             :         else
     706           0 :           error("unknown orientation '%1'", optarg);
     707             :       }
     708           0 :       break;
     709           0 :     case 'c':
     710             :       {
     711             :         char *ptr;
     712           0 :         long n = strtol(optarg, &ptr, 10);
     713           0 :         if (ptr == optarg)
     714           0 :           error("argument for -c must be a positive integer");
     715           0 :         else if (n <= 0 || n > 32767)
     716           0 :           error("out of range argument for -c");
     717             :         else
     718           0 :           ncopies = unsigned(n);
     719           0 :         break;
     720             :       }
     721           0 :     case 'w':
     722             :       {
     723             :         char *ptr;
     724           0 :         errno = 0;
     725           0 :         long n = strtol(optarg, &ptr, 10);
     726           0 :         if (ptr == optarg)
     727           0 :           error("argument for -w must be a non-negative integer");
     728           0 :         else if (errno == ERANGE || n < 0 || n > INT_MAX)
     729           0 :           error("out of range argument for -w");
     730             :         else
     731           0 :           linewidth_factor = int(n);
     732           0 :         break;
     733             :       }
     734           0 :     case 'h':
     735           0 :       usage(stdout);
     736           0 :       exit(EXIT_SUCCESS);
     737             :       break;
     738           0 :     case '?':
     739           0 :       if (optopt != 0)
     740           0 :         error("unrecognized command-line option '%1'", char(optopt));
     741             :       else
     742           0 :         error("unrecognized command-line option '%1'",
     743           0 :               argv[(optind - 1)]);
     744           0 :       usage(stderr);
     745           0 :       exit(2);
     746             :       break;
     747           0 :     case ':':
     748           0 :       error("command-line option '%1' requires an argument",
     749           0 :             char(optopt));
     750           0 :       usage(stderr);
     751           0 :       exit(2);
     752             :       break;
     753           0 :     default:
     754           0 :       assert(0 == "unhandled getopt_long return value");
     755             :     }
     756           1 :   if (optind >= argc)
     757           1 :     do_file("-");
     758           1 :   while (optind < argc)
     759           0 :     do_file(argv[optind++]);
     760           1 :   if (lbpoutput)
     761           1 :     lbpputs("\033c\033<");
     762           1 :   return 0;
     763             : }
     764             : 
     765             : // Local Variables:
     766             : // fill-column: 72
     767             : // mode: C++
     768             : // End:
     769             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14