Imported Upstream version 1.23.0
[platform/upstream/groff.git] / src / utils / addftinfo / addftinfo.cpp
1 /* Copyright (C) 1989-2020 Free Software Foundation, Inc.
2      Written by James Clark (jjc@jclark.com)
3
4 This file is part of groff.
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 #include "lib.h"
20
21 #include <ctype.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include "errarg.h"
25 #include "error.h"
26 #include "stringclass.h"
27 #include "cset.h"
28 #include "guess.h"
29
30 extern "C" const char *Version_string;
31
32 static void usage(FILE *stream);
33 static void usage();
34 static void usage(const char *problem);
35 static void version();
36 static void convert_font(const font_params &, FILE *, FILE *);
37
38 typedef int font_params::*param_t;
39
40 static struct {
41   const char *name;
42   param_t par;
43 } param_table[] = {
44   { "asc-height", &font_params::asc_height },
45   { "body-depth", &font_params::body_depth },
46   { "body-height", &font_params::body_height },
47   { "cap-height", &font_params::cap_height },
48   { "comma-depth", &font_params::comma_depth },
49   { "desc-depth", &font_params::desc_depth },
50   { "fig-height", &font_params::fig_height },
51   { "x-height", &font_params::x_height },
52 };
53
54 // These are all in thousandths of an em.
55 // These values are correct for PostScript Times Roman.
56
57 #define DEFAULT_X_HEIGHT 448
58 #define DEFAULT_FIG_HEIGHT 676
59 #define DEFAULT_ASC_HEIGHT 682
60 #define DEFAULT_BODY_HEIGHT 676
61 #define DEFAULT_CAP_HEIGHT 662
62 #define DEFAULT_COMMA_DEPTH 143
63 #define DEFAULT_DESC_DEPTH 217
64 #define DEFAULT_BODY_DEPTH 177
65
66 int main(int argc, char **argv)
67 {
68   program_name = argv[0];
69   int i;
70   for (i = 1; i < argc; i++) {
71     if (!strcmp(argv[i], "-v") || !strcmp(argv[i],"--version"))
72       version();
73     if (!strcmp(argv[i],"--help")) {
74       usage(stdout);
75       exit(0);
76     }
77   }
78   if (argc < 4)
79     usage("insufficient arguments");
80   /* The next couple of usage() calls cannot provide a meaningful
81      diagnostic because we don't know whether sscanf() failed on a
82      required parameter or an option.  A refactor could fix this. */
83   int resolution;
84   if (sscanf(argv[argc-3], "%d", &resolution) != 1)
85     usage();
86   if (resolution <= 0)
87     fatal("resolution must be positive");
88   int unitwidth;
89   if (sscanf(argv[argc-2], "%d", &unitwidth) != 1)
90     usage();
91   if (unitwidth <= 0)
92     fatal("unit width must be positive");
93   font_params param;
94   const char *font = argv[argc-1];
95   param.italic = (font[0] != '\0' && strchr(font, '\0')[-1] == 'I');
96   param.em = (resolution*unitwidth)/72;
97   param.x_height = DEFAULT_X_HEIGHT;
98   param.fig_height = DEFAULT_FIG_HEIGHT;
99   param.asc_height = DEFAULT_ASC_HEIGHT;
100   param.body_height = DEFAULT_BODY_HEIGHT;
101   param.cap_height = DEFAULT_CAP_HEIGHT;
102   param.comma_depth = DEFAULT_COMMA_DEPTH;
103   param.desc_depth = DEFAULT_DESC_DEPTH;
104   param.body_depth = DEFAULT_BODY_DEPTH;
105   for (i = 1; i < argc && argv[i][0] == '-'; i++) {
106     if (argv[i][1] == '-' && argv[i][2] == '\0') {
107       i++;
108       break;
109     }
110     if (i + 1 >= argc)
111       usage("option requires argument");
112     size_t j;
113     for (j = 0;; j++) {
114       if (j >= sizeof(param_table)/sizeof(param_table[0]))
115         fatal("parameter '%1' not recognized", argv[i] + 1);
116       if (strcmp(param_table[j].name, argv[i] + 1) == 0)
117         break;
118     }
119     if (sscanf(argv[i+1], "%d", &(param.*(param_table[j].par))) != 1)
120       fatal("invalid option argument '%1'", argv[i+1]);
121     i++;
122   }
123   if (argc - i != 3)
124     usage("insufficient arguments");
125   errno = 0;
126   FILE *infp = fopen(font, "r");
127   if (infp == 0)
128     fatal("can't open '%1': %2", font, strerror(errno));
129   convert_font(param, infp, stdout);
130   return 0;
131 }
132
133 static void usage(FILE *stream)
134 {
135   fprintf(stream, "usage: %s", program_name);
136   size_t len = sizeof(param_table)/sizeof(param_table[0]);
137   for (size_t i = 0; i < len; i++)
138     fprintf(stream, " [-%s n]", param_table[i].name);
139   fputs(" resolution unit-width font\n", stream);
140   fprintf(stream, "usage: %s {-v | --version}\n"
141           "usage: %s --help\n", program_name, program_name);
142 }
143
144 static void usage()
145 {
146   usage(stderr);
147   exit(1);
148 }
149
150 static void usage(const char *problem)
151 {
152   error("%1", problem);
153   usage();
154 }
155
156 static void version()
157 {
158   printf("GNU addftinfo (groff) version %s\n", Version_string);
159   exit(0);
160 }
161
162 static int get_line(FILE *fp, string *p)
163 {
164   int c;
165   p->clear();
166   while ((c = getc(fp)) != EOF) {
167     *p += char(c);
168     if (c == '\n')
169       break;
170   }
171   return p->length() > 0;
172 }
173
174 static void convert_font(const font_params &param, FILE *infp,
175                          FILE *outfp)
176 {
177   string s;
178   while (get_line(infp, &s)) {
179     put_string(s, outfp);
180     if (s.length() >= 8
181         && strncmp(&s[0], "charset", 7))
182       break;
183   }
184   while (get_line(infp, &s)) {
185     s += '\0';
186     string name;
187     const char *p = s.contents();
188     while (csspace(*p))
189       p++;
190     while (*p != '\0' && !csspace(*p))
191       name += *p++;
192     while (csspace(*p))
193       p++;
194     for (const char *q = s.contents(); q < p; q++)
195       putc(*q, outfp);
196     char *next;
197     char_metric metric;
198     metric.width = (int)strtol(p, &next, 10);
199     if (next != p) {
200       printf("%d", metric.width);
201       p = next;
202       metric.type = (int)strtol(p, &next, 10);
203       if (next != p) {
204         name += '\0';
205         guess(name.contents(), param, &metric);
206         if (metric.sk == 0) {
207           if (metric.left_ic == 0) {
208             if (metric.ic == 0) {
209               if (metric.depth == 0) {
210                 if (metric.height != 0)
211                   printf(",%d", metric.height);
212               }
213               else
214                 printf(",%d,%d", metric.height, metric.depth);
215             }
216             else
217               printf(",%d,%d,%d", metric.height, metric.depth,
218                      metric.ic);
219           }
220           else
221             printf(",%d,%d,%d,%d", metric.height, metric.depth,
222                    metric.ic, metric.left_ic);
223         }
224         else
225           printf(",%d,%d,%d,%d,%d", metric.height, metric.depth,
226                  metric.ic, metric.left_ic, metric.sk);
227       }
228     }
229     fputs(p, outfp);
230   }
231 }
232
233 // Local Variables:
234 // fill-column: 72
235 // mode: C++
236 // End:
237 // vim: set cindent noexpandtab shiftwidth=2 textwidth=72: