1 /*============================================================================
2   WCSLIB 7.7 - an implementation of the FITS WCS standard.
3   Copyright (C) 1995-2021, Mark Calabretta
4 
5   This file is part of WCSLIB.
6 
7   WCSLIB is free software: you can redistribute it and/or modify it under the
8   terms of the GNU Lesser General Public License as published by the Free
9   Software Foundation, either version 3 of the License, or (at your option)
10   any later version.
11 
12   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
15   more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with WCSLIB.  If not, see http://www.gnu.org/licenses.
19 
20   Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21   http://www.atnf.csiro.au/people/Mark.Calabretta
22   $Id: wcsutrn.l,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *=============================================================================
24 *
25 * wcsutrn.l is a Flex description file containing the definition of a lexical
26 * scanner that translates non-standard FITS units specifications.
27 *
28 * It requires Flex v2.5.4 or later.
29 *
30 * Refer to wcsunits.h for a description of the user interface and operating
31 * notes.
32 *
33 *===========================================================================*/
34 
35 /* Options. */
36 %option full
37 %option never-interactive
38 %option noinput
39 %option noyywrap
40 %option outfile="wcsutrn.c"
41 %option prefix="wcsutrn"
42 %option reentrant
43 %option extra-type="struct wcsutrn_extra *"
44 
45 /* Exclusive start states. */
46 %x NEXT FLUSH
47 
48 %{
49 #include <setjmp.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #include "wcserr.h"
55 #include "wcsunits.h"
56 
57 // User data associated with yyscanner.
58 struct wcsutrn_extra {
59   // Used in preempting the call to exit() by yy_fatal_error().
60   jmp_buf abort_jmp_env;
61 };
62 
63 #define YY_DECL int wcsutrne_scanner(int ctrl, char unitstr[], \
64  struct wcserr **err, yyscan_t yyscanner)
65 
66 // Dummy definition to circumvent compiler warnings.
67 #define YY_INPUT(inbuff, count, bufsize) { count = YY_NULL; }
68 
69 // Preempt the call to exit() by yy_fatal_error().
70 #define exit(status) longjmp(yyextra->abort_jmp_env, status);
71 
72 // Internal helper functions.
73 static YY_DECL;
74 
75 %}
76 
77 %%
78 	static const char *function = "wcsutrne_scanner";
79 
80 	if (err) *err = 0x0;
81 
82 	char orig[80], subs[80];
83 	*orig = '\0';
84 	*subs = '\0';
85 
86 	int bracket = 0;
87 	int unsafe  = 0;
88 	int status  = -1;
89 
90 	yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
91 	yy_scan_string(unitstr, yyscanner);
92 	*unitstr = '\0';
93 
94 	// Return here via longjmp() invoked by yy_fatal_error().
95 	if (setjmp(yyextra->abort_jmp_env)) {
96 	  return wcserr_set(WCSERR_SET(UNITSERR_PARSER_ERROR),
97 	    "Internal units translator error");
98 	}
99 
100 	BEGIN(INITIAL);
101 
102 	#ifdef DEBUG
103 	fprintf(stderr, "\n%s ->\n", unitstr);
104 	#endif
105 
106 ^" "*"[" {
107 	  // Looks like a keycomment.
108 	  strcat(unitstr, "[");
109 	  bracket = 1;
110 	}
111 
112 " "+	  // Discard leading whitespace.
113 
114 [^A-Za-z] {
115 	  // Non-alphabetic character.
116 	  strcat(unitstr, yytext);
117 	  if (bracket && *yytext == ']') {
118 	    BEGIN(FLUSH);
119 	  }
120 	}
121 
122 Angstroms|angstroms? {
123 	  strcpy(orig, yytext);
124 	  strcpy(subs, "Angstrom");
125 	  BEGIN(NEXT);
126 	}
127 
128 arcmins|ARCMINS? {
129 	  strcpy(orig, yytext);
130 	  strcpy(subs, "arcmin");
131 	  BEGIN(NEXT);
132 	}
133 
134 arcsecs|ARCSECS? {
135 	  strcpy(orig, yytext);
136 	  strcpy(subs, "arcsec");
137 	  BEGIN(NEXT);
138 	}
139 
140 BEAM	{
141 	  strcpy(orig, yytext);
142 	  strcpy(subs, "beam");
143 	  BEGIN(NEXT);
144 	}
145 
146 Byte	{
147 	  strcpy(orig, yytext);
148 	  strcpy(subs, "byte");
149 	  BEGIN(NEXT);
150 	}
151 
152 days?|DAYS? {
153 	  strcpy(orig, yytext);
154 	  strcpy(subs, "d");
155 	  BEGIN(NEXT);
156 	}
157 
158 D	{
159 	  unsafe = 1;
160 	  strcpy(orig, yytext);
161 	  strcpy(subs, (ctrl & 4) ? "d" : "D");
162 	  BEGIN(NEXT);
163 	}
164 
165 degrees?|Deg|Degrees?|DEG|DEGREES? {
166 	  strcpy(orig, yytext);
167 	  strcpy(subs, "deg");
168 	  BEGIN(NEXT);
169 	}
170 
171 GHZ	{
172 	  strcpy(orig, yytext);
173 	  strcpy(subs, "GHz");
174 	  BEGIN(NEXT);
175 	}
176 
177 hr|HR	{
178 	  strcpy(orig, yytext);
179 	  strcpy(subs, "h");
180 	  BEGIN(NEXT);
181 	}
182 
183 H	{
184 	  unsafe = 1;
185 	  strcpy(orig, yytext);
186 	  strcpy(subs, (ctrl & 2) ? "h" : "H");
187 	  BEGIN(NEXT);
188 	}
189 
190 hz|HZ	{
191 	  strcpy(orig, yytext);
192 	  strcpy(subs, "Hz");
193 	  BEGIN(NEXT);
194 	}
195 
196 KHZ	{
197 	  strcpy(orig, yytext);
198 	  strcpy(subs, "kHz");
199 	  BEGIN(NEXT);
200 	}
201 
202 JY	{
203 	  strcpy(orig, yytext);
204 	  strcpy(subs, "Jy");
205 	  BEGIN(NEXT);
206 	}
207 
208 [kK]elvins?|KELVINS? {
209 	  strcpy(orig, yytext);
210 	  strcpy(subs, "K");
211 	  BEGIN(NEXT);
212 	}
213 
214 KM	{
215 	  strcpy(orig, yytext);
216 	  strcpy(subs, "km");
217 	  BEGIN(NEXT);
218 	}
219 
220 metres?|meters?|M|METRES?|METERS? {
221 	  strcpy(orig, yytext);
222 	  strcpy(subs, "m");
223 	  BEGIN(NEXT);
224 	}
225 
226 MIN	{
227 	  strcpy(orig, yytext);
228 	  strcpy(subs, "min");
229 	  BEGIN(NEXT);
230 	}
231 
232 MHZ	{
233 	  strcpy(orig, yytext);
234 	  strcpy(subs, "MHz");
235 	  BEGIN(NEXT);
236 	}
237 
238 Ohm	{
239 	  strcpy(orig, yytext);
240 	  strcpy(subs, "ohm");
241 	  BEGIN(NEXT);
242 	}
243 
244 [pP]ascals?|PASCALS? {
245 	  strcpy(orig, yytext);
246 	  strcpy(subs, "Pa");
247 	  BEGIN(NEXT);
248 	}
249 
250 pixels|PIXELS? {
251 	  strcpy(orig, yytext);
252 	  strcpy(subs, "pixel");
253 	  BEGIN(NEXT);
254 	}
255 
256 radians?|RAD|RADIANS? {
257 	  strcpy(orig, yytext);
258 	  strcpy(subs, "rad");
259 	  BEGIN(NEXT);
260 	}
261 
262 sec|seconds?|SEC|SECONDS? {
263 	  strcpy(orig, yytext);
264 	  strcpy(subs, "s");
265 	  BEGIN(NEXT);
266 	}
267 
268 S	{
269 	  unsafe = 1;
270 	  strcpy(orig, yytext);
271 	  strcpy(subs, (ctrl & 1) ? "s" : "S");
272 	  BEGIN(NEXT);
273 	}
274 
275 [vV]olts?|VOLTS? {
276 	  strcpy(orig, yytext);
277 	  strcpy(subs, "V");
278 	  BEGIN(NEXT);
279 	}
280 
281 years?|YR|YEARS? {
282 	  strcpy(orig, yytext);
283 	  strcpy(subs, "yr");
284 	  BEGIN(NEXT);
285 	}
286 
287 [A-Za-z]+ {
288 	  // Not a recognized alias.
289 	  strcpy(orig, yytext);
290 	  strcpy(subs, orig);
291 	  BEGIN(NEXT);
292 	}
293 
294 <NEXT>[A-Za-z]+ {
295 	  // Reject the alias match.
296 	  strcat(orig, yytext);
297 	  strcpy(subs, orig);
298 	}
299 
300 <NEXT>" "+[^A-Za-z] {
301 	  // Discard separating whitespace.
302 	  unput(yytext[yyleng-1]);
303 	}
304 
305 <NEXT>" "+[A-Za-z] {
306 	  // Compress separating whitespace.
307 	  strcat(unitstr, subs);
308 	  strcat(unitstr, " ");
309 	  if (strcmp(orig, subs)) status = 0;
310 	  unput(yytext[yyleng-1]);
311 	  *subs = '\0';
312 	  BEGIN(INITIAL);
313 	}
314 
315 <NEXT>.	{
316 	  // Copy anything else unchanged.
317 	  strcat(unitstr, subs);
318 	  if (strcmp(orig, subs)) status = 0;
319 	  unput(*yytext);
320 	  *subs = '\0';
321 	  BEGIN(INITIAL);
322 	}
323 
324 <FLUSH>.* {
325 	  // Copy out remaining input.
326 	  strcat(unitstr, yytext);
327 	}
328 
329 <<EOF>>	{
330 	  // End-of-string.
331 	  if (*subs) {
332 	    strcat(unitstr, subs);
333 	    if (strcmp(orig, subs)) status = 0;
334 	  }
335 
336 	  if (unsafe) {
337 	    return wcserr_set(WCSERR_SET(UNITSERR_UNSAFE_TRANS),
338 	      "Unsafe unit translation in '%s'", unitstr);
339 	  }
340 	  return status;
341 	}
342 
343 %%
344 
345 /*----------------------------------------------------------------------------
346 * External interface to the scanner.
347 *---------------------------------------------------------------------------*/
348 
349 int wcsutrne(
350   int ctrl,
351   char unitstr[],
352   struct wcserr **err)
353 
354 {
355   // Function prototypes.
356   int yylex_init_extra(YY_EXTRA_TYPE extra, yyscan_t *yyscanner);
357   int yylex_destroy(yyscan_t yyscanner);
358 
359   struct wcsutrn_extra extra;
360   yyscan_t yyscanner;
361   yylex_init_extra(&extra, &yyscanner);
362   int status = wcsutrne_scanner(ctrl, unitstr, err, yyscanner);
363   yylex_destroy(yyscanner);
364 
365   return status;
366 }
367