dir: support text direction with .>>, .<<, \> and \<
[neatroff.git] / roff.c
blob6a1e16892640bfca31b56aea8b0633a470afd30d
1 /*
2 * NEATROFF TYPESETTING SYSTEM
4 * Copyright (C) 2012-2016 Ali Gholami Rudi <ali at rudi dot ir>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include "roff.h"
24 void errmsg(char *fmt, ...)
26 va_list ap;
27 va_start(ap, fmt);
28 vfprintf(stderr, fmt, ap);
29 va_end(ap);
32 void errdie(char *msg)
34 fprintf(stderr, msg);
35 exit(1);
38 void *mextend(void *old, long oldsz, long newsz, int memsz)
40 void *new = xmalloc(newsz * memsz);
41 memcpy(new, old, oldsz * memsz);
42 memset(new + oldsz * memsz, 0, (newsz - oldsz) * memsz);
43 free(old);
44 return new;
47 void *xmalloc(long len)
49 void *m = malloc(len);
50 if (!m)
51 errdie("neatroff: malloc() failed\n");
52 return m;
55 static int xopens(char *path)
57 FILE *filp = fopen(path, "r");
58 if (filp)
59 fclose(filp);
60 return filp != NULL;
63 /* parse the argument of -r and -d options */
64 static void cmddef(char *arg, int *reg, char **def)
66 char regname[RNLEN] = "";
67 char *eq = strchr(arg, '=');
68 memcpy(regname, arg, eq ? MIN(RNLEN - 1, eq - arg) : 1);
69 *reg = map(regname);
70 *def = eq ? eq + 1 : arg + 1;
73 /* find the macro specified with -m option */
74 static int cmdmac(char *dir, char *arg)
76 char path[PATHLEN];
77 snprintf(path, sizeof(path), "%s/%s.tmac", dir, arg);
78 if (!xopens(path))
79 snprintf(path, sizeof(path), "%s/tmac.%s", dir, arg);
80 if (!xopens(path))
81 snprintf(path, sizeof(path), "%s/%s", dir, arg);
82 if (!xopens(path))
83 return 1;
84 in_queue(path);
85 return 0;
88 static char *usage =
89 "Usage: neatroff [options] input\n\n"
90 "Options:\n"
91 " -mx \tinclude macro x\n"
92 " -rx=y \tset number register x to y\n"
93 " -dx=y \tdefine string register x as y\n"
94 " -C \tenable compatibility mode\n"
95 " -Tdev \tset output device\n"
96 " -Fdir \tset font directory (" TROFFFDIR ")\n"
97 " -Mdir \tset macro directory (" TROFFMDIR ")\n";
99 int main(int argc, char **argv)
101 char *fontdir = TROFFFDIR;
102 char *macrodir = TROFFMDIR;
103 char *mac, *def, *dev = "utf";
104 int reg, ret;
105 int i;
106 for (i = 1; i < argc; i++) {
107 if (argv[i][0] != '-' || !argv[i][1])
108 break;
109 switch (argv[i][1]) {
110 case 'C':
111 n_cp = 1;
112 break;
113 case 'm':
114 mac = argv[i] + 2;
115 if (strchr(mac, '/') || (cmdmac(macrodir, mac) && cmdmac(".", mac)))
116 in_queue(mac);
117 break;
118 case 'r':
119 cmddef(argv[i][2] ? argv[i] + 2 : argv[++i], &reg, &def);
120 num_set(reg, eval_re(def, num_get(reg), 'u'));
121 break;
122 case 'd':
123 cmddef(argv[i][2] ? argv[i] + 2 : argv[++i], &reg, &def);
124 str_set(reg, def);
125 break;
126 case 'F':
127 fontdir = argv[i][2] ? argv[i] + 2 : argv[++i];
128 break;
129 case 'M':
130 macrodir = argv[i][2] ? argv[i] + 2 : argv[++i];
131 break;
132 case 'T':
133 dev = argv[i][2] ? argv[i] + 2 : argv[++i];
134 break;
135 default:
136 printf("%s", usage);
137 return 0;
140 if (dev_open(fontdir, dev)) {
141 fprintf(stderr, "neatroff: cannot open device %s\n", dev);
142 return 1;
144 hyph_init();
145 env_init();
146 tr_init();
147 if (i == argc)
148 in_queue(NULL); /* reading from standard input */
149 for (; i < argc; i++)
150 in_queue(!strcmp("-", argv[i]) ? NULL : argv[i]);
151 out("s%d\n", n_s);
152 out("f%d\n", n_f);
153 ret = render();
154 out("V%d\n", n_p);
155 hyph_done();
156 tr_done();
157 env_done();
158 dev_close();
159 map_done();
160 dir_done();
161 return ret;