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