1 /*** dgrep.c -- grep for lines with dates
2 *
3 * Copyright (C) 2011-2016 Sebastian Freundt
4 *
5 * Author: Sebastian Freundt <freundt@ga-group.nl>
6 *
7 * This file is part of dateutils.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of the author nor the names of any contributors
21 * may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 **/
37 #if defined HAVE_CONFIG_H
38 # include "config.h"
39 #endif /* HAVE_CONFIG_H */
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdint.h>
43 #include <sys/time.h>
44 #include <time.h>
45
46 #include "dt-core.h"
47 #include "dt-core-tz-glue.h"
48 #include "dt-io.h"
49 #include "dexpr.h"
50 #include "dt-locale.h"
51 #include "prchunk.h"
52
53 const char *prog = "dgrep";
54
55
56 /* dexpr subsystem */
57 #include "dexpr.c"
58
59 struct prln_ctx_s {
60 struct grep_atom_soa_s *ndl;
61 dexpr_t root;
62 zif_t fromz;
63 zif_t z;
64 unsigned int only_matching_p:1U;
65 unsigned int invert_match_p:1U;
66 };
67
68 static void
proc_line(struct prln_ctx_s ctx,char * line,size_t llen)69 proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
70 {
71 char *osp = NULL;
72 char *oep = NULL;
73
74 /* check if line matches,
75 * there's currently no way to specify NEEDLE */
76 for (char *lp = line, *const zp = line + llen, *sp, *ep;
77 /*no check*/; lp = ep, osp = sp, oep = ep) {
78 struct dt_dt_s d =
79 dt_io_find_strpdt2(
80 lp, zp - lp, ctx.ndl, &sp, &ep, ctx.fromz);
81 bool unkp = dt_unk_p(d);
82
83 if (unkp) {
84 /* just plain nothing */
85 break;
86 } else if (ctx.z != NULL) {
87 /* promote to zone ctx.z */
88 d = dtz_enrichz(d, ctx.z);
89 }
90 /* otherwise */
91 if (dexpr_matches_p(ctx.root, d)) {
92 if (ctx.invert_match_p) {
93 /* nothing must match */
94 return;
95 } else if (!ctx.only_matching_p) {
96 sp = line;
97 ep = line + llen;
98 }
99 /* make sure we finish the line */
100 *ep++ = '\n';
101 __io_write(sp, ep - sp, stdout);
102 return;
103 }
104 }
105 if (ctx.invert_match_p) {
106 /* no match but invert_match select, print line */
107 if (!ctx.only_matching_p) {
108 osp = line;
109 oep = line + llen;
110 } else if (osp == NULL || oep == NULL) {
111 /* no date in line and only-matching is active
112 * bugger off */
113 return;
114 }
115 /* finish the line and bugger off */
116 *oep++ = '\n';
117 __io_write(osp, oep - osp, stdout);
118 }
119 return;
120 }
121
122
123 #include "dgrep.yucc"
124
125 int
main(int argc,char * argv[])126 main(int argc, char *argv[])
127 {
128 yuck_t argi[1U];
129 char **fmt;
130 size_t nfmt;
131 dexpr_t root;
132 oper_t o = OP_UNK;
133 int res = 0;
134
135 if (yuck_parse(argi, argc, argv)) {
136 res = 1;
137 goto out;
138 }
139
140 /* init and unescape sequences, maybe */
141 ckv_fmt = fmt = argi->input_format_args;
142 ckv_nfmt = nfmt = argi->input_format_nargs;
143 if (argi->backslash_escapes_flag) {
144 for (size_t i = 0; i < nfmt; i++) {
145 dt_io_unescape(fmt[i]);
146 }
147 }
148 if (argi->base_arg) {
149 struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL);
150 dt_set_base(base);
151 }
152
153 if (argi->eq_flag) {
154 o = OP_EQ;
155 } else if (argi->ne_flag) {
156 o = OP_NE;
157 } else if (argi->lt_flag || argi->ot_flag) {
158 o = OP_LT;
159 } else if (argi->le_flag) {
160 o = OP_LE;
161 } else if (argi->gt_flag || argi->nt_flag) {
162 o = OP_GT;
163 } else if (argi->ge_flag) {
164 o = OP_GE;
165 }
166 /* parse the expression */
167 if (argi->nargs == 0U ||
168 dexpr_parse(&root, argi->args[0U], strlen(argi->args[0U])) < 0) {
169 res = 1;
170 error("Error: need an expression to grep");
171 goto out;
172 }
173 /* fixup o, default is OP_EQ */
174 if (o != OP_UNK && root->type != DEX_VAL) {
175 res = 1;
176 error("\
177 long opt operators (--lt, --gt, ...) cannot be used in conjunction \n\
178 with complex expressions");
179 goto out;
180 } else if (o != OP_UNK) {
181 /* fiddle with the operator in the expression */
182 root->kv->op = o;
183 }
184
185 if (argi->from_locale_arg) {
186 setilocale(argi->from_locale_arg);
187 }
188
189 /* otherwise bring dexpr to normal form */
190 dexpr_simplify(root);
191 /* beef */
192 {
193 /* read from stdin */
194 size_t lno = 0;
195 struct grep_atom_s __nstk[16], *needle = __nstk;
196 size_t nneedle = countof(__nstk);
197 struct grep_atom_soa_s ndlsoa;
198 void *pctx;
199 struct prln_ctx_s prln = {
200 .ndl = &ndlsoa,
201 .root = root,
202 .fromz = dt_io_zone(argi->from_zone_arg),
203 .z = dt_io_zone(argi->zone_arg),
204 .only_matching_p = argi->only_matching_flag,
205 .invert_match_p = argi->invert_match_flag,
206 };
207
208 /* no threads reading this stream */
209 __io_setlocking_bycaller(stdout);
210
211 /* lest we overflow the stack */
212 if (nfmt >= nneedle) {
213 /* round to the nearest 8-multiple */
214 nneedle = (nfmt | 7) + 1;
215 needle = calloc(nneedle, sizeof(*needle));
216 }
217 /* and now build the needle */
218 ndlsoa = build_needle(needle, nneedle, fmt, nfmt);
219
220 /* using the prchunk reader now */
221 if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
222 serror("Error: could not open stdin");
223 goto ndl_free;
224 }
225 while (prchunk_fill(pctx) >= 0) {
226 for (char *line; prchunk_haslinep(pctx); lno++) {
227 size_t llen = prchunk_getline(pctx, &line);
228
229 proc_line(prln, line, llen);
230 }
231 }
232 /* get rid of resources */
233 free_prchunk(pctx);
234 ndl_free:
235 if (needle != __nstk) {
236 free(needle);
237 }
238 }
239 /* resource freeing */
240 free_dexpr(root);
241 dt_io_clear_zones();
242 if (argi->from_locale_arg) {
243 setilocale(NULL);
244 }
245 out:
246 yuck_free(argi);
247 return res;
248 }
249
250 /* dgrep.c ends here */
251