002
2021-06-15
op
* Much of the design is taken from doas (parse.y rev 1.29)
004
2021-06-15
op
* Copyright (c) 2021 Omar Polo <op@omarpolo.com>
005
2021-06-15
op
* Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
007
2021-06-15
op
* Permission to use, copy, modify, and distribute this software for any
008
2021-06-15
op
* purpose with or without fee is hereby granted, provided that the above
009
2021-06-15
op
* copyright notice and this permission notice appear in all copies.
011
2021-06-15
op
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
012
2021-06-15
op
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
013
2021-06-15
op
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
014
2021-06-15
op
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
015
2021-06-15
op
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
016
2021-06-15
op
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
017
2021-06-15
op
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
023
2021-11-05
op
#include "keymap.h"
024
2021-06-15
op
#include "telescope.h"
025
2022-01-11
op
#include "utils.h"
027
2021-06-21
op
#include <assert.h>
028
2021-06-15
op
#include <ctype.h>
029
2021-06-15
op
#include <limits.h>
030
2021-06-21
op
#include <ncurses.h>
031
2021-06-15
op
#include <stdarg.h>
032
2021-06-15
op
#include <stdio.h>
033
2021-06-15
op
#include <stdlib.h>
034
2021-06-15
op
#include <string.h>
036
2021-06-15
op
typedef struct {
038
2021-06-15
op
char *str;
041
2021-06-15
op
int lineno;
042
2021-06-15
op
int colno;
043
2021-06-15
op
} yystype;
044
2021-06-15
op
#define YYSTYPE yystype
046
2021-06-15
op
static char *current_style;
047
2021-06-21
op
static int color_type;
049
2021-06-15
op
static const char *path;
051
2021-06-15
op
FILE *yyfp;
053
2021-06-15
op
int parse_errors = 0;
055
2021-06-15
op
static void yyerror(const char *, ...);
056
2021-06-15
op
static int yylex(void);
057
2021-06-21
op
static void setprfx(const char *, const char *);
058
2021-06-19
op
static void setvari(char *, int);
059
2021-06-19
op
static void setvars(char *, char *);
060
2021-06-21
op
static int colorname(const char *);
061
2021-06-21
op
static void setcolor(const char *, const char *, const char *);
062
2021-08-26
op
static int attrname(const char *);
063
2021-06-22
op
static void setattr(char *, char *, char *);
064
2021-06-23
op
static void add_proxy(char *, char *);
065
2021-06-25
op
static void bindkey(const char *, const char *, const char *);
066
2021-07-15
op
static void do_parseconfig(const char *, int);
070
2021-11-03
op
%token ATTR
071
2021-11-03
op
%token BIND BG
072
2021-11-03
op
%token CONT
074
2021-11-03
op
%token PRFX PROXY
075
2021-11-03
op
%token SET STYLE
076
2021-11-03
op
%token UNBIND
077
2021-11-03
op
%token VIA
079
2021-11-03
op
%token <str> STRING
080
2021-11-03
op
%token <num> NUMBER
084
2021-06-15
op
grammar : /* empty */
085
2021-06-15
op
| grammar '\n'
086
2021-06-15
op
| grammar rule '\n'
087
2021-06-15
op
| error '\n'
090
2021-06-15
op
rule : set
091
2021-06-21
op
| style {
092
2021-06-21
op
free(current_style);
093
2021-06-21
op
current_style = NULL;
100
2021-11-03
op
set : SET STRING '=' STRING { setvars($2, $4); }
101
2021-11-03
op
| SET STRING '=' NUMBER { setvari($2, $4); }
104
2021-11-03
op
style : STYLE STRING { current_style = $2; } stylespec ;
105
2021-08-30
op
stylespec : styleopt | '{' optnl styleopts '}' ;
107
2021-06-15
op
styleopts : /* empty */
108
2021-07-09
op
| styleopts styleopt optnl
111
2021-11-03
op
styleopt : PRFX STRING { setprfx($2, $2); }
112
2021-11-03
op
| PRFX STRING STRING { setprfx($2, $3); }
113
2021-11-03
op
| BG { color_type = BG; } colorspec
114
2021-11-03
op
| FG { color_type = FG; } colorspec
115
2021-11-03
op
| ATTR attr
118
2021-11-03
op
colorspec : STRING { setcolor($1, $1, $1); free($1); }
119
2021-11-03
op
| STRING STRING { setcolor($1, $2, $1); free($1); free($2); }
120
2021-11-03
op
| STRING STRING STRING { setcolor($1, $2, $3); free($1); free($2); free($3); }
123
2021-11-03
op
attr : STRING { setattr($1, $1, $1); free($1); }
124
2021-11-03
op
| STRING STRING { setattr($1, $2, $1); free($1); free($2); }
125
2021-11-03
op
| STRING STRING STRING { setattr($1, $2, $3); free($1); free($2); free($3); }
128
2021-11-03
op
bind : BIND STRING STRING STRING { bindkey($2, $3, $4); free($2); free($3); free($4); }
131
2021-11-03
op
unbind : UNBIND STRING STRING { yyerror("TODO: unbind %s %s", $2, $3); }
134
2021-11-03
op
proxy : PROXY STRING VIA STRING { add_proxy($2, $4); free($4); }
137
2021-07-09
op
optnl : '\n' optnl /* zero or more newlines */
138
2021-07-09
op
| /* empty */
144
2021-06-15
op
yyerror(const char *fmt, ...)
146
2021-06-15
op
va_list va;
148
2021-06-15
op
fprintf(stderr, "%s:%d ", path, yylval.lineno+1);
149
2021-06-15
op
va_start(va, fmt);
150
2021-06-15
op
vfprintf(stderr, fmt, va);
151
2021-06-15
op
va_end(va);
152
2021-06-15
op
fprintf(stderr, "\n");
153
2021-06-15
op
parse_errors++;
156
2021-06-15
op
static struct keyword {
157
2021-06-15
op
const char *word;
158
2021-06-15
op
int token;
159
2021-06-15
op
} keywords[] = {
160
2021-11-03
op
{ "attr", ATTR },
161
2021-11-03
op
{ "bg", BG },
162
2021-11-03
op
{ "bind", BIND },
163
2021-11-03
op
{ "cont", CONT },
164
2021-11-03
op
{ "fg", FG },
165
2021-11-03
op
{ "prefix", PRFX },
166
2021-11-03
op
{ "proxy", PROXY },
167
2021-11-03
op
{ "set", SET },
168
2021-11-03
op
{ "style", STYLE },
169
2021-11-03
op
{ "unbind", UNBIND },
170
2021-11-03
op
{ "via", VIA },
174
2021-06-15
op
yylex(void)
176
2021-06-15
op
char buf[1024], *ebuf, *p, *str;
177
2021-06-15
op
const char *errstr;
178
2021-06-15
op
int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
179
2021-06-15
op
size_t i;
182
2021-06-15
op
ebuf = buf + sizeof(buf);
185
2021-06-15
op
/* skip whitespace first */
186
2021-06-15
op
for (c = getc(yyfp); c == ' ' || c == '\t' || c == '\f'; c = getc(yyfp))
187
2021-06-15
op
yylval.colno++;
189
2021-06-15
op
/* check for special one-character constructions */
190
2021-06-15
op
switch (c) {
191
2021-06-24
op
case '\r':
192
2021-06-24
op
/* silently eat up any \r */
193
2021-06-24
op
goto repeat;
194
2021-06-15
op
case '\n':
195
2021-06-15
op
yylval.colno = 0;
196
2021-06-15
op
yylval.lineno++;
197
2021-06-15
op
/* fallthrough */
198
2021-06-15
op
case '{':
199
2021-06-15
op
case '}':
200
2021-06-15
op
case '=':
201
2021-06-15
op
return c;
202
2021-06-15
op
case '#':
203
2021-06-15
op
/* skip comments; NUL is allowed; no continuation */
204
2021-06-15
op
while ((c = getc(yyfp)) != '\n')
205
2021-06-15
op
if (c == EOF)
206
2021-06-15
op
goto eof;
207
2021-06-15
op
yylval.colno = 0;
208
2021-06-15
op
yylval.lineno++;
209
2021-06-15
op
return c;
210
2021-06-15
op
case EOF:
211
2021-06-15
op
goto eof;
214
2021-06-15
op
/* parsing next word */
215
2021-06-15
op
for (;; c = getc(yyfp), yylval.colno++) {
216
2021-06-15
op
switch (c) {
217
2021-06-15
op
case '\0':
218
2021-06-15
op
yyerror("unallowed character NULL in column %d",
219
2021-06-15
op
yylval.colno+1);
220
2021-06-15
op
escape = 0;
221
2021-06-15
op
continue;
222
2021-06-15
op
case '\\':
223
2021-06-15
op
escape = !escape;
224
2021-06-15
op
if (escape)
225
2021-06-15
op
continue;
227
2021-06-24
op
case '\r':
228
2021-06-24
op
/* ignore \r here too */
229
2021-06-24
op
continue;
230
2021-06-15
op
case '\n':
231
2021-06-15
op
if (quotes)
232
2021-06-15
op
yyerror("unterminated quotes in column %d",
233
2021-06-15
op
yylval.colno+1);
234
2021-06-15
op
if (escape) {
235
2021-06-15
op
nonkw = 1;
236
2021-06-15
op
escape = 0;
237
2021-06-15
op
yylval.colno = 0;
238
2021-06-15
op
yylval.lineno++;
240
2021-06-15
op
goto eow;
241
2021-06-15
op
case EOF:
242
2021-06-15
op
if (escape)
243
2021-06-15
op
yyerror("unterminated escape in column %d",
244
2021-06-15
op
yylval.colno);
245
2021-06-15
op
if (quotes)
246
2021-06-15
op
yyerror("unterminated quotes in column %d",
247
2021-06-15
op
qpos + 1);
248
2021-06-15
op
goto eow;
249
2021-06-15
op
case '{':
250
2021-06-15
op
case '}':
251
2021-06-15
op
case '=':
252
2021-06-15
op
case '#':
253
2021-06-15
op
case ' ':
254
2021-06-15
op
case '\t':
255
2021-06-15
op
if (!escape && !quotes)
256
2021-06-15
op
goto eow;
258
2021-06-15
op
case '"':
259
2021-06-15
op
if (!escape) {
260
2021-06-15
op
quotes = !quotes;
261
2021-06-15
op
if (quotes) {
262
2021-06-15
op
nonkw = 1;
263
2021-06-15
op
qpos = yylval.colno;
265
2021-06-15
op
continue;
268
2021-06-15
op
*p++ = c;
269
2021-06-15
op
if (p == ebuf) {
270
2021-06-15
op
yyerror("line too long");
273
2021-06-15
op
escape = 0;
278
2021-06-15
op
if (c != EOF)
279
2021-06-15
op
ungetc(c, yyfp);
280
2021-06-15
op
if (p == buf) {
282
2021-06-15
op
* There could be a number of reason for empty buffer,
283
2021-06-15
op
* and we handle all of them here, to avoid cluttering
284
2021-06-15
op
* the main loop.
286
2021-06-15
op
if (c == EOF)
287
2021-06-15
op
goto eof;
288
2021-06-15
op
else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */
289
2021-06-15
op
goto repeat;
291
2021-06-15
op
if (!nonkw) {
292
2021-06-15
op
for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
293
2021-06-15
op
if (strcmp(buf, keywords[i].word) == 0)
294
2021-06-15
op
return keywords[i].token;
297
2021-06-15
op
c = *buf;
298
2021-06-15
op
if (!nonkw && (c == '-' || isdigit(c))) {
299
2021-06-15
op
yylval.num = strtonum(buf, INT_MIN, INT_MAX, &errstr);
300
2021-06-15
op
if (errstr != NULL)
301
2021-06-15
op
yyerror("number is %s: %s", errstr, buf);
302
2021-11-03
op
return NUMBER;
304
2021-06-15
op
if ((str = strdup(buf)) == NULL)
305
2021-06-15
op
err(1, "%s", __func__);
306
2021-06-15
op
yylval.str = str;
307
2021-11-03
op
return STRING;
310
2021-06-15
op
if (ferror(yyfp))
311
2021-06-15
op
yyerror("input error reading config");
312
2021-06-15
op
return 0;
315
2021-06-15
op
static void
316
2021-06-21
op
setprfx(const char *prfx, const char *cont)
318
2021-06-21
op
assert(current_style != NULL);
320
2021-06-21
op
if (!config_setprfx(current_style, prfx, cont))
321
2021-06-21
op
yyerror("invalid style %s", current_style);
324
2021-06-19
op
static void
325
2021-06-19
op
setvari(char *var, int val)
327
2021-06-19
op
if (!config_setvari(var, val))
328
2021-06-19
op
yyerror("invalid variable or value: %s = %d",
329
2021-06-19
op
var, val);
331
2021-06-19
op
free(var);
334
2021-06-19
op
static void
335
2021-06-19
op
setvars(char *var, char *val)
337
2021-08-26
op
if (!config_setvars(var, val))
338
2021-06-19
op
yyerror("invalid variable or value: %s = \"%s\"",
339
2021-06-19
op
var, val);
341
2021-06-19
op
free(var);
344
2021-06-21
op
static int
345
2021-06-21
op
colorname(const char *name)
348
2021-06-21
op
const char *name;
349
2021-06-21
op
short val;
350
2021-06-21
op
} *i, colors[] = {
351
2021-06-21
op
{ "default", -1 },
352
2021-06-21
op
{ "black", COLOR_BLACK },
353
2021-06-21
op
{ "red", COLOR_RED },
354
2021-06-21
op
{ "green", COLOR_GREEN },
355
2021-06-21
op
{ "yellow", COLOR_YELLOW },
356
2021-06-21
op
{ "blue", COLOR_BLUE },
357
2021-06-21
op
{ "magenta", COLOR_MAGENTA },
358
2021-06-21
op
{ "cyan", COLOR_CYAN },
359
2021-06-21
op
{ "white", COLOR_WHITE },
360
2021-06-21
op
{ NULL, 0 },
362
2021-06-22
op
const char *errstr;
365
2022-04-24
op
if (!strncmp(name, "colo", 4)) {
366
2021-06-22
op
/* people are strange */
367
2022-04-24
op
if (!strncmp(name, "color", 5))
368
2021-06-22
op
name += 5;
369
2022-04-24
op
else if (!strncmp(name, "colour", 6))
370
2021-06-22
op
name += 6;
372
2021-06-22
op
goto err;
374
2021-06-22
op
n = strtonum(name, 0, 256, &errstr);
375
2021-06-22
op
if (errstr != NULL)
376
2021-06-22
op
yyerror("color number is %s: %s", errstr, name);
377
2021-06-22
op
return n;
380
2021-06-21
op
for (i = colors; i->name != NULL; ++i) {
381
2021-06-21
op
if (!strcmp(i->name, name))
382
2021-06-21
op
return i->val;
386
2021-06-21
op
yyerror("unknown color name \"%s\"", name);
387
2021-06-21
op
return -1;
391
2021-06-21
op
setcolor(const char *prfx, const char *line, const char *trail)
393
2021-06-21
op
int p, l, t;
395
2021-06-21
op
assert(current_style != NULL);
397
2021-06-21
op
p = colorname(prfx);
398
2021-06-21
op
l = colorname(line);
399
2021-06-21
op
t = colorname(trail);
401
2021-11-03
op
if (!config_setcolor(color_type == BG, current_style, p, l, t))
402
2021-06-22
op
yyerror("invalid style %s", current_style);
405
2021-06-22
op
static int
406
2021-08-26
op
attrname(const char *n)
409
2021-06-22
op
const char *name;
410
2021-06-22
op
unsigned int val;
411
2021-06-22
op
} *i, attrs[] = {
412
2021-06-22
op
{ "normal", A_NORMAL },
413
2021-06-22
op
{ "standout", A_STANDOUT },
414
2021-06-22
op
{ "underline", A_UNDERLINE },
415
2021-06-22
op
{ "reverse", A_REVERSE },
416
2021-06-22
op
{ "blink", A_BLINK },
417
2021-06-22
op
{ "dim", A_DIM },
418
2021-06-22
op
{ "bold", A_BOLD },
419
2021-06-22
op
{ NULL, 0 },
421
2021-06-22
op
int ret, found;
422
2021-08-26
op
char *ap, *dup, *orig;
424
2021-08-26
op
if ((dup = strdup(n)) == NULL)
425
2021-08-26
op
err(1, "strdup");
427
2021-08-26
op
orig = dup;
430
2021-08-26
op
while ((ap = strsep(&dup, ",")) != NULL) {
431
2021-06-22
op
if (*ap == '\0')
432
2021-06-22
op
continue;
434
2021-06-22
op
found = 0;
435
2021-06-22
op
for (i = attrs; i ->name != NULL; ++i) {
436
2021-06-22
op
if (strcmp(i->name, ap))
437
2021-06-22
op
continue;
438
2021-06-22
op
ret |= i->val;
439
2021-06-22
op
found = 1;
443
2021-06-22
op
if (!found)
444
2021-06-22
op
yyerror("unknown attribute \"%s\" at col %d",
445
2021-06-22
op
ap, yylval.colno+1);
448
2021-08-26
op
free(orig);
449
2021-06-22
op
return ret;
452
2021-06-22
op
static void
453
2021-06-22
op
setattr(char *prfx, char *line, char *trail)
455
2021-06-22
op
int p, l, t;
457
2021-06-22
op
assert(current_style != NULL);
459
2021-06-22
op
p = attrname(prfx);
460
2021-06-22
op
l = attrname(line);
461
2021-06-22
op
t = attrname(trail);
463
2021-06-22
op
if (!config_setattr(current_style, p, l, t))
464
2021-06-21
op
yyerror("invalid style %s", current_style);
467
2021-06-23
op
static void
468
2021-06-23
op
add_proxy(char *proto, char *proxy)
470
2021-06-23
op
struct proxy *p;
471
2021-06-23
op
struct phos_uri uri;
473
2021-06-23
op
if (!phos_parse_absolute_uri(proxy, &uri)) {
474
2021-06-23
op
yyerror("can't parse URL: %s", proxy);
478
2021-06-23
op
if (*uri.path != '\0' || *uri.query != '\0' || *uri.fragment != '\0') {
479
2021-06-23
op
yyerror("proxy url can't have path, query or fragments");
483
2021-06-23
op
if (strcmp(uri.scheme, "gemini")) {
484
2021-06-23
op
yyerror("disallowed proxy protocol %s", uri.scheme);
488
2021-06-23
op
if ((p = calloc(1, sizeof(*p))) == NULL)
489
2021-06-23
op
err(1, "calloc");
491
2021-06-23
op
p->match_proto = proto;
492
2021-07-25
op
p->proto = PROTO_GEMINI;
494
2021-06-23
op
if ((p->host = strdup(uri.host)) == NULL)
495
2021-06-23
op
err(1, "strdup");
497
2021-06-23
op
if ((p->port = strdup(uri.port)) == NULL)
498
2021-06-23
op
err(1, "strdup");
500
2021-06-23
op
TAILQ_INSERT_HEAD(&proxies, p, proxies);
503
2021-06-25
op
static interactivefn *
504
2021-06-25
op
cmdname(const char *name)
506
2021-06-25
op
struct cmd *cmd;
508
2021-08-26
op
for (cmd = cmds; cmd->cmd != NULL; ++cmd) {
509
2021-06-25
op
if (!strcmp(cmd->cmd, name))
510
2021-06-25
op
return cmd->fn;
513
2021-06-25
op
return NULL;
516
2021-06-25
op
static void
517
2021-06-25
op
bindkey(const char *map, const char *key, const char *cmd)
519
2021-06-25
op
struct kmap *kmap;
520
2021-06-25
op
interactivefn *fn;
522
2021-06-25
op
if (!strcmp(map, "global-map"))
523
2021-06-25
op
kmap = &global_map;
524
2021-06-25
op
else if (!strcmp(map, "minibuffer-map"))
525
2021-06-25
op
kmap = &minibuffer_map;
527
2021-06-25
op
yyerror("unknown map: %s", map);
531
2021-06-25
op
if ((fn = cmdname(cmd)) == NULL) {
532
2021-06-25
op
yyerror("unknown cmd: %s", fn);
536
2021-06-25
op
if (!kmap_define_key(kmap, key, fn))
537
2021-06-25
op
yyerror("failed to bind %s %s %s", map, key, cmd);
540
2021-07-15
op
static void
541
2021-07-15
op
do_parseconfig(const char *filename, int fonf)
543
2021-06-15
op
if ((yyfp = fopen(filename, "r")) == NULL) {
544
2021-06-15
op
if (fonf)
545
2021-06-15
op
err(1, "%s", filename);
549
2021-06-15
op
path = filename;
550
2021-06-15
op
yyparse();
551
2021-06-15
op
fclose(yyfp);
552
2021-06-15
op
if (parse_errors)
557
2021-07-15
op
parseconfig(const char *filename, int fonf)
559
2021-07-15
op
char altconf[PATH_MAX], *term;
561
2021-07-15
op
/* load the given config file */
562
2021-07-15
op
do_parseconfig(filename, fonf);
564
2021-07-15
op
/* then try to load file-TERM */
566
2021-07-15
op
if ((term = getenv("TERM")) == NULL)
569
2021-07-15
op
strlcpy(altconf, filename, sizeof(altconf));
570
2021-07-15
op
strlcat(altconf, "-", sizeof(altconf));
571
2021-07-15
op
strlcat(altconf, term, sizeof(altconf));
573
2021-07-15
op
do_parseconfig(altconf, 0);