/*
** cdecl -- C gibberish translator
** src/c_sglob.c
**
** Copyright (C) 2021 Paul J. Lucas
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
*/
/**
* @file
* Defines functions for dealing with "sglob" (C++ scoped name glob) objects,
* e.g., `S::T::*`, that are used to match snames (C++ scoped names).
*/
// local
#include "pjl_config.h" /* must go first */
/// @cond DOXYGEN_IGNORE
#define C_SGLOB_INLINE _GL_EXTERN_INLINE
/// @endcond
#include "c_sglob.h"
// standard
#include
#include /* for free(3) */
////////// extern functions ///////////////////////////////////////////////////
void c_sglob_cleanup( c_sglob_t *sglob ) {
if ( sglob != NULL ) {
for ( size_t i = 0; i < sglob->count; ++i )
free( sglob->pattern[i] );
free( sglob->pattern );
c_sglob_init( sglob );
}
}
void c_sglob_parse( char const *s, c_sglob_t *sglob ) {
assert( sglob != NULL );
if ( s == NULL )
return;
SKIP_WS( s );
//
// Scan through the scoped glob to count the number of scopes which is the
// number of occurrences of `::` plus 1, e.g., `a::b::c` yields 3.
//
sglob->count = 1;
for ( char const *t = s; *t != '\0'; ++t ) {
if ( *t == ':' ) {
++t;
assert( *t == ':' );
++sglob->count;
}
} // for
//
// Special case: if the scoped glob starts with `**`, match in any scope.
// Skip past `**::` and decrement scope count.
//
sglob->match_in_any_scope = s[0] == '*' && s[1] == '*';
if ( sglob->match_in_any_scope ) {
s += 2 /* "**" */;
SKIP_WS( s );
assert( s[0] == ':' && s[1] == ':' );
s += 2 /* "::" */;
--sglob->count;
}
sglob->pattern = MALLOC( char*, sglob->count );
//
// Break up scoped glob into array of globs.
//
char const *glob_begin = SKIP_WS( s );
size_t glob_index = 0;
for (;;) {
switch ( *s ) {
case ':':
case '\0': { // found end of glob
size_t const glob_len = STATIC_CAST( size_t, s - glob_begin );
assert( glob_len > 0 );
assert( glob_index < sglob->count );
sglob->pattern[ glob_index ] = check_strndup( glob_begin, glob_len );
if ( *s == '\0' )
return;
assert( *s == ':' );
++s;
assert( *s == ':' );
++s;
SKIP_WS( s );
assert( is_ident( *s ) || *s == '*' );
glob_begin = s;
++glob_index;
break;
}
default:
assert( is_ident( *s ) );
PJL_FALLTHROUGH;
case '*':
++s;
break;
} // switch
} // for
}
///////////////////////////////////////////////////////////////////////////////
/* vim:set et sw=2 ts=2: */