-
Notifications
You must be signed in to change notification settings - Fork 56
/
Copy pathmain.c
231 lines (184 loc) · 6.59 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
#include <limits.h>
#include <alloca.h>
#include <err.h>
#include "lottypes.h"
#include "lotdefs.h"
#include "lotfuncs.h"
#include "atfuncs.h"
extern int __unix_main(int argc, char **argv, char **envp);
extern int setchrclass(const char *class);
static void canonicalize_auto_worksheet(int *argc, char **argv, const char *wkspath)
{
static char autofile[PATH_MAX];
if (realpath(wkspath, autofile) == NULL) {
warn("Failed to canonicalize worksheet path.");
return;
}
if (access(autofile, F_OK) != 0) {
warn("The worksheet specified does not exist.");
return;
}
// Okay, replace it with a canonical path!
argv[(*argc)++] = "-w";
argv[(*argc)++] = autofile;
}
#define MAX_MACRO 64
// This is used to evaluate a macro on the commandline.
static int macro_cell_num = -1;
static int macro_cell_cnt;
static int macro_run_signal;
static const char *macro_cell_text[MAX_MACRO];
static const char *playback_macro_text(int16_t n)
{
// n is set when 123 wants to advance to the next cell, so
// we just remove the contents. Note that some macro commands
// "advance" the macro cell automatically, like {OPEN}, {WRITE},
// {IF}.
macro_cell_num += n;
if (macro_cell_num < MAX_MACRO) {
return macro_cell_text[macro_cell_num];
}
return NULL;
}
// This is called when 123 is ready to receive input, we can check
// if we have any jobs we want to do.
int ready_to_read(int fd)
{
static struct MACXRTNS macro = {
.get_mac_text = playback_macro_text,
};
// Only check for macro jobs in READY mode.
if (!in_rdy_mode())
return 0;
// If we have a macro to evaluate, submit it here.
if (macro_cell_cnt && macro_cell_num == -1) {
// Start at the first cell, this allows multiple cells to be
// used on the commandline, -e a -e b -e c, and so on.
macro_cell_num = 0;
// Submit it.
macro_buff_run(¯o);
}
// If a signal handler macro has been triggered, run it here.
if (macro_run_signal) {
// Mark this signal processed.
macro_run_signal = 0;
// Trigger a {REFRESH} to leave the idle loop.
kfqueue_submit_kfun(6244);
// Invoke the macro \1.
macro_key_run(24);
}
return 0;
}
// This signal handler triggers the use of macro \1.
static void macro_signal(int n)
{
macro_run_signal++;
}
// This is an atexit() routine that is called after 1-2-3 prints
// it's own help, so we can append any flags we support.
static void print_help()
{
static int printed;
// This can happen if multiple invalid options are passed.
if (printed++)
return;
printf(" -b to enable banner\n");
printf(" -u to disable undo support\n");
printf(" -e macro to evaluate a macro\n");
}
static const char *optstring = ":f:c:k:np:w:hbue:";
int main(int argc, char **argv, char **envp)
{
char **lotargv;
char dumpfile[64];
int lotargc;
int opt;
// The location of terminfo definitions.
setenv("TERMINFO", "/usr/share/terminfo/", 0);
// This controls how long lotus waits to see if an escape character is part
// of a sequence or on it's own. Increase it if escape characters are not
// being recognized properly, perhaps you're using 123 over a very slow
// connection. If you set it too high, lotus might seem to pause when
// pressing the Esc key.
setenv("LOTUS_ESCAPE_TIMEOUT", "1", 0);
// This changes how some timeouts work, is this still necessary?
setenv("LOTUS_OS_ENV", "systemv", 0);
// If you send lotus a SIGUSR1 (e.g. kill -USR1 $(pidof 123)), it will save
// a copy of the screen to the specified file. You can use this for automation
// or grabbing some figures over ssh from a session you left running.
snprintf(dumpfile, sizeof dumpfile, "123screen.%d.txt", getpid());
setenv("LOTUS_SCREEN_DUMP", dumpfile, 0);
setchrclass("ascii");
// Setup a signal handler for SIGUSR2
signal(SIGUSR2, macro_signal);
// Disable the banner by default, it can be re-enabled via -b.
banner_printed = true;
// Enable undo by default, you can disable it via -u.
reset_undo(1);
// No need to close the printer driver, it is currently a noop.
need_to_close = false;
// Configure our @functions here.
init_at_funcs();
// We always need at least two entries, for argv[0] and a terminator.
lotargc = 2;
// We need to do a first pass through the options to see how many there
// are.
while ((opt = getopt(argc, argv, optstring)) != -1)
lotargc++;
// If there was a non-option parameter, we will inject a synthetic
// parameter.
if (argv[optind] != NULL)
lotargc += 2;
// Allocate the argument vector we're going to pass through to lotus.
lotargv = alloca(lotargc * sizeof(*argv));
// Now reset and copy the options over.
lotargc = 0;
// Reset optind to restart getopt();
optind = 1;
// The first argument is the same.
lotargv[lotargc++] = argv[0];
// This time we copy options over.
while ((opt = getopt(argc, argv, optstring)) != -1) {
// Here 'continue' means don't pass this option to Lotus and 'break'
// means pass it through verbatim.
switch (opt) {
case 'b': banner_printed = false;
continue;
case 'u': undo_off_cmd();
continue;
case 'e': if (macro_cell_cnt < MAX_MACRO) {
macro_cell_text[macro_cell_cnt++] = optarg;
}
continue;
case '?':
case 'h': atexit(print_help);
break;
}
// If we reach here, we want to pass this option through to
// Lotus verbatim.
lotargv[lotargc] = alloca(3);
lotargv[lotargc][0] = '-';
lotargv[lotargc][1] = opt;
lotargv[lotargc][2] = 0;
lotargc++;
// There may also be an argument.
if (optarg)
lotargv[lotargc++] = optarg;
}
// Lotus does not accept any non-options arguments. If you do provide
// one, we will try to translate it into a worksheet name.
if (argv[optind] != NULL) {
canonicalize_auto_worksheet(&lotargc, lotargv, argv[optind]);
}
// Always add a NULL terminator
lotargv[lotargc] = NULL;
return __unix_main(lotargc, lotargv, envp);
}