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