-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopen_brace.c
248 lines (180 loc) · 6.47 KB
/
open_brace.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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#define _ISOC99_SOURCE 1
#include"strglob.h"
/*! @fn char *open_brace(char *optr, STR_GLOB *restrict pugp)
*
* @brief parse string input after a left curly brace, i.e. `{`
*
* @param [in] optr a pointer to the string location after the left curly brace
*
* @param [out] pugp a pointer to the glob list element currently being handled
*
* @return a pointer to the string location of the matching right curly brace, i.e. `}`
*
* @see open_bracket
*
* @see open_paren
*/
char *open_brace(char *optr, STR_GLOB *restrict pugp) {
assert(optr);
assert(pugp);
*optr++ = '\0';
char *restrict close_brace = strchr(optr, '}');
if(!close_brace)
strglob_error("No matching close brace!");
*close_brace++ = '\0';
char *restrict first_comma = strchr(optr, ',');
if(!first_comma) {
char *restrict open_colon = strchr(optr, ':');
if(!open_colon) {
char *restrict twodots1 = strstr(optr, "..");
if(twodots1) {
*twodots1 = '\0';
twodots1 += 2;
if(strchr(optr, '.')) {
const float fbeg = strtof(optr, NULL), fend = strtof(twodots1, NULL);
char *restrict twodots2 = strstr(twodots1, "..");
float finc = 1.0;
if(errno == ERANGE)
strglob_error("Erroneous floating point range!");
if(twodots2) {
*twodots2 = '\0';
twodots2 += 2;
if(!*twodots2)
strglob_error("Empty floating point increment value!");
finc = strtof(twodots2, NULL);
if(errno == ERANGE)
strglob_error("Erroneous floating point increment value!");
}
pugp->runi.frng.beg = fbeg;
pugp->runi.frng.end = fend;
pugp->runi.frng.inc = finc;
pugp->type = 6; /* float range */
} else {
char *restrict twodots2 = strstr(twodots1, "..");
intmax_t ainc = 1;
if(twodots2) {
*twodots2 = '\0';
twodots2 += 2;
if(!*twodots2)
strglob_error("Empty alphanumeric increment value!");
ainc = strtoimax(twodots2, NULL, 0xA);
if(errno == ERANGE)
strglob_error("Erroenous alphanumeric increment value!");
}
if(*optr == '+')
optr++;
if(*optr == '-' || isdigit(*optr)) {
pugp->runi.crng.beg = strtoimax(optr, NULL, 0xA);
if(errno == ERANGE)
strglob_error("Erroneous integer range start value!");
if(*twodots1 != '-' && *twodots1 != '+' && !isdigit(*twodots1))
strglob_error("Integer range finish value must begin with a numeric digit or sign!");
pugp->runi.crng.end = strtoimax(twodots1, NULL, 0xA);
if(errno == ERANGE)
strglob_error("Erroneous integer range finish value!");
pugp->type = 1; /* integer range */
} else {
pugp->runi.crng.beg = *optr;
pugp->runi.crng.end = *twodots1;
pugp->type = 2; /* character range */
}
pugp->runi.crng.inc = ainc;
return close_brace;
}
} else {
#ifdef STRGLOB_ENVIRON_EXPAND
if(*optr == '$') {
optr++;
char *const aenv = getenv(optr);
pugp->out = malloc(2 * sizeof(*(pugp->out)));
if(!pugp->out)
exit_verbose("malloc", __FILE__, __LINE__);
if(!aenv)
pugp->out[0] = "";
else
pugp->out[0] = aenv;
pugp->out[1] = NULL;
} else {
#endif
#ifdef STRGLOB_FILE_INCLUDES
struct stat asta = { 0x0 };
if(!stat(optr, &asta))
exit_verbose("stat", __FILE__, __LINE__);
if((asta.st_mode & S_IFMT) == S_IFDIR) { /* select a random file */
else if((asta.st_mode & S_IFMT) == S_ISLNK) {
/* if sticky bit is set, select one random line */
/* otherwise, select all lines, randomly, i.e. mmap() and shuffle.. */
} else { /* read lines from file */
const size_t nlns = 1 + count_lines(optr);
if(nlns > 0) {
FILE *fptr = fopen(optr, "r");
if(fptr) {
register size_t alin = 0;
char abuf[BUFSIZ] = { 0x0 };
char **lptr = malloc(nlns * sizeof*lptr);
if(!lptr)
exit_verbose("malloc", __FILE__, __LINE__);
while(fgets(abuf, sizeof abuf, fptr) && alin < nlns) {
char *astr = strdup(abuf);
if(!astr)
exit_verbose("strdup", __FILE__, __LINE__);
char *atok = strpbrk(astr, "\r\n");
if(atok)
*atok = '\0';
lptr[alin] = astr;
alin++;
}
lptr[alin] = NULL;
pugp->type = 3; /* set */
pugp->out = lptr;
return close_brace;
} else
exit_verbose("fopen", __FILE__, __LINE__);
} else { /* empty file, so create empty string array */
char **const ep = malloc(sizeof*ep);
if(!ep)
exit_verbose("malloc", __FILE__, __LINE__);
*ep = NULL;
pugp->type = 3; /* set */
pugp->out = ep;
return close_brace;
}
}
#else
strglob_error("No comma, colon, dash or dot-dot inside curly braces!");
#endif
#ifdef STRGLOB_ENVIRON_EXPAND
}
#endif
}
return open_colon;
} else {
*open_colon++ = '\0';
char *restrict close_colon = strchr(open_colon, ':');
if(!close_colon)
strglob_error("No closing colon after opening colon inside curly braces!");
*close_colon++ = '\0';
if(string_class(open_colon, pugp))
strglob_error("No matching string class found!");
}
return close_brace;
}
const size_t acnt = 2 + count_commas(optr);
char **pp = malloc(acnt * sizeof*pp);
if(!pp)
exit_verbose("malloc", __FILE__, __LINE__);
pugp->out = pp;
pugp->type = 3; /* set */
do {
char *restrict next_comma = strchr(optr, ',');
if(!next_comma) {
*pp++ = optr;
break;
}
*next_comma++ = '\0';
*pp++ = optr;
optr = next_comma;
} while(true);
*pp = NULL;
return close_brace;
}