-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparser.c
More file actions
125 lines (118 loc) · 3.06 KB
/
Copy pathparser.c
File metadata and controls
125 lines (118 loc) · 3.06 KB
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
/*
* file: parser.c
* description: skeleton code for a simple shell
*
* Peter Desnoyers, Northeastern Fall 2023
*/
#include <stdio.h>
#include <ctype.h>
#include "parser.h"
/* makes a bit of logic below prettier */
int isquote(int c)
{
return c == '"' || c == '\'';
}
/* really simple command line parser.
* probably fails in a lot of corner cases.
*/
/* tokenizer, takes previous char c1 (=0 at start) and current char c2.
* returns the OR of the following values:
* SPLIT - c2 goes in a new word
* SAVE - c2 gets stored in its word
* it's horribly ad-hoc, and the approach fails for more complex grammars
* (e.g. it can't do wildcards right without extensive modification)
*/
int split(char c1, char c2)
{
static int in_2quote;
static int in_1quote;
if (c1 == 0)
return NO_SPLIT | (isspace(c2) ? NO_SAVE : SAVE);
if (in_2quote) {
if (c2 == '"') {
in_2quote = 0;
return SPLIT | NO_SAVE;
}
else
return NO_SPLIT | SAVE;
}
else if (in_1quote) {
if (c2 == '\'') {
in_1quote = 0;
return SPLIT | NO_SAVE;
}
else
return NO_SPLIT | SAVE;
}
if (c2 == '"') {
in_2quote = 1;
return (isspace(c1) ? NO_SPLIT : SPLIT) | NO_SAVE;
}
if (c2 == '\'') {
in_1quote = 1;
return (isspace(c1) ? NO_SPLIT : SPLIT) | NO_SAVE;
}
if (c2 == '|')
return (isspace(c1) ? NO_SPLIT : SPLIT) | SAVE;
if (c1 == '|')
return SPLIT | (isspace(c2) ? NO_SAVE : SAVE);
if (isspace(c2))
return ((isspace(c1) || isquote(c1)) ? NO_SPLIT : SPLIT) | NO_SAVE;
if (c2 == '>' || c2 == '<')
return (isspace(c1) ? NO_SPLIT : SPLIT) | SAVE;
if (c1 == '>' || c1 == '<')
return SPLIT | (isspace(c2) ? NO_SAVE : SAVE);
return NO_SPLIT | SAVE;
}
/* parse an input line, copying individual words (plus terminating
* null characters) into an output buffer, and storing pointers to
* those words in an argv-like array, both passed by the caller.
*
* returns: number of words in argv
*/
int parse(const char *line, int argc_max, char **argv, char *buf, int buf_len)
{
char *ptr = buf;
int i = 0, prev = 0;
argv[i] = ptr;
for (const char *p = line; *p != 0; p++) {
int val = split(prev, *p);
if (val & SPLIT) {
*ptr++ = 0;
argv[++i] = ptr;
}
if (val & SAVE)
*ptr++ = *p;
prev = *p;
if (ptr > buf+buf_len-2)
break;
if (i >= argc_max-1)
break;
}
if (ptr != argv[i]) {
*ptr++ = 0;
i++;
}
argv[i] = NULL;
return i;
}
#ifdef TEST
#include <stdio.h>
int main(int argc, char **argv)
{
FILE *fp = stdin;
if (argc > 1)
fp = fopen(argv[1], "r");
char line[1024], buf[1024], *words[20];
while (fgets(line, sizeof(line), fp)) {
const char *comma = "";
int n = parse(line, 20, words, buf, sizeof(buf));
printf("[");
for (int i = 0; i < n; i++) {
printf("%s'%s'", comma, words[i]);
comma = ", ";
}
printf("]\n");
}
}
#endif