fmt: new hyphenation support with penalties
[neatroff.git] / cp.c
blob8fb34cfea2e9fb9753e4b7def50db93ca4e8ec9a
1 /* copy-mode character interpretation */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include "roff.h"
6 static int cp_nblk; /* input block depth (text in \{ and \}) */
7 static int cp_sblk[NIES]; /* skip \} escape at this depth, if set */
8 static int cp_widreq = 1; /* inline \w requests */
10 static void cparg(char *d)
12 int c = cp_next();
13 int i = 0;
14 if (c == '(') {
15 d[i++] = cp_next();
16 d[i++] = cp_next();
17 } else if (!n_cp && c == '[') {
18 c = cp_next();
19 while (i < NMLEN - 1 && c >= 0 && c != ']') {
20 d[i++] = c;
21 c = cp_next();
23 } else {
24 d[i++] = c;
26 d[i] = '\0';
29 static int regid(void)
31 char regname[NMLEN];
32 cparg(regname);
33 return map(regname);
36 static void cp_num(void)
38 int id;
39 int c = cp_next();
40 if (c != '-' && c != '+')
41 cp_back(c);
42 id = regid();
43 if (c == '-' || c == '+')
44 num_get(id, c == '+' ? 1 : -1);
45 if (num_str(id))
46 in_push(num_str(id), NULL);
49 static void cp_str(void)
51 char *buf = str_get(regid());
52 if (buf)
53 in_push(buf, NULL);
56 static void cp_numfmt(void)
58 in_push(num_getfmt(regid()), NULL);
61 static void cp_arg(void)
63 char argname[NMLEN];
64 char *arg = NULL;
65 int argnum;
66 cparg(argname);
67 argnum = atoi(argname);
68 if (argnum > 0 && argnum < NARGS + 1)
69 arg = in_arg(argnum);
70 if (arg)
71 in_push(arg, NULL);
74 static void cp_width(void)
76 char wid[16];
77 sprintf(wid, "%d", ren_wid(cp_next, cp_back));
78 in_push(wid, NULL);
81 static int cp_raw(void)
83 int c;
84 if (in_top() >= 0)
85 return in_next();
86 do {
87 c = in_next();
88 } while (c == c_ni);
89 if (c == c_ec) {
90 do {
91 c = in_next();
92 } while (c == c_ni);
93 if (c == '\n')
94 return cp_raw();
95 if (c == '.')
96 return '.';
97 if (c == '\\') {
98 in_back('\\');
99 return c_ni;
101 if (c == 't') {
102 in_back('\t');
103 return c_ni;
105 if (c == 'a') {
106 in_back('\x01');
107 return c_ni;
109 if (c == '{' && cp_nblk < LEN(cp_sblk))
110 cp_sblk[cp_nblk++] = 0;
111 if (c == '}' && cp_nblk > 0)
112 if (cp_sblk[--cp_nblk])
113 return cp_raw();
114 in_back(c);
115 return c_ec;
117 return c;
120 int cp_next(void)
122 int c;
123 if (in_top() >= 0)
124 return in_next();
125 c = cp_raw();
126 if (c == c_ec) {
127 c = cp_raw();
128 if (c == '"') {
129 while (c >= 0 && c != '\n')
130 c = cp_raw();
131 } else if (c == 'w' && cp_widreq) {
132 cp_width();
133 c = cp_next();
134 } else if (c == 'n') {
135 cp_num();
136 c = cp_next();
137 } else if (c == '*') {
138 cp_str();
139 c = cp_next();
140 } else if (c == 'g') {
141 cp_numfmt();
142 c = cp_next();
143 } else if (c == '$') {
144 cp_arg();
145 c = cp_next();
146 } else {
147 cp_back(c);
148 c = c_ec;
151 return c;
154 void cp_blk(int skip)
156 int c;
157 int nblk = cp_nblk;
158 do {
159 c = skip ? cp_raw() : cp_next();
160 } while (c == ' ' || c == '\t');
161 if (skip) {
162 while (c >= 0 && (c != '\n' || cp_nblk > nblk))
163 c = cp_raw();
164 } else {
165 if (c == c_ec && in_top() == '{') { /* a troff \{ \} block */
166 cp_sblk[nblk] = 1;
167 cp_raw();
168 } else {
169 cp_back(c);
174 void cp_wid(int enable)
176 cp_widreq = enable;