OSDN Git Service

Handle "%" wildcard matches in package and subsystem version strings.
[mingw/mingw-get.git] / src / pkginfo / pkginfo.l
1 /*
2  * pkginfo.l
3  *
4  * $Id$
5  *
6  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7  * Copyright (C) 2009, 2010, MinGW Project
8  *
9  *
10  * A simple lexical analyser for decomposing package archive names into their
11  * constituent components.  It implements the schema:--
12  *
13  *   <archive-name>      ::= <package-id>[["-"<system-id>]][[-<status>]]"-"<type-id>
14  *
15  *   <package-id>        ::= <package-name>"-"<version>[["-"<build-id>]]
16  *   <system-id>         ::= <system-name>[["-"<version>[["-"<build-id>]]]]
17  *   <type-id>           ::= <component-id>"."<format-type>[["."<compression-type>]]
18  *
19  *   <package-name>      ::= !"-"{!"-"}
20  *
21  *   <version>           ::= <major>[["."<minor>[["."<patchlevel>]]]]
22  *
23  *   <major>             ::= "0".."9"{"0".."9"}
24  *   <minor>             ::= "0".."9"{"0".."9"}[[<suffix>]]
25  *   <patchlevel>        ::= "0".."9"{"0".."9"}[[<suffix>]]
26  *   <suffix>            ::= {!("0".."9"|"-"|".")}
27  *
28  *   <build-id>          ::= <datestamp>|<serial-number>{"-"<serial-number>}
29  *
30  *   <serial-number>     ::= "0".."9"{"0".."9"}
31  *   <datestamp>         ::= <serial-number> ; nominally 8 digit date as YYYYMMDD
32  *                                           ; (currently unenforced, however)
33  *
34  *   <system-name>       ::= !("0".."9"|"-"|"."){!("-"|".")}
35  *
36  *   <status>            ::= ("alpha"|"beta"|"stable")[[-<build-id>]]
37  *
38  *   <component-id>      ::= <component-class>[["-"<component-version>]]
39  *
40  *   <component-class>   ::= !("0".."9"|"-"|"."){!("-"|".")}
41  *   <component-version> ::= "0".."9"{!("-"|".")}
42  *
43  *   <format-type>       ::= !("-"|"."){!("-"|".")}
44  *   <compression-type>  ::= !("-"|"."){!("-"|".")}
45  *
46  * Notes:--
47  *
48  *   <format-type> is expected to take one of the nominal values from the set
49  *   "exe"|"tar"|"zip"; however, this is not enforced.
50  *
51  *   <compression-type> is expected to take one of the nominal values from the
52  *   set "bz2"|"gz"|"lzma"; however, this is similarly not enforced.
53  *
54  *   Additionally, "?" is used as a sentinel, and is not permitted *anywhere*
55  *   in <archive-name>; (possibly something like ASCII <ETX> would be a more
56  *   useful choice for this purpose.
57  *
58  *
59  * This is free software.  Permission is granted to copy, modify and
60  * redistribute this software, under the provisions of the GNU General
61  * Public License, Version 3, (or, at your option, any later version),
62  * as published by the Free Software Foundation; see the file COPYING
63  * for licensing details.
64  *
65  * Note, in particular, that this software is provided "as is", in the
66  * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
67  * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
68  * PARTICULAR PURPOSE.  Under no circumstances will the author, or the
69  * MinGW Project, accept liability for any damages, however caused,
70  * arising from the use of this software.
71  *
72  */
73 %option noyywrap
74 %option prefix="__pkginfo_"
75 %option case-insensitive
76
77 %x      TRANS FINAL
78
79 STATUS_KEYWORDS (alpha|beta|stable)
80
81     #include "pkginfo.h"
82     #define YY_DECL int yylex( int start, pkginfo_t signature, char *name )
83
84 %%
85
86     static int index, mark, phase;
87
88     if( start == PACKAGE_NAME )
89     {
90       /* Initialise for new package archive name...
91        * Clear all `signature' array slots, and set up
92        * to capture the <package-name> element.
93        */
94       BEGIN INITIAL;
95       phase = mark = 0;
96       for( index = PACKAGE_NAME; index < PACKAGE_TAG_COUNT; index++ )
97         signature[index] = NULL;
98       index = PACKAGE_NAME;
99       signature[PACKAGE_NAME] = name;
100     }
101
102 - { /*
103      * General case rule...
104      * Found the standard element separator, so initiate a transition.
105      */
106     BEGIN TRANS;
107     return yyleng;
108   }
109
110 [^-]* {
111     /* General case rule...
112      * Matched an arbitrary sequence of non-separators, so mark them;
113      * they will be appended to the current element.
114      */
115     return mark += yyleng;
116   }
117
118 <TRANS>{STATUS_KEYWORDS}- {
119     /*
120      * Transitional case rule...
121      * Identify a following package development <status> descriptor;
122      * revert to INITIAL state, to continue the <archive-name> scan.
123      */
124     BEGIN INITIAL;
125     if( index < PACKAGE_RELEASE_STATUS )
126     {
127       /* and, when the <status> descriptor is appropriately placed,
128        * set up `signature' storage to capture it, adjusting phase to
129        * detect a following <build-id>, (representing a release id).
130        */
131       name[mark] = '\0';
132       signature[index = PACKAGE_RELEASE_STATUS] = name + mark + 1;
133       phase = 1;
134     }
135     /* otherwise we simply ignore a misplaced <status> descriptor,
136      * but in either case, we continue the scan at the start of the
137      * apparent <status> descriptor, which has been detected.
138      */
139     ++mark;
140     yyless( 0 );
141   }
142
143 <TRANS>([%&*]|[^-0-9.][^-.]+)(-[0-9][^-.]*){0,1}(\.[^-.]+){1,2}\? {
144     /*
145      * Transitional case rule...
146      * Identify a following terminal <type-id> sequence; set up
147      * `signature' storage to capture it, and initiate FINAL phase
148      * of <archive-name> scan.
149      */
150     BEGIN FINAL;
151     phase = 0;
152     name[mark++] = '\0';
153     signature[index = PACKAGE_COMPONENT_CLASS] = name + mark;
154     yyless( 0 );
155   }
156
157 <TRANS>([%&*][.-])|([0-9]+[.-]) {
158     /*
159      * Transitional case rule...
160      * Found a purely numeric following element, such as a <major>
161      * version number field, or a <serial-number>.
162      */
163     BEGIN INITIAL;
164     if( ++phase < 3 )
165     {
166       /* For a version number element,
167        * terminate the preceding name element, and set up the
168        * `signature' table to capture the version number.
169        */
170       name[mark] = '\0';
171       signature[++index] = name + mark + 1;
172     }
173     /* For any other numeric element class,
174      * simply advance the position marker, and leave the content
175      * to be retrieved by a general (INITIAL) case rule.
176      */
177     ++mark;
178     yyless( 0 );
179   }
180
181 <TRANS>. {
182     /*
183      * Transitional case rule...
184      * Handle any other non-specific element type,
185      * found after an element delimiter.
186      */
187     BEGIN INITIAL;
188     if( phase )
189     {
190       /* When processing a <version> or <build-id> element,
191        * terminate it.
192        */
193       name[mark] = '\0';
194       if( phase < 2 )
195         /*
196          * ...and if we haven't reached a <build-id>, then
197          * there isn't one here; leave its pointer unassigned.
198          */
199         ++index;
200
201       /* Save pointer to next element,
202        * (which should be <subsystem-name>),
203        * and reset phase accordingly.
204        */
205       signature[++index] = name + mark + 1;
206       phase = 0;
207     }
208     /* Update element marker, and leave content to be scanned
209      * on return to the INITIAL state.
210      */
211     ++mark;
212     yyless( 0 );
213   }
214
215 <FINAL>\. {
216     /*
217      * Wrap up processing rule...
218      * Found a "." element separator, so move on to capture
219      * the next element of the <type-id>...
220      */
221     if( index < PACKAGE_COMPONENT_VERSION )
222       /*
223        * ...omitting the <component-version>, which has either
224        * been captured already, or isn't present.
225        */
226       ++index;
227     name[mark++] = '\0';
228     signature[++index] = name + mark;
229     return yyleng;
230   }
231
232 <FINAL>- {
233     /*
234      * Wrap up processing rule...
235      * Found a "-" element separator...
236      */
237     if( index == PACKAGE_COMPONENT_CLASS )
238     {
239       /* ...this should occur only to separate
240        * the <component-version> from the <component-class>;
241        * in this case, terminate the <component-class>, and
242        * prepare to capture the <component-version>.
243        */
244       name[mark++] = '\0';
245       signature[++index] = name + mark;
246     }
247     return yyleng;
248   }
249
250 <FINAL>[^.?-]* {
251     /*
252      * Wrap up processing rule...
253      * Found element content; adjust mark to its end.
254      */
255     return mark += yyleng;
256   }
257
258 <FINAL>\? {
259     /*
260      * Wrap up processing rule...
261      * Found the sentinel for the end of <archive-name>;
262      * delete it, and we should be done.
263      */
264     name[mark] = '\0';
265   }
266
267 %%
268
269 void *get_pkginfo( const char *name, pkginfo_t signature )
270 {
271   if( (*signature = malloc( strlen( name ) + 2)) != NULL )
272   {
273     int start = PACKAGE_NAME;
274     sprintf( *signature, "%s?", name );
275     yy_scan_string( *signature );
276     while( (start = yylex( start, signature, *signature )) > 0 )
277       ;
278     yy_delete_buffer( YY_CURRENT_BUFFER );
279   }
280   return *signature;
281 }
282
283 /* $RCSfile$: end of file */