From: Keith M. <kei...@us...> - 2009-10-12 21:35:37
|
Update of /cvsroot/mingw/mingw-get/src/pkginfo In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv21303/src/pkginfo Added Files: driver.c pkginfo.h pkginfo.l Log Message: Add pkginfo implementation --- NEW FILE: pkginfo.l --- /* * pkginfo.l * * $Id: pkginfo.l,v 1.1 2009/10/12 21:35:29 keithmarshall Exp $ * * Written by Keith Marshall <kei...@us...> * Copyright (C) 2009, MinGW Project * * * A simple lexical analyser for decomposing package archive names into their * constituent components. It implements the schema:-- * * <archive-name> ::= <package-id>[["-"<system-id>]][[-<status>]]"-"<type-id> * * <package-id> ::= <package-name>"-"<version>[["-"<build-id>]] * <system-id> ::= <system-name>[["-"<version>[["-"<build-id>]]]] * <type-id> ::= <component-id>"."<format-type>[["."<compression-type>]] * * <package-name> ::= !"-"{!"-"} * * <version> ::= <major>[["."<minor>[["."<patchlevel>]]]] * * <major> ::= "0".."9"{"0".."9"} * <minor> ::= "0".."9"{"0".."9"}[[<suffix>]] * <patchlevel> ::= "0".."9"{"0".."9"}[[<suffix>]] * <suffix> ::= {!("0".."9"|"-"|".")} * * <build-id> ::= <datestamp>|<serial-number>{"-"<serial-number>} * * <serial-number> ::= "0".."9"{"0".."9"} * <datestamp> ::= <serial-number> ; nominally 8 digit date as YYYYMMDD * ; (currently unenforced, however) * * <system-name> ::= !("0".."9"|"-"|"."){!("-"|".")} * * <status> ::= ("alpha"|"beta"|"stable")[[-<build-id>]] * * <component-id> ::= <component-class>[["-"<component-version>]] * * <component-class> ::= !("0".."9"|"-"|"."){!("-"|".")} * <component-version> ::= "0".."9"{!("-"|".")} * * <format-type> ::= !("-"|"."){!("-"|".")} * <compression-type> ::= !("-"|"."){!("-"|".")} * * Notes:-- * * <format-type> is expected to take one of the nominal values from the set * "exe"|"tar"|"zip"; however, this is not enforced. * * <compression-type> is expected to take one of the nominal values from the * set "bz2"|"gz"|"lzma"; however, this is similarly not enforced. * * Additionally, "?" is used as a sentinel, and is not permitted *anywhere* * in <archive-name>; (possibly something like ASCII <ETX> would be a more * useful choice for this purpose. * * * This is free software. Permission is granted to copy, modify and * redistribute this software, under the provisions of the GNU General * Public License, Version 3, (or, at your option, any later version), * as published by the Free Software Foundation; see the file COPYING * for licensing details. * * Note, in particular, that this software is provided "as is", in the * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY * PARTICULAR PURPOSE. Under no circumstances will the author, or the * MinGW Project, accept liability for any damages, however caused, * arising from the use of this software. * */ %option noyywrap %option prefix="__pkginfo_" %option case-insensitive %x TRANS FINAL STATUS_KEYWORDS (alpha|beta|stable) #include "pkginfo.h" #define YY_DECL int yylex( int start, pkginfo_t signature, char *name ) %% static int index, mark, phase; if( start == PACKAGE_NAME ) { /* Initialise for new package archive name... * Clear all `signature' array slots, and set up * to capture the <package-name> element. */ BEGIN INITIAL; phase = mark = 0; for( index = PACKAGE_NAME; index < PACKAGE_TAG_COUNT; index++ ) signature[index] = NULL; index = PACKAGE_NAME; signature[PACKAGE_NAME] = name; } - { /* * General case rule... * Found the standard element separator, so initiate a transition. */ BEGIN TRANS; return yyleng; } [^-]* { /* General case rule... * Matched an arbitrary sequence of non-separators, so mark them; * they will be appended to the current element. */ return mark += yyleng; } <TRANS>{STATUS_KEYWORDS}- { /* * Transitional case rule... * Identify a following package development <status> descriptor; * revert to INITIAL state, to continue the <archive-name> scan. */ BEGIN INITIAL; if( index < PACKAGE_RELEASE_STATUS ) { /* and, when the <status> descriptor is appropriately placed, * set up `signature' storage to capture it, adjusting phase to * detect a following <build-id>, (representing a release id). */ name[mark] = '\0'; signature[index = PACKAGE_RELEASE_STATUS] = name + mark + 1; phase = 1; } /* otherwise we simply ignore a misplaced <status> descriptor, * but in either case, we continue the scan at the start of the * apparent <status> descriptor, which has been detected. */ ++mark; yyless( 0 ); } <TRANS>([&*]|[^-0-9.][^-.]+)(-[0-9][^-.]*){0,1}(\.[^-.]+){1,2}\? { /* * Transitional case rule... * Identify a following terminal <type-id> sequence; set up * `signature' storage to capture it, and initiate FINAL phase * of <archive-name> scan. */ BEGIN FINAL; phase = 0; name[mark++] = '\0'; signature[index = PACKAGE_COMPONENT_CLASS] = name + mark; yyless( 0 ); } <TRANS>([&*][.-])|([0-9]+[.-]) { /* * Transitional case rule... * Found a purely numeric following element, such as a <major> * version number field, or a <serial-number>. */ BEGIN INITIAL; if( ++phase < 3 ) { /* For a version number element, * terminate the preceding name element, and set up the * `signature' table to capture the version number. */ name[mark] = '\0'; signature[++index] = name + mark + 1; } /* For any other numeric element class, * simply advance the position marker, and leave the content * to be retrieved by a general (INITIAL) case rule. */ ++mark; yyless( 0 ); } <TRANS>. { /* * Transitional case rule... * Handle any other non-specific element type, * found after an element delimiter. */ BEGIN INITIAL; if( phase ) { /* When processing a <version> or <build-id> element, * terminate it. */ name[mark] = '\0'; if( phase < 2 ) /* * ...and if we haven't reached a <build-id>, then * there isn't one here; leave its pointer unassigned. */ ++index; /* Save pointer to next element, * (which should be <subsystem-name>), * and reset phase accordingly. */ signature[++index] = name + mark + 1; phase = 0; } /* Update element marker, and leave content to be scanned * on return to the INITIAL state. */ ++mark; yyless( 0 ); } <FINAL>\. { /* * Wrap up processing rule... * Found a "." element separator, so move on to capture * the next element of the <type-id>... */ if( index < PACKAGE_COMPONENT_VERSION ) /* * ...omitting the <component-version>, which has either * been captured already, or isn't present. */ ++index; name[mark++] = '\0'; signature[++index] = name + mark; return yyleng; } <FINAL>- { /* * Wrap up processing rule... * Found a "-" element separator... */ if( index == PACKAGE_COMPONENT_CLASS ) { /* ...this should occur only to separate * the <component-version> from the <component-class>; * in this case, terminate the <component-class>, and * prepare to capture the <component-version>. */ name[mark++] = '\0'; signature[++index] = name + mark; } return yyleng; } <FINAL>[^.?-]* { /* * Wrap up processing rule... * Found element content; adjust mark to its end. */ return mark += yyleng; } <FINAL>\? { /* * Wrap up processing rule... * Found the sentinel for the end of <archive-name>; * delete it, and we should be done. */ name[mark] = '\0'; } %% void *get_pkginfo( const char *name, pkginfo_t signature ) { if( (*signature = malloc( strlen( name ) + 2)) != NULL ) { int start = PACKAGE_NAME; sprintf( *signature, "%s?", name ); yy_scan_string( *signature ); while( (start = yylex( start, signature, *signature )) > 0 ) ; yy_delete_buffer( YY_CURRENT_BUFFER ); } return *signature; } /* $RCSfile: pkginfo.l,v $: end of file */ --- NEW FILE: driver.c --- /* * driver.c * * $Id: driver.c,v 1.1 2009/10/12 21:35:29 keithmarshall Exp $ * * Written by Keith Marshall <kei...@us...> * Copyright (C) 2009, MinGW Project * * * Simple driver program, for the lexical package name analyser, as * implemented in the "flex" file "pkginfo.l". When compiled as: * * lex -t pkginfo.l > pkginfo.c * gcc -o pkginfo driver.c pkginfo.c * * it creates a simple command line tool for analysis and validation * of package archive names, in accordance with agreed MinGW Project * package naming conventions. * * * This is free software. Permission is granted to copy, modify and * redistribute this software, under the provisions of the GNU General * Public License, Version 3, (or, at your option, any later version), * as published by the Free Software Foundation; see the file COPYING * for licensing details. * * Note, in particular, that this software is provided "as is", in the * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY * PARTICULAR PURPOSE. Under no circumstances will the author, or the * MinGW Project, accept liability for any damages, however caused, * arising from the use of this software. * */ #include <stdio.h> #include "pkginfo.h" static __inline__ char *spec( char *tag ) { /* A local helper function... * Returns the content of `tag', if defined, * otherwise "<unspecified>". */ static char *unspecified = "<unspecified>"; if( tag == NULL ) return unspecified; return tag; } int main( int argc, char **argv ) { /* A trivial driver program, * to illustrate the behaviour of the "pkginfo" scanner. */ pkginfo_t tags = { /* * Labels to print, * identifying individual elements of a package tarname. */ "Package Name:", "Package Version:", "Package Build:", "Subsystem Name:", "Subsystem Version:", "Subsystem Build:", "Release Status:", "Release Reference:", "Component Type:", "Component Version:", "Archive Format:", "Compression Type" }, signature; /* Treating each command line argument as an individual * package tarball name... */ while( --argc ) { int start; void *refdata; /* ...analyse it... */ if( (refdata = get_pkginfo( *++argv, signature )) != NULL ) { /* ...and, on success, print its decomposition summary. */ for( start = PACKAGE_NAME; start < PACKAGE_TAG_COUNT; start++ ) printf( "%-19s%s\n", tags[start], spec( signature[start] ) ); /* To avoid memory leaks... * free the dynamic memory allocated by the scanner. */ free( refdata ); } } /* Trivially, always return success. */ return 0; } /* $RCSfile: driver.c,v $: end of file */ --- NEW FILE: pkginfo.h --- #ifndef PKGINFO_H /* * pkginfo.h * * $Id: pkginfo.h,v 1.1 2009/10/12 21:35:29 keithmarshall Exp $ * * Written by Keith Marshall <kei...@us...> * Copyright (C) 2009, MinGW Project * * * Public interface for the package tarname interpreter. Provides * type definitions and function prototypes for the "C" interpreter, * which is implemented as a "flex" scanner in file "pkginfo.l", to * be accessed via the "get_pkginfo()" function. * * When included by "C++" code, it also defines the interface * for the "pkgSpecs" class, which is used by the package manager, * for convenient evaluation and comparison of package attributes, * based on examination of the package tarname. * * * This is free software. Permission is granted to copy, modify and * redistribute this software, under the provisions of the GNU General * Public License, Version 3, (or, at your option, any later version), * as published by the Free Software Foundation; see the file COPYING * for licensing details. * * Note, in particular, that this software is provided "as is", in the * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY * PARTICULAR PURPOSE. Under no circumstances will the author, or the * MinGW Project, accept liability for any damages, however caused, * arising from the use of this software. * */ #define PKGINFO_H 1 enum { /* Symbolic names for the elements of an archive's tarname... */ PACKAGE_NAME = 0, /* the name of the package */ PACKAGE_VERSION, /* the version number of this release */ PACKAGE_BUILD, /* the build serial number */ PACKAGE_SUBSYSTEM_NAME, /* subsystem to which it belongs */ PACKAGE_SUBSYSTEM_VERSION, /* version of that subsystem */ PACKAGE_SUBSYSTEM_BUILD, /* subsystem build serial number */ PACKAGE_RELEASE_STATUS, /* package development status */ PACKAGE_RELEASE_INDEX, /* package release serial number */ PACKAGE_COMPONENT_CLASS, /* component type, e.g. bin, dll, dev */ PACKAGE_COMPONENT_VERSION, /* component version, e.g. of dll */ PACKAGE_FORMAT, /* package format, e.g. tar, zip, exe */ PACKAGE_COMPRESSION_TYPE, /* compression format, e.g. gz, bz2 */ PACKAGE_TAG_COUNT /* number of above element types */ }; /* * The "pkginfo_t" type describes a data structure, * (basically an array of pointers to character string elements), * in which each of the preceding package attributes is stored, * after extraction from the tarname, by "get_pkginfo()". */ typedef char *pkginfo_t[PACKAGE_TAG_COUNT]; #ifdef __cplusplus /* * The "get_pkginfo()" function offers a "C" language API... */ extern "C" #endif /* * ...it accepts a fully qualified package tarname as its first * argument, copies it to dynamically allocated memory, decomposes * this to the set of attributes enumerated above, and stores the * pointers to the individual attributes into the appropriate slots * within the "pkginfo_t" array referenced by the second argument, * whence the caller may retrieve the attribute values using the * enumerated attribute names to index the array. * * The return value is a pointer to the dynamically allocated memory * used to store the decomposition of the tarname, (or "NULL", if * the function fails); to avoid memory leaks, the caller should * call "free()" on this pointer, when the returned data is no * longer required. */ void *get_pkginfo( const char *, pkginfo_t ); #ifdef __cplusplus /* * "C++" applications may encapsulate the "C" language API within the * "pkgSpecs" class. This manages the "C" language memory allocation * internally, relieving the caller of the responsibility for freeing * allocated memory, and provides accessor and comparator methods for * retrieval and comparison of package attributes. */ #include <stdlib.h> /* for definition of NULL */ #include "pkgbase.h" /* for pkgXmlNode class declaration */ class pkgSpecs { private: /* Package attribute data retrieved from the "C" language API, * and automatically populated on class instantiation. */ pkginfo_t specs; /* pkginfo data array */ void *content; /* buffer to hold its content */ public: /* Constructors... */ pkgSpecs( const char* ); pkgSpecs( const pkgSpecs& ); pkgSpecs( pkgXmlNode* ); /* Destructor... */ ~pkgSpecs(); /* Operators... */ pkgSpecs& operator=( const pkgSpecs& ); /* Accessors... */ inline const char *GetPackageName(){ return specs[PACKAGE_NAME]; } inline const char *GetPackageVersion(){ return specs[PACKAGE_VERSION]; } inline const char *GetPackageBuild(){ return specs[PACKAGE_BUILD]; } inline const char *GetSubSystemName(){ return specs[PACKAGE_SUBSYSTEM_NAME]; } inline const char *GetSubSystemVersion(){ return specs[PACKAGE_SUBSYSTEM_VERSION]; } inline const char *GetSubSystemBuild(){ return specs[PACKAGE_SUBSYSTEM_BUILD]; } inline const char *GetReleaseStatus(){ return specs[PACKAGE_RELEASE_STATUS]; } inline const char *GetReleaseIndex(){ return specs[PACKAGE_RELEASE_INDEX]; } inline const char *GetComponentClass(){ return specs[PACKAGE_COMPONENT_CLASS]; } inline const char *GetComponentVersion(){ return specs[PACKAGE_COMPONENT_VERSION]; } inline const char *GetPackageFormat(){ return specs[PACKAGE_FORMAT]; } inline const char *GetCompressionType(){ return specs[PACKAGE_COMPRESSION_TYPE]; } /* Comparators... */ bool operator<( pkgSpecs& ); bool operator<=( pkgSpecs& ); bool operator==( pkgSpecs& ); bool operator>=( pkgSpecs& ); bool operator>( pkgSpecs& ); }; #endif /* __cplusplus */ #endif /* PKGINFO_H: $RCSfile: pkginfo.h,v $: end of file */ |