2017-08-29 09:09:51 +00:00
/*
* $ Id $
*
2019-06-06 05:28:23 +00:00
Copyright ( c ) 2006 - 2019 Chung , Hyung - Hwan . All rights reserved .
2017-08-29 09:09:51 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
/*
* dict . c Routines to read the dictionary file .
*
* Version : $ Id $
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
*
* Copyright 2000 , 2006 The FreeRADIUS server project
*/
# include <qse/rad/raddic.h>
2017-12-13 08:21:13 +00:00
# include <qse/rad/radmsg.h>
2017-12-08 08:12:24 +00:00
# include <qse/cmn/htl.h>
2017-08-29 09:09:51 +00:00
# include <qse/cmn/str.h>
2017-12-13 08:21:13 +00:00
# include <qse/cmn/chr.h>
2017-12-14 04:08:10 +00:00
# include <qse/cmn/path.h>
2017-08-29 09:09:51 +00:00
# include "../cmn/mem-prv.h"
# include <qse/si/sio.h>
2017-12-13 08:21:13 +00:00
# include <stdarg.h>
typedef struct const_fixup_t const_fixup_t ;
struct const_fixup_t
{
const_fixup_t * next ;
qse_raddic_const_t * dval ;
2017-12-18 06:27:54 +00:00
qse_size_t line ;
qse_char_t * fn ;
2017-12-13 08:21:13 +00:00
qse_char_t attrstr [ 1 ] ;
} ;
2017-08-29 09:09:51 +00:00
struct qse_raddic_t
{
2017-12-13 08:21:13 +00:00
qse_mmgr_t * mmgr ;
qse_raddic_errnum_t errnum ;
qse_char_t errmsg [ 256 ] ;
qse_char_t errmsg2 [ 256 ] ;
struct
{
int trait ;
} opt ;
2017-08-29 09:09:51 +00:00
2017-12-08 08:12:24 +00:00
qse_htl_t vendors_byname ;
qse_htl_t vendors_byvalue ;
2017-12-11 10:02:49 +00:00
qse_htl_t attrs_byname ;
qse_htl_t attrs_byvalue ;
2017-12-12 07:27:17 +00:00
qse_htl_t consts_byvalue ;
qse_htl_t consts_byname ;
2017-11-30 05:46:42 +00:00
2017-12-11 10:02:49 +00:00
qse_raddic_attr_t * last_attr ;
qse_raddic_attr_t * base_attrs [ 256 ] ;
2017-12-13 08:21:13 +00:00
const_fixup_t * const_fixup ;
2017-08-29 09:09:51 +00:00
} ;
typedef struct name_id_t name_id_t ;
struct name_id_t
{
2017-12-13 08:21:13 +00:00
const qse_char_t * name ;
int id ;
2017-12-14 10:02:44 +00:00
int length ;
2017-08-29 09:09:51 +00:00
} ;
static const name_id_t type_table [ ] =
{
2017-12-14 10:02:44 +00:00
{ QSE_T ( " string " ) , QSE_RADDIC_ATTR_TYPE_STRING , - 1 } ,
{ QSE_T ( " octets " ) , QSE_RADDIC_ATTR_TYPE_OCTETS , - 1 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " ipaddr " ) , QSE_RADDIC_ATTR_TYPE_IPV4_ADDR , 4 } ,
{ QSE_T ( " ipv4prefix " ) , QSE_RADDIC_ATTR_TYPE_IPV4_PREFIX , - 1 } ,
{ QSE_T ( " ipv6addr " ) , QSE_RADDIC_ATTR_TYPE_IPV6_ADDR , 16 } ,
{ QSE_T ( " ipv6prefix " ) , QSE_RADDIC_ATTR_TYPE_IPV6_PREFIX , - 1 } ,
{ QSE_T ( " ifid " ) , QSE_RADDIC_ATTR_TYPE_IFID , 8 } ,
{ QSE_T ( " combo-ip " ) , QSE_RADDIC_ATTR_TYPE_COMBO_IP_ADDR , - 1 } ,
{ QSE_T ( " combo-prefix " ) , QSE_RADDIC_ATTR_TYPE_COMBO_IP_PREFIX , - 1 } ,
{ QSE_T ( " ether " ) , QSE_RADDIC_ATTR_TYPE_ETHERNET , 6 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " bool " ) , QSE_RADDIC_ATTR_TYPE_BOOL , 1 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " uint8 " ) , QSE_RADDIC_ATTR_TYPE_UINT8 , 1 } ,
{ QSE_T ( " uint16 " ) , QSE_RADDIC_ATTR_TYPE_UINT16 , 2 } ,
{ QSE_T ( " uint32 " ) , QSE_RADDIC_ATTR_TYPE_UINT32 , 4 } ,
{ QSE_T ( " uint64 " ) , QSE_RADDIC_ATTR_TYPE_UINT64 , 8 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " int8 " ) , QSE_RADDIC_ATTR_TYPE_INT8 , 1 } ,
{ QSE_T ( " int16 " ) , QSE_RADDIC_ATTR_TYPE_INT16 , 2 } ,
{ QSE_T ( " int32 " ) , QSE_RADDIC_ATTR_TYPE_INT32 , 4 } ,
{ QSE_T ( " int64 " ) , QSE_RADDIC_ATTR_TYPE_INT64 , 8 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " float32 " ) , QSE_RADDIC_ATTR_TYPE_FLOAT32 , 4 } ,
{ QSE_T ( " float64 " ) , QSE_RADDIC_ATTR_TYPE_FLOAT64 , 8 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " timeval " ) , QSE_RADDIC_ATTR_TYPE_TIMEVAL , - 1 } ,
{ QSE_T ( " date " ) , QSE_RADDIC_ATTR_TYPE_DATE , 4 } ,
{ QSE_T ( " date_milliseconds " ) , QSE_RADDIC_ATTR_TYPE_DATE_MILLISECONDS , - 1 } ,
{ QSE_T ( " date_microseconds " ) , QSE_RADDIC_ATTR_TYPE_DATE_MICROSECONDS , - 1 } ,
{ QSE_T ( " date_nanoseconds " ) , QSE_RADDIC_ATTR_TYPE_DATE_NANOSECONDS , - 1 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " abinary " ) , QSE_RADDIC_ATTR_TYPE_ABINARY , - 1 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " size " ) , QSE_RADDIC_ATTR_TYPE_SIZE , 8 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " tlv " ) , QSE_RADDIC_ATTR_TYPE_TLV , - 1 } ,
{ QSE_T ( " struct " ) , QSE_RADDIC_ATTR_TYPE_STRUCT , - 1 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " extended " ) , QSE_RADDIC_ATTR_TYPE_EXTENDED , 0 } ,
{ QSE_T ( " long-extended " ) , QSE_RADDIC_ATTR_TYPE_LONG_EXTENDED , 0 } ,
2017-12-14 04:08:10 +00:00
2017-12-14 10:02:44 +00:00
{ QSE_T ( " vsa " ) , QSE_RADDIC_ATTR_TYPE_VSA , - 1 } ,
{ QSE_T ( " evs " ) , QSE_RADDIC_ATTR_TYPE_EVS , - 1 } ,
{ QSE_T ( " vendor " ) , QSE_RADDIC_ATTR_TYPE_VENDOR , - 1 } ,
2017-12-14 04:08:10 +00:00
/*
* Alternative names
*/
2017-12-14 10:02:44 +00:00
{ QSE_T ( " cidr " ) , QSE_RADDIC_ATTR_TYPE_IPV4_PREFIX , - 1 } ,
{ QSE_T ( " byte " ) , QSE_RADDIC_ATTR_TYPE_UINT8 , 1 } ,
{ QSE_T ( " short " ) , QSE_RADDIC_ATTR_TYPE_UINT16 , 2 } ,
{ QSE_T ( " integer " ) , QSE_RADDIC_ATTR_TYPE_UINT32 , 4 } ,
{ QSE_T ( " integer64 " ) , QSE_RADDIC_ATTR_TYPE_UINT64 , 8 } ,
{ QSE_T ( " decimal " ) , QSE_RADDIC_ATTR_TYPE_FLOAT64 , 8 } ,
{ QSE_T ( " signed " ) , QSE_RADDIC_ATTR_TYPE_INT32 , 4 }
2017-08-29 09:09:51 +00:00
} ;
2017-12-13 08:21:13 +00:00
/* -------------------------------------------------------------------------- */
2017-12-14 10:02:44 +00:00
static int str_to_type ( qse_raddic_t * dic , const qse_char_t * name , int * length )
2017-12-13 08:21:13 +00:00
{
int i ;
for ( i = 0 ; i < QSE_COUNTOF ( type_table ) ; i + + )
{
2017-12-14 10:02:44 +00:00
if ( qse_strcmp ( name , type_table [ i ] . name ) = = 0 )
{
if ( length ) * length = type_table [ i ] . length ;
return type_table [ i ] . id ;
}
2017-12-13 08:21:13 +00:00
}
dic - > errnum = QSE_RADDIC_EINVAL ;
return - 1 ;
}
2017-12-11 10:02:49 +00:00
/* -------------------------------------------------------------------------- */
2017-12-08 08:12:24 +00:00
static qse_uint32_t dict_vendor_name_hash ( qse_htl_t * htl , const void * data )
2017-11-30 05:46:42 +00:00
{
2017-12-08 08:12:24 +00:00
return qse_strcasehash32 ( ( ( const qse_raddic_vendor_t * ) data ) - > name ) ;
2017-11-30 05:46:42 +00:00
}
2017-12-08 08:12:24 +00:00
static int dict_vendor_name_cmp ( qse_htl_t * htl , const void * one , const void * two )
2017-11-30 05:46:42 +00:00
{
2017-12-08 08:12:24 +00:00
const qse_raddic_vendor_t * a = one ;
const qse_raddic_vendor_t * b = two ;
return qse_strcasecmp ( a - > name , b - > name ) ;
}
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
static void dict_vendor_name_free ( qse_htl_t * htl , void * data )
2017-11-30 05:46:42 +00:00
{
2017-12-08 08:12:24 +00:00
QSE_MMGR_FREE ( htl - > mmgr , data ) ;
}
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
static qse_uint32_t dict_vendor_name_hetero_hash ( qse_htl_t * htl , const void * one )
2017-11-30 05:46:42 +00:00
{
2017-12-08 08:12:24 +00:00
return qse_strcasehash32 ( ( const qse_char_t * ) one ) ;
}
static int dict_vendor_name_hetero_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_vendor_t * b = two ;
return qse_strcasecmp ( ( const qse_char_t * ) one , b - > name ) ;
}
static qse_uint32_t dict_vendor_value_hash ( qse_htl_t * htl , const void * data )
{
const qse_raddic_vendor_t * v = ( const qse_raddic_vendor_t * ) data ;
return qse_genhash32 ( & v - > vendorpec , QSE_SIZEOF ( v - > vendorpec ) ) ;
}
static int dict_vendor_value_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_vendor_t * a = one ;
const qse_raddic_vendor_t * b = two ;
return a - > vendorpec - b - > vendorpec ;
}
2017-11-30 05:46:42 +00:00
2017-12-11 10:02:49 +00:00
/* -------------------------------------------------------------------------- */
static qse_uint32_t dict_attr_name_hash ( qse_htl_t * htl , const void * data )
{
return qse_strcasehash32 ( ( ( const qse_raddic_attr_t * ) data ) - > name ) ;
}
static int dict_attr_name_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_attr_t * a = one ;
const qse_raddic_attr_t * b = two ;
return qse_strcasecmp ( a - > name , b - > name ) ;
}
static void dict_attr_name_free ( qse_htl_t * htl , void * data )
{
QSE_MMGR_FREE ( htl - > mmgr , data ) ;
}
static qse_uint32_t dict_attr_name_hetero_hash ( qse_htl_t * htl , const void * one )
{
return qse_strcasehash32 ( ( const qse_char_t * ) one ) ;
}
static int dict_attr_name_hetero_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_attr_t * b = two ;
return qse_strcasecmp ( ( const qse_char_t * ) one , b - > name ) ;
}
static qse_uint32_t dict_attr_value_hash ( qse_htl_t * htl , const void * data )
{
const qse_raddic_attr_t * v = ( const qse_raddic_attr_t * ) data ;
qse_uint32_t hv ;
hv = qse_genhash32 ( & v - > vendor , QSE_SIZEOF ( v - > vendor ) ) ;
return qse_genhash32_update ( & v - > attr , QSE_SIZEOF ( v - > attr ) , hv ) ;
}
static int dict_attr_value_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_attr_t * a = one ;
const qse_raddic_attr_t * b = two ;
if ( a - > vendor < b - > vendor ) return - 1 ;
2017-12-12 07:27:17 +00:00
if ( a - > vendor > b - > vendor ) return 1 ;
2017-12-14 10:02:44 +00:00
if ( a - > attr < b - > attr ) return - 1 ;
if ( a - > attr > b - > attr ) return 1 ;
return 0 ;
2017-12-11 10:02:49 +00:00
}
/* -------------------------------------------------------------------------- */
2017-12-12 07:27:17 +00:00
struct const_hsd_t
{
const qse_char_t * name ;
2017-12-13 08:21:13 +00:00
qse_uint32_t attr ;
2017-12-12 07:27:17 +00:00
} ;
typedef struct const_hsd_t const_hsd_t ;
static qse_uint32_t dict_const_name_hash ( qse_htl_t * htl , const void * data )
{
qse_uint32_t hash ;
const qse_raddic_const_t * dval = data ;
hash = qse_strcasehash32 ( dval - > name ) ;
return qse_genhash32_update ( & dval - > attr , QSE_SIZEOF ( dval - > attr ) , hash ) ;
}
static int dict_const_name_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const qse_raddic_const_t * a = one ;
const qse_raddic_const_t * b = two ;
2017-12-14 04:08:10 +00:00
if ( a - > attr < b - > attr ) return - 1 ;
if ( a - > attr > b - > attr ) return 1 ;
2017-12-12 07:27:17 +00:00
return qse_strcasecmp ( a - > name , b - > name ) ;
}
static void dict_const_name_free ( qse_htl_t * htl , void * data )
{
QSE_MMGR_FREE ( htl - > mmgr , data ) ;
}
static qse_uint32_t dict_const_name_hetero_hash ( qse_htl_t * htl , const void * one )
{
qse_uint32_t hash ;
const const_hsd_t * hsd = ( const const_hsd_t * ) one ;
hash = qse_strcasehash32 ( hsd - > name ) ;
return qse_genhash32_update ( & hsd - > attr , QSE_SIZEOF ( hsd - > attr ) , hash ) ;
}
static int dict_const_name_hetero_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
const const_hsd_t * hsd = ( const const_hsd_t * ) one ;
const qse_raddic_const_t * b = ( const qse_raddic_const_t * ) two ;
2017-12-14 04:08:10 +00:00
if ( hsd - > attr < b - > attr ) return - 1 ;
if ( hsd - > attr > b - > attr ) return 1 ;
2017-12-12 07:27:17 +00:00
return qse_strcasecmp ( hsd - > name , b - > name ) ;
}
static qse_uint32_t dict_const_value_hash ( qse_htl_t * htl , const void * data )
{
qse_uint32_t hash ;
const qse_raddic_const_t * dval = data ;
hash = qse_genhash32 ( & dval - > attr , QSE_SIZEOF ( dval - > attr ) ) ;
return qse_genhash32_update ( & dval - > value , QSE_SIZEOF ( dval - > value ) , hash ) ;
}
static int dict_const_value_cmp ( qse_htl_t * htl , const void * one , const void * two )
{
2017-12-14 04:08:10 +00:00
const qse_raddic_const_t * a = one ;
const qse_raddic_const_t * b = two ;
2017-12-12 07:27:17 +00:00
2017-12-14 04:08:10 +00:00
if ( a - > attr < b - > attr ) return - 1 ;
if ( a - > attr > b - > attr ) return 1 ;
2017-12-12 07:27:17 +00:00
2017-12-18 06:27:54 +00:00
if ( a - > value < b - > value ) return - 1 ;
if ( a - > value > b - > value ) return 1 ;
2017-12-14 10:02:44 +00:00
2017-12-18 06:27:54 +00:00
return 0 ;
2017-12-12 07:27:17 +00:00
}
/* -------------------------------------------------------------------------- */
2017-08-29 09:09:51 +00:00
int qse_raddic_init ( qse_raddic_t * dic , qse_mmgr_t * mmgr )
{
2017-12-14 10:02:44 +00:00
int count = 0 ;
2017-08-29 09:09:51 +00:00
QSE_MEMSET ( dic , 0 , QSE_SIZEOF ( * dic ) ) ;
dic - > mmgr = mmgr ;
2017-12-13 08:21:13 +00:00
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOERR ) ;
2017-08-29 09:09:51 +00:00
2017-12-14 10:02:44 +00:00
if ( qse_htl_init ( & dic - > vendors_byname , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) | |
qse_htl_init ( & dic - > vendors_byvalue , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) | |
qse_htl_init ( & dic - > attrs_byname , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) | |
qse_htl_init ( & dic - > attrs_byvalue , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) | |
qse_htl_init ( & dic - > consts_byname , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) | |
qse_htl_init ( & dic - > consts_byvalue , mmgr , 1 ) < = - 1 | | ( + + count = = 0 ) )
{
goto oops ;
}
2017-12-08 08:12:24 +00:00
qse_htl_sethasher ( & dic - > vendors_byname , dict_vendor_name_hash ) ;
qse_htl_setcomper ( & dic - > vendors_byname , dict_vendor_name_cmp ) ;
qse_htl_setfreeer ( & dic - > vendors_byname , dict_vendor_name_free ) ;
qse_htl_sethasher ( & dic - > vendors_byvalue , dict_vendor_value_hash ) ;
qse_htl_setcomper ( & dic - > vendors_byvalue , dict_vendor_value_cmp ) ;
/* no freeer for dic->vendors_byvalue */
2017-08-29 09:09:51 +00:00
2017-12-11 10:02:49 +00:00
qse_htl_sethasher ( & dic - > attrs_byname , dict_attr_name_hash ) ;
qse_htl_setcomper ( & dic - > attrs_byname , dict_attr_name_cmp ) ;
qse_htl_setfreeer ( & dic - > attrs_byname , dict_attr_name_free ) ;
qse_htl_sethasher ( & dic - > attrs_byvalue , dict_attr_value_hash ) ;
qse_htl_setcomper ( & dic - > attrs_byvalue , dict_attr_value_cmp ) ;
/* no freeer for dic->attrs_byvalue */
2017-12-12 07:27:17 +00:00
qse_htl_sethasher ( & dic - > consts_byname , dict_const_name_hash ) ;
qse_htl_setcomper ( & dic - > consts_byname , dict_const_name_cmp ) ;
qse_htl_setfreeer ( & dic - > consts_byname , dict_const_name_free ) ;
qse_htl_sethasher ( & dic - > consts_byvalue , dict_const_value_hash ) ;
qse_htl_setcomper ( & dic - > consts_byvalue , dict_const_value_cmp ) ;
/* no freeer for dic->consts_byvalue */
2017-08-29 09:09:51 +00:00
return 0 ;
2017-12-14 10:02:44 +00:00
oops :
if ( count > = 6 ) qse_htl_fini ( & dic - > consts_byvalue ) ;
if ( count > = 5 ) qse_htl_fini ( & dic - > consts_byname ) ;
if ( count > = 4 ) qse_htl_fini ( & dic - > attrs_byvalue ) ;
if ( count > = 3 ) qse_htl_fini ( & dic - > attrs_byname ) ;
if ( count > = 2 ) qse_htl_fini ( & dic - > vendors_byvalue ) ;
if ( count > = 1 ) qse_htl_fini ( & dic - > vendors_byname ) ;
return - 1 ;
2017-08-29 09:09:51 +00:00
}
void qse_raddic_fini ( qse_raddic_t * dic )
{
2017-12-13 08:21:13 +00:00
qse_raddic_clear ( dic ) ;
2017-12-12 07:27:17 +00:00
qse_htl_fini ( & dic - > consts_byvalue ) ;
qse_htl_fini ( & dic - > consts_byname ) ;
2017-12-14 10:02:44 +00:00
qse_htl_fini ( & dic - > attrs_byvalue ) ;
qse_htl_fini ( & dic - > attrs_byname ) ;
qse_htl_fini ( & dic - > vendors_byvalue ) ;
qse_htl_fini ( & dic - > vendors_byname ) ;
2017-08-29 09:09:51 +00:00
}
qse_raddic_t * qse_raddic_open ( qse_mmgr_t * mmgr , qse_size_t xtnsize )
{
qse_raddic_t * dic ;
dic = ( qse_raddic_t * ) QSE_MMGR_ALLOC ( mmgr , QSE_SIZEOF ( qse_raddic_t ) + xtnsize ) ;
if ( dic )
{
if ( qse_raddic_init ( dic , mmgr ) < = - 1 )
{
QSE_MMGR_FREE ( mmgr , dic ) ;
return QSE_NULL ;
}
else QSE_MEMSET ( QSE_XTN ( dic ) , 0 , xtnsize ) ;
}
return dic ;
}
void qse_raddic_close ( qse_raddic_t * dic )
{
qse_raddic_fini ( dic ) ;
QSE_MMGR_FREE ( dic - > mmgr , dic ) ;
2017-12-08 08:12:24 +00:00
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
int qse_raddic_getopt ( qse_raddic_t * dic , qse_raddic_opt_t id , void * value )
{
switch ( id )
{
case QSE_RADDIC_TRAIT :
* ( int * ) value = dic - > opt . trait ;
return 0 ;
}
qse_raddic_seterrnum ( dic , QSE_RADDIC_EINVAL ) ;
return - 1 ;
}
int qse_raddic_setopt ( qse_raddic_t * dic , qse_raddic_opt_t id , const void * value )
{
switch ( id )
{
case QSE_RADDIC_TRAIT :
dic - > opt . trait = * ( const int * ) value ;
return 0 ;
}
qse_raddic_seterrnum ( dic , QSE_RADDIC_EINVAL ) ;
return - 1 ;
}
static const qse_char_t * errnum_to_str ( qse_raddic_errnum_t errnum )
{
static const qse_char_t * errstr [ ] =
{
QSE_T ( " no error " ) ,
QSE_T ( " other error " ) ,
QSE_T ( " not implemented " ) ,
QSE_T ( " subsystem error " ) ,
QSE_T ( " internal error that should never have happened " ) ,
QSE_T ( " insufficient memory " ) ,
QSE_T ( " invalid parameter or data " ) ,
QSE_T ( " no data found " ) ,
QSE_T ( " existing data found " ) ,
QSE_T ( " syntax error " )
} ;
return errnum < QSE_COUNTOF ( errstr ) ? errstr [ errnum ] : QSE_T ( " unknown error " ) ;
}
qse_raddic_errnum_t qse_raddic_geterrnum ( qse_raddic_t * dic )
{
return dic - > errnum ;
}
const qse_char_t * qse_raddic_geterrmsg ( qse_raddic_t * dic )
{
return dic - > errmsg ;
}
void qse_raddic_seterrnum ( qse_raddic_t * dic , qse_raddic_errnum_t errnum )
{
dic - > errnum = errnum ;
qse_strxcpy ( dic - > errmsg , QSE_COUNTOF ( dic - > errmsg ) , errnum_to_str ( errnum ) ) ;
}
void qse_raddic_seterrfmt ( qse_raddic_t * dic , qse_raddic_errnum_t errnum , const qse_char_t * fmt , . . . )
{
va_list ap ;
dic - > errnum = errnum ;
va_start ( ap , fmt ) ;
qse_strxvfmt ( dic - > errmsg , QSE_COUNTOF ( dic - > errmsg ) , fmt , ap ) ;
va_end ( ap ) ;
}
/* -------------------------------------------------------------------------- */
void qse_raddic_clear ( qse_raddic_t * dic )
{
int i ;
while ( dic - > const_fixup )
{
const_fixup_t * fixup = dic - > const_fixup ;
dic - > const_fixup = dic - > const_fixup - > next ;
QSE_MMGR_FREE ( dic - > mmgr , fixup - > dval ) ;
QSE_MMGR_FREE ( dic - > mmgr , fixup ) ;
}
dic - > last_attr = QSE_NULL ;
for ( i = 0 ; i < QSE_COUNTOF ( dic - > base_attrs ) ; i + + ) dic - > base_attrs [ i ] = QSE_NULL ;
qse_htl_clear ( & dic - > vendors_byname ) ;
qse_htl_clear ( & dic - > vendors_byvalue ) ;
qse_htl_clear ( & dic - > attrs_byname ) ;
qse_htl_clear ( & dic - > attrs_byvalue ) ;
qse_htl_clear ( & dic - > consts_byvalue ) ;
qse_htl_clear ( & dic - > consts_byname ) ;
}
2017-12-11 10:02:49 +00:00
/* -------------------------------------------------------------------------- */
2017-12-08 08:12:24 +00:00
qse_raddic_vendor_t * qse_raddic_findvendorbyname ( qse_raddic_t * dic , const qse_char_t * name )
{
qse_htl_node_t * np ;
np = qse_htl_heterosearch ( & dic - > vendors_byname , name , dict_vendor_name_hetero_hash , dict_vendor_name_hetero_cmp ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find a vendor named %s " ) , name ) ;
return QSE_NULL ;
}
2017-12-08 08:12:24 +00:00
return ( qse_raddic_vendor_t * ) np - > data ;
2017-08-29 09:09:51 +00:00
}
2017-12-08 08:12:24 +00:00
/*
* Return the vendor struct based on the PEC .
*/
2017-12-18 06:27:54 +00:00
qse_raddic_vendor_t * qse_raddic_findvendorbyvalue ( qse_raddic_t * dic , unsigned int vendorpec )
2017-12-08 08:12:24 +00:00
{
qse_htl_node_t * np ;
qse_raddic_vendor_t dv ;
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
dv . vendorpec = vendorpec ;
np = qse_htl_search ( & dic - > vendors_byvalue , & dv ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find a vendor of value %u " ) , vendorpec ) ;
2017-12-13 08:21:13 +00:00
return QSE_NULL ;
}
2017-12-08 08:12:24 +00:00
return ( qse_raddic_vendor_t * ) np - > data ;
}
2017-12-18 06:27:54 +00:00
qse_raddic_vendor_t * qse_raddic_addvendor ( qse_raddic_t * dic , const qse_char_t * name , unsigned int vendorpec )
2017-11-30 05:46:42 +00:00
{
qse_size_t length ;
2017-12-11 08:48:06 +00:00
qse_raddic_vendor_t * dv , * old_dv ;
2017-12-08 08:12:24 +00:00
qse_htl_node_t * np ;
2017-11-30 05:46:42 +00:00
2017-12-13 08:21:13 +00:00
if ( vendorpec < = 0 | | vendorpec > 65535 )
{
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " vendor value %u out of accepted range " ) , vendorpec ) ;
2017-12-13 08:21:13 +00:00
return QSE_NULL ;
}
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
length = qse_strlen ( name ) ;
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
/* no +1 for the terminating null because dv->name is char[1] */
dv = QSE_MMGR_ALLOC ( dic - > mmgr , QSE_SIZEOF ( * dv ) + ( length * QSE_SIZEOF ( * name ) ) ) ;
2017-12-13 08:21:13 +00:00
if ( dv = = QSE_NULL )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
return QSE_NULL ;
}
2017-12-11 08:48:06 +00:00
2017-11-30 05:46:42 +00:00
qse_strcpy ( dv - > name , name ) ;
2017-12-11 10:02:49 +00:00
dv - > vendorpec = vendorpec ;
2017-11-30 05:46:42 +00:00
dv - > type = dv - > length = 1 ; /* defaults */
2017-12-11 08:48:06 +00:00
dv - > nextv = QSE_NULL ;
2017-11-30 05:46:42 +00:00
2017-12-08 08:12:24 +00:00
/* return an existing item or insert a new item */
np = qse_htl_ensert ( & dic - > vendors_byname , dv ) ;
if ( ! np | | np - > data ! = dv )
2017-11-30 05:46:42 +00:00
{
2017-12-08 08:12:24 +00:00
/* insertion failure or existing item found */
2017-12-13 08:21:13 +00:00
if ( ! np ) qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
else qse_raddic_seterrfmt ( dic , QSE_RADDIC_EEXIST , QSE_T ( " existing vendor %s " ) , name ) ;
2017-12-08 08:12:24 +00:00
QSE_MMGR_FREE ( dic - > mmgr , dv ) ;
return QSE_NULL ;
2017-11-30 05:46:42 +00:00
}
2017-12-11 08:48:06 +00:00
/* attempt to update the lookup table by value */
np = qse_htl_upyank ( & dic - > vendors_byvalue , dv , ( void * * ) & old_dv ) ;
if ( np )
2017-12-08 08:12:24 +00:00
{
2017-12-11 08:48:06 +00:00
/* updated the existing item successfully.
* link the old item to the current item */
QSE_ASSERT ( np - > data = = dv ) ;
QSE_ASSERT ( dv - > vendorpec = = old_dv - > vendorpec ) ;
dv - > nextv = old_dv ;
}
else
{
/* update failure, this entry must be new. try insertion */
if ( ! qse_htl_insert ( & dic - > vendors_byvalue , dv ) )
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
2017-12-11 08:48:06 +00:00
qse_htl_delete ( & dic - > vendors_byname , dv ) ;
return QSE_NULL ;
}
2017-11-30 05:46:42 +00:00
}
2017-12-08 08:12:24 +00:00
return dv ;
2017-11-30 05:46:42 +00:00
}
2017-12-11 08:48:06 +00:00
int qse_raddic_deletevendorbyname ( qse_raddic_t * dic , const qse_char_t * name )
{
qse_raddic_vendor_t * dv , * dv2 ;
dv = qse_raddic_findvendorbyname ( dic , name ) ;
if ( ! dv ) return - 1 ;
dv2 = qse_raddic_findvendorbyvalue ( dic , dv - > vendorpec ) ;
QSE_ASSERT ( dv2 ! = QSE_NULL ) ;
if ( dv ! = dv2 )
{
qse_raddic_vendor_t * x , * y ;
QSE_ASSERT ( qse_strcasecmp ( dv - > name , dv2 - > name ) ! = 0 ) ;
QSE_ASSERT ( dv - > vendorpec = = dv2 - > vendorpec ) ;
/* when the vendor of the given name is not the first one
* referenced by value , i need to unlink the vendor from the
* vendor chains with the same ID */
x = dv2 ;
y = QSE_NULL ;
while ( x )
{
if ( x = = dv )
{
if ( y ) y - > nextv = x - > nextv ;
break ;
}
y = x ;
x = x - > nextv ;
}
}
else
{
/* this is the only vendor with the vendor ID. i can
* safely remove it from the lookup table by value */
qse_htl_delete ( & dic - > vendors_byvalue , dv ) ;
}
/* delete the vendor from the lookup table by name */
qse_htl_delete ( & dic - > vendors_byname , dv ) ;
return 0 ;
}
2017-12-18 06:27:54 +00:00
int qse_raddic_deletevendorbyvalue ( qse_raddic_t * dic , unsigned int vendorpec )
2017-12-11 08:48:06 +00:00
{
qse_raddic_vendor_t * dv ;
2017-12-11 10:02:49 +00:00
dv = qse_raddic_findvendorbyvalue ( dic , vendorpec ) ;
2017-12-11 08:48:06 +00:00
if ( ! dv ) return - 1 ;
if ( dv - > nextv )
{
qse_htl_update ( & dic - > vendors_byvalue , dv - > nextv ) ;
}
else
{
/* this is the only vendor with the vendor ID. i can
* safely remove it from the lookup table by value */
qse_htl_delete ( & dic - > vendors_byvalue , dv ) ;
}
/* delete the vendor from the lookup table by name */
qse_htl_delete ( & dic - > vendors_byname , dv ) ;
return 0 ;
}
2017-11-30 05:46:42 +00:00
2017-12-11 10:02:49 +00:00
/* -------------------------------------------------------------------------- */
qse_raddic_attr_t * qse_raddic_findattrbyname ( qse_raddic_t * dic , const qse_char_t * name )
{
qse_htl_node_t * np ;
np = qse_htl_heterosearch ( & dic - > attrs_byname , name , dict_attr_name_hetero_hash , dict_attr_name_hetero_cmp ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find an attribute named %s " ) , name ) ;
return QSE_NULL ;
}
2017-12-11 10:02:49 +00:00
return ( qse_raddic_attr_t * ) np - > data ;
}
2017-12-13 08:21:13 +00:00
qse_raddic_attr_t * qse_raddic_findattrbyvalue ( qse_raddic_t * dic , qse_uint32_t attr )
2017-12-11 10:02:49 +00:00
{
qse_htl_node_t * np ;
qse_raddic_attr_t dv ;
/* simple cache lookup for basic attributes */
if ( attr > = 0 & & attr < = 255 ) return dic - > base_attrs [ attr ] ;
dv . attr = attr ;
dv . vendor = QSE_RADDIC_ATTR_VENDOR ( attr ) ;
np = qse_htl_search ( & dic - > attrs_byvalue , & dv ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find an attribute of value %d and of vendor %d " ) , QSE_RADDIC_ATTR_VALUE ( attr ) , QSE_RADDIC_ATTR_VENDOR ( attr ) ) ;
return QSE_NULL ;
}
2017-12-11 10:02:49 +00:00
return ( qse_raddic_attr_t * ) np - > data ;
}
2017-12-18 06:27:54 +00:00
qse_raddic_attr_t * qse_raddic_addattr ( qse_raddic_t * dic , const qse_char_t * name , unsigned int vendor , qse_raddic_attr_type_t type , unsigned int value , const qse_raddic_attr_flags_t * flags )
2017-12-11 10:02:49 +00:00
{
qse_size_t length ;
qse_raddic_attr_t * dv , * old_dv ;
qse_htl_node_t * np ;
2017-12-18 06:27:54 +00:00
if ( vendor < 0 | | vendor > 65535u )
2017-12-13 08:21:13 +00:00
{
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " vendor %u out of accepted range " ) , vendor ) ;
2017-12-13 08:21:13 +00:00
return QSE_NULL ; /* 0 is allowed to mean no vendor */
}
2017-12-18 06:27:54 +00:00
if ( value < 0 | | value > 65535u )
2017-12-13 08:21:13 +00:00
{
/* the upper bound is not 255 because there are vendors defining values in 16-bit format */
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " attribute value %u out of accepted range " ) , value ) ;
2017-12-13 08:21:13 +00:00
return QSE_NULL ;
}
2017-12-11 10:02:49 +00:00
length = qse_strlen ( name ) ;
if ( vendor > 0 )
{
/* TODO: validation ... */
}
/* no +1 for the terminating null because dv->name is char[1] */
dv = QSE_MMGR_ALLOC ( dic - > mmgr , QSE_SIZEOF ( * dv ) + ( length * QSE_SIZEOF ( * name ) ) ) ;
2017-12-13 08:21:13 +00:00
if ( dv = = QSE_NULL )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
return QSE_NULL ;
}
2017-12-11 10:02:49 +00:00
qse_strcpy ( dv - > name , name ) ;
dv - > attr = QSE_RADDIC_ATTR_MAKE ( vendor , value ) ;
dv - > vendor = vendor ;
dv - > type = type ;
dv - > flags = * flags ;
dv - > nexta = QSE_NULL ;
/* return an existing item or insert a new item */
np = qse_htl_ensert ( & dic - > attrs_byname , dv ) ;
if ( ! np | | np - > data ! = dv )
{
/* insertion failure or existing item found */
2017-12-13 08:21:13 +00:00
if ( ! np ) qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
else qse_raddic_seterrfmt ( dic , QSE_RADDIC_EEXIST , QSE_T ( " existing attribute %s " ) , name ) ;
2017-12-11 10:02:49 +00:00
QSE_MMGR_FREE ( dic - > mmgr , dv ) ;
return QSE_NULL ;
}
/* attempt to update the lookup table by value */
np = qse_htl_upyank ( & dic - > attrs_byvalue , dv , ( void * * ) & old_dv ) ;
if ( np )
{
/* updated the existing item successfully.
* link the old item to the current item */
QSE_ASSERT ( np - > data = = dv ) ;
QSE_ASSERT ( dv - > attr = = old_dv - > attr ) ;
dv - > nexta = old_dv ;
}
else
{
/* update failure, this entry must be new. try insertion */
if ( ! qse_htl_insert ( & dic - > attrs_byvalue , dv ) )
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
2017-12-11 10:02:49 +00:00
qse_htl_delete ( & dic - > attrs_byname , dv ) ;
return QSE_NULL ;
}
}
2017-12-13 08:21:13 +00:00
if ( vendor = = 0 & & value < = 255 ) dic - > base_attrs [ value ] = dv ; /* cache a base attribute */
2017-12-11 10:02:49 +00:00
return dv ;
}
int qse_raddic_deleteattrbyname ( qse_raddic_t * dic , const qse_char_t * name )
{
qse_raddic_attr_t * dv , * dv2 ;
dv = qse_raddic_findattrbyname ( dic , name ) ;
if ( ! dv ) return - 1 ;
dv2 = qse_raddic_findattrbyvalue ( dic , dv - > attr ) ;
QSE_ASSERT ( dv2 ! = QSE_NULL ) ;
if ( dv ! = dv2 )
{
qse_raddic_attr_t * x , * y ;
QSE_ASSERT ( qse_strcasecmp ( dv - > name , dv2 - > name ) ! = 0 ) ;
QSE_ASSERT ( dv - > attr = = dv2 - > attr ) ;
QSE_ASSERT ( dv - > vendor = = dv2 - > vendor ) ;
2017-12-12 03:17:02 +00:00
/* when the attribute of the given name is not the first one
2017-12-11 10:02:49 +00:00
* referenced by value , i need to unlink the attr from the
* attr chains with the same ID */
x = dv2 ;
y = QSE_NULL ;
while ( x )
{
if ( x = = dv )
{
if ( y ) y - > nexta = x - > nexta ;
break ;
}
y = x ;
x = x - > nexta ;
}
2017-12-12 03:17:02 +00:00
/* no need to update cache as the deleted item was not the first one formerly */
2017-12-11 10:02:49 +00:00
}
else
{
/* this is the only attr with the attr ID. i can
* safely remove it from the lookup table by value */
2017-12-12 07:27:17 +00:00
if ( dv = = dic - > last_attr ) dic - > last_attr = QSE_NULL ;
2017-12-12 03:17:02 +00:00
if ( dv - > vendor = = 0 )
{
/* update the cache first */
dic - > base_attrs [ dv - > vendor ] = QSE_NULL ;
}
2017-12-11 10:02:49 +00:00
qse_htl_delete ( & dic - > attrs_byvalue , dv ) ;
}
/* delete the attr from the lookup table by name */
qse_htl_delete ( & dic - > attrs_byname , dv ) ;
return 0 ;
}
2017-12-14 10:02:44 +00:00
int qse_raddic_deleteattrbyvalue ( qse_raddic_t * dic , qse_uint32_t attr )
2017-12-11 10:02:49 +00:00
{
qse_raddic_attr_t * dv ;
dv = qse_raddic_findattrbyvalue ( dic , attr ) ;
if ( ! dv ) return - 1 ;
2017-12-12 03:17:02 +00:00
QSE_ASSERT ( QSE_RADDIC_ATTR_VENDOR ( attr ) = = dv - > vendor ) ;
if ( QSE_RADDIC_ATTR_VENDOR ( attr ) = = 0 )
{
/* update the cache */
2017-12-12 07:27:17 +00:00
if ( dv = = dic - > last_attr ) dic - > last_attr = QSE_NULL ;
2017-12-12 03:17:02 +00:00
dic - > base_attrs [ QSE_RADDIC_ATTR_VALUE ( attr ) ] = dv - > nexta ;
}
2017-12-11 10:02:49 +00:00
if ( dv - > nexta )
{
qse_htl_update ( & dic - > attrs_byvalue , dv - > nexta ) ;
}
else
{
/* this is the only attr with the attr ID. i can
* safely remove it from the lookup table by value */
qse_htl_delete ( & dic - > attrs_byvalue , dv ) ;
}
/* delete the attr from the lookup table by name */
qse_htl_delete ( & dic - > attrs_byname , dv ) ;
return 0 ;
}
/* -------------------------------------------------------------------------- */
2017-12-13 08:21:13 +00:00
qse_raddic_const_t * qse_raddic_findconstbyname ( qse_raddic_t * dic , qse_uint32_t attr , const qse_char_t * name )
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
qse_htl_node_t * np ;
const_hsd_t hsd ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
hsd . name = name ;
hsd . attr = attr ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
np = qse_htl_heterosearch ( & dic - > consts_byname , & hsd . name , dict_const_name_hetero_hash , dict_const_name_hetero_cmp ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find a constant named %s " ) , name ) ;
return QSE_NULL ;
}
2017-12-12 07:27:17 +00:00
return ( qse_raddic_const_t * ) np - > data ;
2017-11-30 05:46:42 +00:00
}
2017-12-18 06:27:54 +00:00
qse_raddic_const_t * qse_raddic_findconstbyvalue ( qse_raddic_t * dic , qse_uint32_t attr , qse_uintmax_t value )
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
qse_htl_node_t * np ;
qse_raddic_const_t dval ;
2017-11-30 05:46:42 +00:00
dval . attr = attr ;
2017-12-18 06:27:54 +00:00
dval . value = value ;
2017-12-12 07:27:17 +00:00
np = qse_htl_search ( & dic - > consts_byvalue , & dval ) ;
2017-12-13 08:21:13 +00:00
if ( ! np )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOENT , QSE_T ( " cannot find a constant valued %d " ) , value ) ;
return QSE_NULL ;
}
2017-12-12 07:27:17 +00:00
return ( qse_raddic_const_t * ) np - > data ;
2017-11-30 05:46:42 +00:00
}
2017-12-18 06:27:54 +00:00
static qse_raddic_const_t * __add_const ( qse_raddic_t * dic , qse_raddic_const_t * dval )
{
qse_htl_node_t * np ;
qse_raddic_const_t * old_dval ;
/* return an existing item or insert a new item */
np = qse_htl_ensert ( & dic - > consts_byname , dval ) ;
if ( ! np | | np - > data ! = dval )
{
/* insertion failure or existing item found */
if ( ! np )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
}
else
{
if ( ( dic - > opt . trait & QSE_RADDIC_ALLOW_DUPLICATE_CONST ) & &
( ( qse_raddic_const_t * ) np - > data ) - > value = = dval - > value )
{
QSE_MMGR_FREE ( dic - > mmgr , dval ) ;
return np - > data ;
}
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EEXIST , QSE_T ( " existing constant %s " ) , dval - > name ) ;
}
QSE_MMGR_FREE ( dic - > mmgr , dval ) ;
return QSE_NULL ;
}
/* attempt to update the lookup table by value */
np = qse_htl_upyank ( & dic - > consts_byvalue , dval , ( void * * ) & old_dval ) ;
if ( np )
{
/* updated the existing item successfully.
* link the old item to the current item */
QSE_ASSERT ( np - > data = = dval ) ;
QSE_ASSERT ( dval - > value = = old_dval - > value ) ;
dval - > nextc = old_dval ;
}
else
{
/* update failure, this entry must be new. try insertion */
if ( ! qse_htl_insert ( & dic - > consts_byvalue , dval ) )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
qse_htl_delete ( & dic - > consts_byname , dval ) ;
return QSE_NULL ;
}
}
return dval ;
}
static qse_raddic_const_t * add_const ( qse_raddic_t * dic , const qse_char_t * name , const qse_char_t * attrstr , qse_uintmax_t value , const qse_char_t * fn , qse_size_t line )
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
qse_size_t length ;
2017-12-18 06:27:54 +00:00
qse_raddic_const_t * dval ;
2017-12-12 07:27:17 +00:00
qse_raddic_attr_t * dattr ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
length = qse_strlen ( name ) ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
/* no +1 for the terminating null because dval->name is char[1] */
dval = QSE_MMGR_ALLOC ( dic - > mmgr , QSE_SIZEOF ( * dval ) + ( length * QSE_SIZEOF ( * name ) ) ) ;
2017-12-13 08:21:13 +00:00
if ( dval = = QSE_NULL )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
return QSE_NULL ;
}
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
qse_strcpy ( dval - > name , name ) ;
2017-12-18 06:27:54 +00:00
dval - > value = value ;
2017-12-12 07:27:17 +00:00
dval - > nextc = QSE_NULL ;
2017-11-30 05:46:42 +00:00
/*
* Most VALUEs are bunched together by ATTRIBUTE . We can
* save a lot of lookups on dictionary initialization by
* caching the last attribute .
*/
2017-12-12 07:27:17 +00:00
if ( dic - > last_attr & & qse_strcasecmp ( attrstr , dic - > last_attr - > name ) = = 0 )
2017-11-30 05:46:42 +00:00
{
dattr = dic - > last_attr ;
}
else
{
2017-12-12 07:27:17 +00:00
dattr = qse_raddic_findattrbyname ( dic , attrstr ) ;
2017-11-30 05:46:42 +00:00
dic - > last_attr = dattr ;
}
/*
2017-12-12 07:27:17 +00:00
* Remember which attribute is associated with this value , if possible .
2017-11-30 05:46:42 +00:00
*/
if ( dattr )
{
2017-12-18 06:27:54 +00:00
#if 0
2017-12-14 10:02:44 +00:00
if ( dattr - > type ! = value - > type )
2017-11-30 05:46:42 +00:00
{
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " conflicts between attribute type(%d) and constant value type(%d) " ) , ( int ) dattr - > type , ( int ) value - > type ) ;
2017-12-12 07:27:17 +00:00
return QSE_NULL ;
2017-11-30 05:46:42 +00:00
}
2017-12-18 06:27:54 +00:00
# endif
2017-11-30 05:46:42 +00:00
dval - > attr = dattr - > attr ;
switch ( dattr - > type )
{
2017-12-18 06:27:54 +00:00
case QSE_RADDIC_ATTR_TYPE_UINT8 :
if ( value < QSE_TYPE_MIN ( qse_uint8_t ) | | value > QSE_TYPE_MAX ( qse_uint8_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_UINT16 :
if ( value < QSE_TYPE_MIN ( qse_uint16_t ) | | value > QSE_TYPE_MAX ( qse_uint16_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_UINT32 :
if ( value < QSE_TYPE_MIN ( qse_uint32_t ) | | value > QSE_TYPE_MAX ( qse_uint32_t ) ) goto wrong_value ;
2017-11-30 05:46:42 +00:00
break ;
2017-12-12 07:27:17 +00:00
2017-12-18 06:27:54 +00:00
case QSE_RADDIC_ATTR_TYPE_UINT64 :
if ( value < QSE_TYPE_MIN ( qse_uint64_t ) | | value > QSE_TYPE_MAX ( qse_uint64_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_INT8 :
if ( value < QSE_TYPE_MIN ( qse_int8_t ) | | value > QSE_TYPE_MAX ( qse_int8_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_INT16 :
if ( value < QSE_TYPE_MIN ( qse_int16_t ) | | value > QSE_TYPE_MAX ( qse_int16_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_INT32 :
if ( value < QSE_TYPE_MIN ( qse_int32_t ) | | value > QSE_TYPE_MAX ( qse_int32_t ) ) goto wrong_value ;
break ;
case QSE_RADDIC_ATTR_TYPE_INT64 :
if ( value < QSE_TYPE_MIN ( qse_int64_t ) | | value > QSE_TYPE_MAX ( qse_int64_t ) ) goto wrong_value ;
2017-11-30 05:46:42 +00:00
break ;
/*
* Allow octets for now , because
* of dictionary . cablelabs
*/
2017-12-11 10:02:49 +00:00
case QSE_RADDIC_ATTR_TYPE_OCTETS :
2017-11-30 05:46:42 +00:00
break ;
2017-12-12 07:27:17 +00:00
default : /* cannot define VALUE for other types */
wrong_value :
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " value %jd for a constant %s not allowed for an attribute %s of type %d " ) , value , name , attrstr , ( int ) dattr - > type ) ;
2017-12-12 07:27:17 +00:00
QSE_MMGR_FREE ( dic - > mmgr , dval ) ;
return QSE_NULL ;
2017-11-30 05:46:42 +00:00
}
2017-12-18 06:27:54 +00:00
2017-11-30 05:46:42 +00:00
dattr - > flags . has_value = 1 ;
}
2017-12-12 07:27:17 +00:00
else
2017-11-30 05:46:42 +00:00
{
2017-12-18 06:27:54 +00:00
if ( fn & & ( dic - > opt . trait & QSE_RADDIC_ALLOW_CONST_WITHOUT_ATTR ) )
2017-12-13 08:21:13 +00:00
{
const_fixup_t * fixup ;
2017-12-18 06:27:54 +00:00
qse_size_t attrstrlen , fnlen ;
2017-12-13 08:21:13 +00:00
2017-12-18 06:27:54 +00:00
attrstrlen = qse_strlen ( attrstr ) ;
fnlen = qse_strlen ( fn ) ;
/* TODO: don't copy fn again and again */
fixup = QSE_MMGR_ALLOC ( dic - > mmgr , QSE_SIZEOF ( * fixup ) + ( ( attrstrlen + fnlen + 1 ) * QSE_SIZEOF ( * attrstr ) ) ) ;
2017-12-13 08:21:13 +00:00
if ( ! fixup )
{
qse_raddic_seterrnum ( dic , QSE_RADDIC_ENOMEM ) ;
QSE_MMGR_FREE ( dic - > mmgr , dval ) ;
return QSE_NULL ;
}
QSE_MEMSET ( fixup , 0 , QSE_SIZEOF ( * fixup ) ) ;
qse_strcpy ( fixup - > attrstr , attrstr ) ;
fixup - > dval = dval ;
fixup - > next = dic - > const_fixup ;
2017-12-18 06:27:54 +00:00
fixup - > line = line ;
fixup - > fn = fixup - > attrstr + attrstrlen + 1 ;
qse_strcpy ( fixup - > fn , fn ) ; /* TODO: don't copy fn again and again */
2017-12-13 08:21:13 +00:00
dic - > const_fixup = fixup ;
return dval ; /* this is not complete */
}
else
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_EINVAL , QSE_T ( " attribute %s not found for a constant " ) , attrstr , name ) ;
QSE_MMGR_FREE ( dic - > mmgr , dval ) ;
return QSE_NULL ;
}
2017-12-12 07:27:17 +00:00
}
2017-11-30 05:46:42 +00:00
2017-12-18 06:27:54 +00:00
return __add_const ( dic , dval ) ;
}
2017-11-30 05:46:42 +00:00
2017-12-18 06:27:54 +00:00
qse_raddic_const_t * qse_raddic_addconst ( qse_raddic_t * dic , const qse_char_t * name , const qse_char_t * attrstr , qse_uintmax_t value )
{
return add_const ( dic , name , attrstr , value , QSE_NULL , 0 ) ;
2017-12-12 07:27:17 +00:00
}
2017-11-30 05:46:42 +00:00
2017-12-13 08:21:13 +00:00
int qse_raddic_deleteconstbyname ( qse_raddic_t * dic , qse_uint32_t attr , const qse_char_t * name )
2017-12-12 07:27:17 +00:00
{
qse_raddic_const_t * dv , * dv2 ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
dv = qse_raddic_findconstbyname ( dic , attr , name ) ;
if ( ! dv ) return - 1 ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
QSE_ASSERT ( attr = = dv - > attr ) ;
2017-12-18 06:27:54 +00:00
dv2 = qse_raddic_findconstbyvalue ( dic , attr , dv - > value ) ;
2017-12-12 07:27:17 +00:00
QSE_ASSERT ( dv2 ! = QSE_NULL ) ;
if ( dv ! = dv2 )
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
qse_raddic_const_t * x , * y ;
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
QSE_ASSERT ( qse_strcasecmp ( dv - > name , dv2 - > name ) ! = 0 ) ;
2017-12-18 06:27:54 +00:00
QSE_ASSERT ( dv - > value = = dv2 - > value ) ;
2017-12-12 07:27:17 +00:00
QSE_ASSERT ( dv - > attr = = dv2 - > attr ) ;
/* when the constibute of the given name is not the first one
* referenced by value , i need to unlink the const from the
* const chains with the same ID */
x = dv2 ;
y = QSE_NULL ;
while ( x )
{
if ( x = = dv )
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
if ( y ) y - > nextc = x - > nextc ;
break ;
2017-11-30 05:46:42 +00:00
}
2017-12-12 07:27:17 +00:00
y = x ;
x = x - > nextc ;
2017-11-30 05:46:42 +00:00
}
2017-12-12 07:27:17 +00:00
/* no need to update cache as the deleted item was not the first one formerly */
2017-11-30 05:46:42 +00:00
}
2017-12-12 07:27:17 +00:00
else
2017-11-30 05:46:42 +00:00
{
2017-12-12 07:27:17 +00:00
/* this is the only const with the const ID. i can
* safely remove it from the lookup table by value */
qse_htl_delete ( & dic - > consts_byvalue , dv ) ;
2017-11-30 05:46:42 +00:00
}
2017-12-12 07:27:17 +00:00
/* delete the const from the lookup table by name */
qse_htl_delete ( & dic - > consts_byname , dv ) ;
2017-11-30 05:46:42 +00:00
return 0 ;
}
2017-12-18 06:27:54 +00:00
int qse_raddic_deleteconstbyvalue ( qse_raddic_t * dic , qse_uint32_t attr , qse_uintmax_t value )
2017-12-12 07:27:17 +00:00
{
qse_raddic_const_t * dv ;
dv = qse_raddic_findconstbyvalue ( dic , attr , value ) ;
if ( ! dv ) return - 1 ;
if ( dv - > nextc )
{
qse_htl_update ( & dic - > consts_byvalue , dv - > nextc ) ;
}
else
{
/* this is the only const with the const ID. i can
* safely remove it from the lookup table by value */
qse_htl_delete ( & dic - > consts_byvalue , dv ) ;
}
/* delete the const from the lookup table by name */
qse_htl_delete ( & dic - > consts_byname , dv ) ;
return 0 ;
}
2017-11-30 05:46:42 +00:00
2017-12-12 07:27:17 +00:00
/* -------------------------------------------------------------------------- */
2017-11-30 05:46:42 +00:00
2017-12-13 08:21:13 +00:00
static int str2argv ( qse_char_t * str , qse_char_t * argv [ ] , int max_argc )
2017-08-29 09:09:51 +00:00
{
int nflds , i ;
2017-11-30 05:46:42 +00:00
qse_char_t * ptr ;
2017-08-29 09:09:51 +00:00
2017-11-30 05:46:42 +00:00
nflds = qse_strspl ( str , QSE_T ( " " ) , QSE_T ( ' \0 ' ) , QSE_T ( ' \0 ' ) , QSE_T ( ' \0 ' ) ) ;
2017-12-13 08:21:13 +00:00
if ( nflds < = 0 ) return - 1 ;
2017-08-29 09:09:51 +00:00
ptr = str ;
for ( i = 0 ; i < nflds ; i + + )
{
argv [ i ] = ptr ;
2017-11-30 05:46:42 +00:00
while ( * ptr ! = QSE_T ( ' \0 ' ) ) ptr + + ;
2017-08-29 09:09:51 +00:00
ptr + + ;
}
return nflds ;
}
2017-12-13 08:21:13 +00:00
static int sscanf_i ( qse_raddic_t * dic , const qse_char_t * str , int * pvalue )
2017-11-30 05:46:42 +00:00
{
qse_long_t v ;
const qse_char_t * end ;
2017-12-14 10:02:44 +00:00
2017-12-18 07:20:02 +00:00
v = qse_strtolong ( str , 0 , & end ) ;
2017-12-13 08:21:13 +00:00
if ( * end ! = ' \0 ' )
2017-08-29 09:09:51 +00:00
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " invalid number - %s " ) , str ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-13 08:21:13 +00:00
* pvalue = v ;
2017-08-29 09:09:51 +00:00
return 0 ;
}
2017-12-18 06:27:54 +00:00
static int sscanf_ui ( qse_raddic_t * dic , const qse_char_t * str , qse_uintmax_t * pvalue )
{
qse_uintmax_t v ;
const qse_char_t * end ;
if ( ! QSE_ISDIGIT ( * str ) & & * str ! = QSE_T ( ' + ' ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " invalid unsigned number - %s " ) , str ) ;
return - 1 ;
}
2017-12-18 07:20:02 +00:00
/*QSE_STRTONUM (v, str, &end, 0);*/
v = qse_strtouintmax ( str , 0 , & end ) ;
if ( * end ! = QSE_T ( ' \0 ' ) )
2017-12-18 06:27:54 +00:00
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " invalid unsigned number - %s " ) , str ) ;
return - 1 ;
}
* pvalue = v ;
return 0 ;
}
2017-12-18 07:20:02 +00:00
#if 0
2017-12-14 10:02:44 +00:00
static int sscanf_ui32 ( qse_raddic_t * dic , const qse_char_t * str , qse_uint32_t * pvalue , qse_uint32_t * pvalue2 )
{
qse_long_t v , v2 ;
const qse_char_t * end ;
const qse_char_t * start2 = QSE_NULL ;
if ( ! QSE_ISDIGIT ( * str ) & & * str ! = QSE_T ( ' + ' ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " invalid unsigned number - %s " ) , str ) ;
return - 1 ;
}
2017-12-18 07:20:02 +00:00
/*QSE_STRTONUM (v, str, &end, 0);*/
v = qse_strtolong ( str , 0 , & end ) ;
2017-12-18 07:28:17 +00:00
if ( pvalue2 & & * end = = QSE_T ( ' . ' ) )
2017-12-14 10:02:44 +00:00
{
start2 = end + 1 ;
2017-12-18 07:20:02 +00:00
/*QSE_STRTONUM (v2, start2, &end, 0);*/
v2 = qse_strtolong ( start2 , 0 , & end ) ;
2017-12-14 10:02:44 +00:00
}
if ( * end ! = ' \0 ' )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " invalid unsigned number - %s " ) , str ) ;
return - 1 ;
}
* pvalue = v ;
if ( start2 )
{
* pvalue2 = v2 ;
return ( int ) ( end - start2 ) ; /* the value must not be very long. so i cast it to 'int' */
}
return 0 ;
}
2017-12-18 07:20:02 +00:00
# endif
2017-12-14 10:02:44 +00:00
2017-12-12 07:27:17 +00:00
/*
* Process the ATTRIBUTE command
*/
static int process_attribute (
2017-12-13 08:21:13 +00:00
qse_raddic_t * dic , const qse_char_t * fn , const qse_size_t line ,
int block_vendor , qse_raddic_attr_t * block_tlv , qse_char_t * * argv , int argc )
2017-08-29 09:09:51 +00:00
{
2017-12-18 06:27:54 +00:00
unsigned int vendor = 0 ;
qse_uintmax_t value ;
2017-12-13 08:21:13 +00:00
int type ;
qse_raddic_attr_flags_t flags ;
2017-12-14 10:02:44 +00:00
qse_char_t * p ;
int typelen = - 1 ;
2017-12-13 08:21:13 +00:00
if ( ( argc < 3 ) | | ( argc > 4 ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid ATTRIBUTE line " ) , fn , line ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-14 10:02:44 +00:00
QSE_MEMSET ( & flags , 0 , QSE_SIZEOF ( flags ) ) ;
2017-08-29 09:09:51 +00:00
/*
2017-12-12 07:27:17 +00:00
* Validate all entries
2017-08-29 09:09:51 +00:00
*/
2017-12-18 06:27:54 +00:00
if ( sscanf_ui ( dic , argv [ 1 ] , & value ) < = - 1 | | value > QSE_TYPE_MAX ( qse_uint16_t ) )
2017-08-29 09:09:51 +00:00
{
2017-12-18 07:20:02 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid attribute value %s " ) , fn , line , argv [ 1 ] ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-12 07:27:17 +00:00
/*
* find the type of the attribute .
*/
2017-12-14 10:02:44 +00:00
p = qse_strchr ( argv [ 2 ] , QSE_T ( ' [ ' ) ) ; /* for instance, octets[20] */
if ( p )
{
qse_char_t * q ;
* p = QSE_T ( ' \0 ' ) ;
q = qse_strchr ( p + 1 , QSE_T ( ' ] ' ) ) ;
if ( ! q | | q [ 1 ] ! = QSE_T ( ' \0 ' ) )
{
* p = QSE_T ( ' [ ' ) ;
goto invalid_type ;
}
* q = QSE_T ( ' \0 ' ) ;
if ( sscanf_i ( dic , p + 1 , & typelen ) < = - 1 | | typelen < = 0 | | typelen > 253 )
{
* p = QSE_T ( ' [ ' ) ;
* q = QSE_T ( ' ] ' ) ;
goto invalid_type ;
}
flags . length = typelen ;
}
type = str_to_type ( dic , argv [ 2 ] , & typelen ) ;
2017-12-13 08:21:13 +00:00
if ( type < 0 )
{
2017-12-14 10:02:44 +00:00
invalid_type :
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid attribute type \" %s \" " ) , fn , line , argv [ 2 ] ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-14 10:02:44 +00:00
if ( flags . length < = 0 & & typelen > = 0 ) flags . length = typelen ;
2017-08-29 09:09:51 +00:00
/*
2017-12-12 07:27:17 +00:00
* Only look up the vendor if the string
* is non - empty .
2017-08-29 09:09:51 +00:00
*/
2017-12-14 10:02:44 +00:00
if ( argc > = 4 )
2017-08-29 09:09:51 +00:00
{
2017-12-14 10:02:44 +00:00
qse_char_t * key , * next ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
key = argv [ 3 ] ;
2017-12-13 08:21:13 +00:00
do
{
next = qse_strchr ( key , QSE_T ( ' , ' ) ) ;
if ( next ) * ( next + + ) = QSE_T ( ' \0 ' ) ;
2017-08-29 09:09:51 +00:00
2017-12-14 10:02:44 +00:00
if ( qse_strcasecmp ( key , QSE_T ( " has_tag " ) ) = = 0 | |
qse_strcasecmp ( key , QSE_T ( " has_tag=1 " ) ) = = 0 )
2017-12-13 08:21:13 +00:00
{
2017-12-12 07:27:17 +00:00
flags . has_tag = 1 ;
2017-12-13 08:21:13 +00:00
}
2017-12-14 10:02:44 +00:00
else if ( qse_strzcasecmp ( key , QSE_T ( " encrypt= " ) , 8 ) = = 0 )
2017-12-13 08:21:13 +00:00
{
2017-12-12 07:27:17 +00:00
/* Encryption method, defaults to 0 (none).
Currently valid is just type 2 ,
Tunnel - Password style , which can only
be applied to strings . */
2017-12-18 06:27:54 +00:00
int ev ;
2017-12-14 10:02:44 +00:00
if ( sscanf_i ( dic , key + 8 , & ev ) < = - 1 | | ev < QSE_RADDIC_ATTR_FLAG_ENCRYPT_NONE | | ev > QSE_RADDIC_ATTR_FLAG_ENCRYPT_OTHER )
2017-12-13 08:21:13 +00:00
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid option %s " ) , fn , line , key ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-12-14 10:02:44 +00:00
flags . encrypt = ev ;
2017-12-13 08:21:13 +00:00
}
2017-12-14 10:02:44 +00:00
else if ( qse_strcasecmp ( key , QSE_T ( " array " ) ) = = 0 )
2017-12-13 08:21:13 +00:00
{
2017-12-12 07:27:17 +00:00
flags . array = 1 ;
2017-12-14 10:02:44 +00:00
}
else if ( qse_strcasecmp ( key , QSE_T ( " concat " ) ) = = 0 )
{
flags . concat = 1 ;
}
else if ( qse_strcasecmp ( key , QSE_T ( " internal " ) ) = = 0 )
{
flags . internal = 1 ;
}
else
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: unknown option \" %s \" " ) , fn , line , key ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
key = next ;
if ( key & & ! * key ) break ;
2017-12-13 08:21:13 +00:00
}
while ( key ) ;
2017-12-12 07:27:17 +00:00
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( block_vendor ) vendor = block_vendor ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
/*
* Special checks for tags , they make our life much more
* difficult .
*/
2017-12-13 08:21:13 +00:00
if ( flags . has_tag )
{
2017-08-29 09:09:51 +00:00
/*
2017-12-12 07:27:17 +00:00
* Only string , octets , and integer can be tagged .
2017-08-29 09:09:51 +00:00
*/
2017-12-13 08:21:13 +00:00
switch ( type )
{
case QSE_RADDIC_ATTR_TYPE_STRING :
2017-12-14 04:08:10 +00:00
case QSE_RADDIC_ATTR_TYPE_UINT32 :
2017-12-13 08:21:13 +00:00
break ;
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
default :
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: attribute of this type cannot be tagged " ) , fn , line ) ;
return - 1 ;
2017-08-29 09:09:51 +00:00
}
}
2017-12-13 08:21:13 +00:00
if ( type = = QSE_RADDIC_ATTR_TYPE_TLV )
{
2017-12-12 07:27:17 +00:00
flags . has_tlv = 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-13 08:21:13 +00:00
if ( block_tlv )
{
2017-12-12 07:27:17 +00:00
/*
* TLV ' s can be only one octet .
*/
2017-12-13 08:21:13 +00:00
if ( ( value < = 0 ) | | ( value > 255 ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: sub-tlv's cannot have value > 255 " ) , fn , line ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
#if 0
if ( flags . encrypt ! = QSE_RADDIC_ATTR_FLAG_ENCRYPT_NONE )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: sub-tlv's cannot be encrypted " ) , fn , line ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-12-13 08:21:13 +00:00
# endif
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
value < < = 8 ;
value | = ( block_tlv - > attr & 0xffff ) ;
flags . is_tlv = 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
/*
* Add it in .
*/
2017-12-13 08:21:13 +00:00
if ( qse_raddic_addattr ( dic , argv [ 0 ] , vendor , type , value , & flags ) = = QSE_NULL )
{
qse_strcpy ( dic - > errmsg2 , dic - > errmsg ) ;
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: cannot add attribute - %s " ) , fn , line , dic - > errmsg2 ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
return 0 ;
2017-08-29 09:09:51 +00:00
}
2017-12-13 08:21:13 +00:00
static int process_constant ( qse_raddic_t * dic , const qse_char_t * fn , const qse_size_t line , qse_char_t * * argv , int argc )
2017-08-29 09:09:51 +00:00
{
2017-12-18 06:27:54 +00:00
qse_uintmax_t value ;
2017-12-14 10:02:44 +00:00
int n ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( argc ! = 3 )
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid VALUE line " ) , fn , line ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
/*
* For Compatibility , skip " Server-Config "
*/
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " Server-Config " ) ) = = 0 ) return 0 ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
/*
* Validate all entries
*/
2017-12-14 10:02:44 +00:00
2017-12-18 06:27:54 +00:00
if ( ( n = sscanf_ui ( dic , argv [ 2 ] , & value ) ) < = - 1 )
2017-12-12 07:27:17 +00:00
{
2017-12-13 08:21:13 +00:00
qse_strcpy ( dic - > errmsg2 , dic - > errmsg ) ;
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid constant value - %s " ) , fn , line , dic - > errmsg2 ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-18 06:27:54 +00:00
if ( add_const ( dic , argv [ 1 ] , argv [ 0 ] , value , fn , line ) = = QSE_NULL )
2017-12-12 07:27:17 +00:00
{
2017-12-13 08:21:13 +00:00
qse_strcpy ( dic - > errmsg2 , dic - > errmsg ) ;
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: cannot add a constant \" %s \" - %s " ) , fn , line , argv [ 1 ] , dic - > errmsg2 ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
return 0 ;
2017-08-29 09:09:51 +00:00
}
/*
2017-12-12 07:27:17 +00:00
* Process the VENDOR command
2017-08-29 09:09:51 +00:00
*/
2017-12-12 07:27:17 +00:00
static int process_vendor ( qse_raddic_t * dic , const qse_char_t * fn , const qse_size_t line , qse_char_t * * argv , int argc )
2017-08-29 09:09:51 +00:00
{
2017-12-18 07:20:02 +00:00
unsigned int value ;
2017-12-13 08:21:13 +00:00
int continuation = 0 ;
2017-12-12 07:27:17 +00:00
const qse_char_t * format = QSE_NULL ;
2017-12-18 07:20:02 +00:00
const qse_char_t * end ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( ( argc < 2 ) | | ( argc > 3 ) )
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid VENDOR entry " ) , fn , line ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
/*
2017-12-18 07:20:02 +00:00
* Validate all entries
2017-08-29 09:09:51 +00:00
*/
2017-12-18 07:20:02 +00:00
value = qse_strtoui ( argv [ 1 ] , 0 , & end ) ;
if ( * end ! = QSE_T ( ' \0 ' ) | | value < = 0u | | value > 65535u )
2017-12-13 08:21:13 +00:00
{
2017-12-18 07:28:17 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid vendor value " ) , fn , line ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-12 07:27:17 +00:00
/* Create a new VENDOR entry for the list */
2017-12-13 08:21:13 +00:00
if ( qse_raddic_addvendor ( dic , argv [ 0 ] , value ) = = QSE_NULL )
{
qse_strcpy ( dic - > errmsg2 , dic - > errmsg ) ;
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: cannot add a vendor - %s " ) , fn , line , dic - > errmsg2 ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-12 07:27:17 +00:00
/*
* Look for a format statement
*/
2017-12-13 08:21:13 +00:00
if ( argc = = 3 )
{
2017-12-12 07:27:17 +00:00
format = argv [ 2 ] ;
2017-12-13 08:21:13 +00:00
}
#if 0
else if ( value = = VENDORPEC_USR )
{ /* catch dictionary screw-ups */
format = QSE_T ( " format=4,0 " ) ;
}
else if ( value = = VENDORPEC_LUCENT )
{
format = QSE_T ( " format=2,1 " ) ;
}
else if ( value = = VENDORPEC_STARENT )
{
format = QSE_T ( " format=2,2 " ) ;
2017-12-12 07:27:17 +00:00
} /* else no fixups to do */
2017-12-13 08:21:13 +00:00
# endif
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( format )
{
2017-12-12 07:27:17 +00:00
int type , length ;
2017-12-13 08:21:13 +00:00
const qse_char_t * p ;
2017-12-12 07:27:17 +00:00
qse_raddic_vendor_t * dv ;
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( qse_strzcasecmp ( format , QSE_T ( " format= " ) , 7 ) ! = 0 )
{
2017-12-18 07:28:17 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid vendor format. expected \" format= \" , got \" %s \" " ) , fn , line , format ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-12 07:27:17 +00:00
p = format + 7 ;
2017-12-13 08:21:13 +00:00
if ( qse_strlen ( p ) < 3 | | ! QSE_ISDIGIT ( p [ 0 ] ) | | p [ 1 ] ! = QSE_T ( ' , ' ) | | ! QSE_ISDIGIT ( p [ 2 ] ) | | ( p [ 3 ] & & p [ 3 ] ! = QSE_T ( ' , ' ) ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: Invalid format for VENDOR. Expected text like \" 1,1 \" , got \" %s \" " ) , fn , line , p ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
2017-12-12 07:27:17 +00:00
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
type = p [ 0 ] - QSE_T ( ' 0 ' ) ;
length = p [ 2 ] - QSE_T ( ' 0 ' ) ;
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( p [ 3 ] = = QSE_T ( ' , ' ) )
{
if ( p [ 4 ] ! = QSE_T ( ' c ' ) | | p [ 5 ] ! = QSE_T ( ' \0 ' ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: Invalid format for VENDOR. Expected text like \" 1,1 \" , got \" %s \" " ) , fn , line , p ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-12 07:27:17 +00:00
continuation = 1 ;
2017-08-29 09:09:51 +00:00
}
2017-12-13 08:21:13 +00:00
dv = qse_raddic_findvendorbyvalue ( dic , value ) ;
if ( ! dv )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: Failed adding format for VENDOR " ) , fn , line ) ;
2017-08-29 09:09:51 +00:00
return - 1 ;
}
2017-12-13 08:21:13 +00:00
if ( ( type ! = 1 ) & & ( type ! = 2 ) & & ( type ! = 4 ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid type value %d for VENDOR " ) , fn , line , type ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( ( length ! = 0 ) & & ( length ! = 1 ) & & ( length ! = 2 ) )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: invalid length value %d for VENDOR " ) , fn , line , length ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
dv - > type = type ;
dv - > length = length ;
dv - > flags = continuation ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
return 0 ;
2017-08-29 09:09:51 +00:00
}
2017-12-14 10:02:44 +00:00
static int load_file ( qse_raddic_t * dic , const qse_char_t * fn , const qse_char_t * src_file , qse_size_t src_line )
2017-08-29 09:09:51 +00:00
{
2017-12-12 07:27:17 +00:00
qse_sio_t * sio = QSE_NULL ;
2017-12-14 04:08:10 +00:00
qse_char_t buf [ 256 ] ; /* TODO: is this a good size? */
2017-12-12 07:27:17 +00:00
qse_char_t * p ;
qse_size_t line = 0 ;
2017-12-13 08:21:13 +00:00
qse_raddic_vendor_t * vendor ;
qse_raddic_vendor_t * block_vendor ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
qse_char_t * argv [ 16 ] ; /* TODO: what is the best size? */
int argc ;
qse_raddic_attr_t * da , * block_tlv = QSE_NULL ;
2017-12-14 04:08:10 +00:00
qse_char_t * fname = ( qse_char_t * ) fn ;
2017-12-12 07:27:17 +00:00
2017-12-14 04:08:10 +00:00
if ( ! qse_isabspath ( fn ) & & src_file )
2017-08-29 09:09:51 +00:00
{
2017-12-14 04:08:10 +00:00
const qse_char_t * b = qse_basename ( src_file ) ;
if ( b ! = src_file )
{
2021-08-12 16:18:15 +00:00
fname = qse_substbasenamedup ( src_file , fn , dic - > mmgr ) ;
2017-12-14 04:08:10 +00:00
if ( ! fname )
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ENOMEM , QSE_T ( " %s[%zd]: out of memory before including %s " ) , fn ) ;
return - 1 ;
}
qse_canonpath ( fname , fname , 0 ) ;
}
2017-12-12 07:27:17 +00:00
}
2017-12-14 04:08:10 +00:00
sio = qse_sio_open ( dic - > mmgr , 0 , fname , QSE_SIO_READ ) ;
2017-12-12 07:27:17 +00:00
if ( ! sio )
{
2017-12-13 08:21:13 +00:00
if ( src_file )
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: cannot open %s " ) , src_file , src_line , fname ) ;
2017-12-13 08:21:13 +00:00
else
2017-12-14 10:02:44 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " cannot open \" %s \" " ) , fname ) ;
2017-12-14 04:08:10 +00:00
goto oops ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
block_vendor = 0 ;
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
while ( qse_sio_getstr ( sio , buf , QSE_COUNTOF ( buf ) ) > 0 )
2017-12-12 07:27:17 +00:00
{
line + + ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
qse_strpac ( buf ) ;
if ( buf [ 0 ] = = QSE_T ( ' \0 ' ) | | buf [ 0 ] = = QSE_T ( ' # ' ) ) continue ;
2017-08-29 09:09:51 +00:00
/*
2017-12-12 07:27:17 +00:00
* Comment characters should NOT be appearing anywhere but
* as start of a comment ;
2017-08-29 09:09:51 +00:00
*/
2017-12-12 07:27:17 +00:00
p = qse_strchr ( buf , QSE_T ( ' # ' ) ) ;
if ( p ) * p = QSE_T ( ' \0 ' ) ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
argc = str2argv ( buf , argv , QSE_COUNTOF ( argv ) ) ;
if ( argc = = 0 ) continue ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( argc = = 1 )
{
2017-12-14 10:02:44 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid entry \" %s \" " ) , fname , line , argv [ 0 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
2017-08-29 09:09:51 +00:00
}
/*
2017-12-12 07:27:17 +00:00
* Process VALUE lines .
2017-08-29 09:09:51 +00:00
*/
2017-12-12 07:27:17 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " VALUE " ) ) = = 0 )
{
2017-12-14 04:08:10 +00:00
if ( process_constant ( dic , fname , line , argv + 1 , argc - 1 ) = = - 1 ) goto oops ;
2017-12-12 07:27:17 +00:00
continue ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
/*
* Perhaps this is an attribute .
*/
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " ATTRIBUTE " ) ) = = 0 )
{
2017-12-14 04:08:10 +00:00
if ( process_attribute ( dic , fname , line , ( block_vendor ? block_vendor - > vendorpec : 0 ) , block_tlv , argv + 1 , argc - 1 ) = = - 1 ) goto oops ;
2017-12-12 07:27:17 +00:00
continue ;
2017-08-29 09:09:51 +00:00
}
/*
2017-12-12 07:27:17 +00:00
* See if we need to import another dictionary .
2017-08-29 09:09:51 +00:00
*/
2017-12-12 07:27:17 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " $INCLUDE " ) ) = = 0 )
{
2017-12-14 10:02:44 +00:00
if ( load_file ( dic , argv [ 1 ] , fname , line ) < 0 ) goto oops ;
2017-12-12 07:27:17 +00:00
continue ;
} /* $INCLUDE */
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
/*
* Process VENDOR lines .
*/
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " VENDOR " ) ) = = 0 )
{
2017-12-14 04:08:10 +00:00
if ( process_vendor ( dic , fname , line , argv + 1 , argc - 1 ) = = - 1 ) goto oops ;
2017-12-12 07:27:17 +00:00
continue ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " BEGIN-TLV " ) ) = = 0 )
{
if ( argc ! = 2 )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid BEGIN-TLV entry " ) , fname , line ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
da = qse_raddic_findattrbyname ( dic , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
if ( ! da )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: unknown attribute %s " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( da - > type ! = QSE_RADDIC_ATTR_TYPE_TLV )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: attribute %s is not of type tlv " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
block_tlv = da ;
continue ;
} /* BEGIN-TLV */
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " END-TLV " ) ) = = 0 )
2017-12-12 07:27:17 +00:00
{
if ( argc ! = 2 )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid END-TLV entry " ) , fname , line ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
da = qse_raddic_findattrbyname ( dic , argv [ 1 ] ) ;
if ( ! da )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: unknown attribute %s " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( da ! = block_tlv )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: END-TLV %s does not match any previous BEGIN-TLV " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
block_tlv = QSE_NULL ;
continue ;
} /* END-VENDOR */
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " BEGIN-VENDOR " ) ) = = 0 )
2017-12-12 07:27:17 +00:00
{
if ( argc ! = 2 )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid BEGIN-VENDOR entry " ) , fname , line ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
vendor = qse_raddic_findvendorbyname ( dic , argv [ 1 ] ) ;
if ( ! vendor )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: unknown vendor %s " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
block_vendor = vendor ;
continue ;
} /* BEGIN-VENDOR */
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( qse_strcasecmp ( argv [ 0 ] , QSE_T ( " END-VENDOR " ) ) = = 0 )
{
2017-12-13 08:21:13 +00:00
if ( argc ! = 2 )
{
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid END-VENDOR entry " ) , fname , line ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
vendor = qse_raddic_findvendorbyname ( dic , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
if ( ! vendor )
{
2017-12-18 06:27:54 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: unknown vendor \" %s \" " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
if ( vendor ! = block_vendor )
{
2017-12-13 08:21:13 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR ,
2017-12-14 04:08:10 +00:00
QSE_T ( " %s[%zd]: END-VENDOR %s does not match any previous BEGIN-VENDOR " ) , fname , line , argv [ 1 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
}
block_vendor = 0 ;
continue ;
} /* END-VENDOR */
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
/*
* Any other string : We don ' t recognize it .
*/
2017-12-14 04:08:10 +00:00
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd] invalid keyword \" %s \" " ) , fname , line , argv [ 0 ] ) ;
2017-12-12 07:27:17 +00:00
goto oops ;
2017-08-29 09:09:51 +00:00
}
2017-12-12 07:27:17 +00:00
qse_sio_close ( sio ) ;
2017-12-14 04:08:10 +00:00
if ( fname ! = fn ) QSE_MMGR_FREE ( dic - > mmgr , fname ) ;
2017-12-12 07:27:17 +00:00
return 0 ;
2017-08-29 09:09:51 +00:00
2017-12-12 07:27:17 +00:00
oops :
if ( sio ) qse_sio_close ( sio ) ;
2017-12-14 04:08:10 +00:00
if ( fname ! = fn ) QSE_MMGR_FREE ( dic - > mmgr , fname ) ;
2017-12-12 07:27:17 +00:00
return - 1 ;
}
2017-08-29 09:09:51 +00:00
2017-12-13 08:21:13 +00:00
int qse_raddic_load ( qse_raddic_t * dic , const qse_char_t * file )
2017-12-12 07:27:17 +00:00
{
2017-12-18 06:27:54 +00:00
int n ;
n = load_file ( dic , file , QSE_NULL , 0 ) ;
while ( dic - > const_fixup )
{
qse_raddic_attr_t * attr ;
const_fixup_t * fixup = dic - > const_fixup ;
dic - > const_fixup = dic - > const_fixup - > next ;
if ( n > = 0 )
{
attr = qse_raddic_findattrbyname ( dic , fixup - > attrstr ) ;
if ( attr )
{
fixup - > dval - > attr = attr - > attr ;
attr - > flags . has_value = 1 ;
if ( __add_const ( dic , fixup - > dval ) ! = QSE_NULL ) goto fixed ;
}
else
{
qse_raddic_seterrfmt ( dic , QSE_RADDIC_ESYNERR , QSE_T ( " %s[%zd]: constant \" %s \" defined for an unknown attribute \" %s \" " ) , fixup - > fn , fixup - > line , fixup - > dval - > name , fixup - > attrstr ) ;
n = - 1 ;
}
}
QSE_MMGR_FREE ( dic - > mmgr , fixup - > dval ) ;
fixed :
QSE_MMGR_FREE ( dic - > mmgr , fixup ) ;
}
return n ;
2017-08-29 09:09:51 +00:00
}