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