1 /*** dconv.c -- convert calendrical and time stamp systems
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-io.h"
48 #include "dt-locale.h"
49 #include "prchunk.h"
50
51
52 const char *prog = "dconv";
53
54 struct prln_ctx_s {
55 struct grep_atom_soa_s *ndl;
56 const char *ofmt;
57 zif_t fromz;
58 zif_t outz;
59 int sed_mode_p;
60 int quietp;
61 };
62
63 static int
proc_line(struct prln_ctx_s ctx,char * line,size_t llen)64 proc_line(struct prln_ctx_s ctx, char *line, size_t llen)
65 {
66 struct dt_dt_s d;
67 char *sp = NULL;
68 char *ep = NULL;
69 int rc = 0;
70
71 do {
72 d = dt_io_find_strpdt2(
73 line, llen, ctx.ndl, &sp, &ep, ctx.fromz);
74
75 /* check if line matches */
76 if (!dt_unk_p(d) && ctx.sed_mode_p) {
77 __io_write(line, sp - line, stdout);
78 dt_io_write(d, ctx.ofmt, ctx.outz, '\0');
79 llen -= (ep - line);
80 line = ep;
81 } else if (!dt_unk_p(d)) {
82 if (UNLIKELY(d.fix) && !ctx.quietp) {
83 rc = 2;
84 }
85 dt_io_write(d, ctx.ofmt, ctx.outz, '\n');
86 break;
87 } else if (ctx.sed_mode_p) {
88 line[llen] = '\n';
89 __io_write(line, llen + 1, stdout);
90 break;
91 } else {
92 /* obviously unmatched, warn about it in non -q mode */
93 if (!ctx.quietp) {
94 dt_io_warn_strpdt(line);
95 rc = 2;
96 }
97 break;
98 }
99 } while (1);
100 return rc;
101 }
102
103
104 #include "dconv.yucc"
105
106 int
main(int argc,char * argv[])107 main(int argc, char *argv[])
108 {
109 yuck_t argi[1U];
110 const char *ofmt;
111 char **fmt;
112 size_t nfmt;
113 int rc = 0;
114 zif_t fromz = NULL;
115 zif_t z = NULL;
116
117 if (yuck_parse(argi, argc, argv)) {
118 rc = 1;
119 goto out;
120 }
121 /* init and unescape sequences, maybe */
122 ofmt = argi->format_arg;
123 fmt = argi->input_format_args;
124 nfmt = argi->input_format_nargs;
125 if (argi->backslash_escapes_flag) {
126 dt_io_unescape(argi->format_arg);
127 for (size_t i = 0; i < nfmt; i++) {
128 dt_io_unescape(fmt[i]);
129 }
130 }
131
132 if (argi->locale_arg) {
133 setflocale(argi->locale_arg);
134 }
135 if (argi->from_locale_arg) {
136 setilocale(argi->from_locale_arg);
137 }
138
139 /* try and read the from and to time zones */
140 if (argi->from_zone_arg) {
141 fromz = dt_io_zone(argi->from_zone_arg);
142 }
143 if (argi->zone_arg) {
144 z = dt_io_zone(argi->zone_arg);
145 }
146 if (argi->base_arg) {
147 struct dt_dt_s base = dt_strpdt(argi->base_arg, NULL, NULL);
148 dt_set_base(base);
149 }
150
151 if (argi->nargs) {
152 for (size_t i = 0; i < argi->nargs; i++) {
153 const char *inp = argi->args[i];
154 struct dt_dt_s d = dt_io_strpdt(inp, fmt, nfmt, fromz);
155
156 if (!dt_unk_p(d)) {
157 if (UNLIKELY(d.fix) && !argi->quiet_flag) {
158 rc = 2;
159 }
160 dt_io_write(d, ofmt, z, '\n');
161 } else if (!argi->quiet_flag) {
162 rc = 2;
163 dt_io_warn_strpdt(inp);
164 }
165 }
166 } else {
167 /* read from stdin */
168 size_t lno = 0;
169 struct grep_atom_s __nstk[16], *needle = __nstk;
170 size_t nneedle = countof(__nstk);
171 struct grep_atom_soa_s ndlsoa;
172 void *pctx;
173 struct prln_ctx_s prln = {
174 .ndl = &ndlsoa,
175 .ofmt = ofmt,
176 .fromz = fromz,
177 .outz = z,
178 .sed_mode_p = argi->sed_mode_flag,
179 .quietp = argi->quiet_flag,
180 };
181
182 /* no threads reading this stream */
183 __io_setlocking_bycaller(stdout);
184
185 /* lest we overflow the stack */
186 if (nfmt >= nneedle) {
187 /* round to the nearest 8-multiple */
188 nneedle = (nfmt | 7) + 1;
189 needle = calloc(nneedle, sizeof(*needle));
190 }
191 /* and now build the needles */
192 ndlsoa = build_needle(needle, nneedle, fmt, nfmt);
193
194 /* using the prchunk reader now */
195 if ((pctx = init_prchunk(STDIN_FILENO)) == NULL) {
196 serror("Error: could not open stdin");
197 goto ndl_free;
198 }
199 while (prchunk_fill(pctx) >= 0) {
200 for (char *line; prchunk_haslinep(pctx); lno++) {
201 size_t llen = prchunk_getline(pctx, &line);
202
203 rc |= proc_line(prln, line, llen);
204 }
205 }
206 /* get rid of resources */
207 free_prchunk(pctx);
208 ndl_free:
209 if (needle != __nstk) {
210 free(needle);
211 }
212 }
213
214 dt_io_clear_zones();
215 if (argi->from_locale_arg) {
216 setilocale(NULL);
217 }
218 if (argi->locale_arg) {
219 setflocale(NULL);
220 }
221
222 out:
223 yuck_free(argi);
224 return rc;
225 }
226
227 /* dconv.c ends here */
228