Home | History | Annotate | Line # | Download | only in librewrite
config.c revision 1.1.1.2
      1  1.1.1.2  lukem /*	$NetBSD: config.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
      2  1.1.1.2  lukem 
      3  1.1.1.2  lukem /* OpenLDAP: pkg/ldap/libraries/librewrite/config.c,v 1.14.2.4 2009/01/22 00:00:58 kurt Exp */
      4      1.1  lukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5      1.1  lukem  *
      6  1.1.1.2  lukem  * Copyright 2000-2009 The OpenLDAP Foundation.
      7      1.1  lukem  * All rights reserved.
      8      1.1  lukem  *
      9      1.1  lukem  * Redistribution and use in source and binary forms, with or without
     10      1.1  lukem  * modification, are permitted only as authorized by the OpenLDAP
     11      1.1  lukem  * Public License.
     12      1.1  lukem  *
     13      1.1  lukem  * A copy of this license is available in the file LICENSE in the
     14      1.1  lukem  * top-level directory of the distribution or, alternatively, at
     15      1.1  lukem  * <http://www.OpenLDAP.org/license.html>.
     16      1.1  lukem  */
     17      1.1  lukem /* ACKNOWLEDGEMENT:
     18      1.1  lukem  * This work was initially developed by Pierangelo Masarati for
     19      1.1  lukem  * inclusion in OpenLDAP Software.
     20      1.1  lukem  */
     21      1.1  lukem 
     22      1.1  lukem #include <portable.h>
     23      1.1  lukem 
     24      1.1  lukem #include "rewrite-int.h"
     25      1.1  lukem #include "rewrite-map.h"
     26      1.1  lukem 
     27      1.1  lukem /*
     28      1.1  lukem  * Parses a plugin map
     29      1.1  lukem  */
     30      1.1  lukem static int
     31      1.1  lukem rewrite_parse_builtin_map(
     32      1.1  lukem 		struct rewrite_info *info,
     33      1.1  lukem 		const char *fname,
     34      1.1  lukem 		int lineno,
     35      1.1  lukem 		int argc,
     36      1.1  lukem 		char **argv
     37      1.1  lukem );
     38      1.1  lukem 
     39      1.1  lukem /*
     40      1.1  lukem  * Parses a config line and takes actions to fit content in rewrite structure;
     41      1.1  lukem  * lines handled are of the form:
     42      1.1  lukem  *
     43      1.1  lukem  *      rewriteEngine 		{on|off}
     44      1.1  lukem  *      rewriteMaxPasses        numPasses [numPassesPerRule]
     45      1.1  lukem  *      rewriteContext 		contextName [alias aliasedContextName]
     46      1.1  lukem  *      rewriteRule 		pattern substPattern [ruleFlags]
     47      1.1  lukem  *      rewriteMap 		mapType mapName [mapArgs]
     48      1.1  lukem  *      rewriteParam		paramName paramValue
     49      1.1  lukem  */
     50      1.1  lukem int
     51      1.1  lukem rewrite_parse(
     52      1.1  lukem 		struct rewrite_info *info,
     53      1.1  lukem 		const char *fname,
     54      1.1  lukem 		int lineno,
     55      1.1  lukem 		int argc,
     56      1.1  lukem 		char **argv
     57      1.1  lukem )
     58      1.1  lukem {
     59      1.1  lukem 	int rc = -1;
     60      1.1  lukem 
     61      1.1  lukem 	assert( info != NULL );
     62      1.1  lukem 	assert( fname != NULL );
     63      1.1  lukem 	assert( argv != NULL );
     64      1.1  lukem 	assert( argc > 0 );
     65      1.1  lukem 
     66      1.1  lukem 	/*
     67      1.1  lukem 	 * Switch on the rewrite engine
     68      1.1  lukem 	 */
     69      1.1  lukem 	if ( strcasecmp( argv[ 0 ], "rewriteEngine" ) == 0 ) {
     70      1.1  lukem 		if ( argc < 2 ) {
     71      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
     72      1.1  lukem 					"[%s:%d] rewriteEngine needs 'state'\n%s",
     73      1.1  lukem 					fname, lineno, "" );
     74      1.1  lukem 			return -1;
     75      1.1  lukem 
     76      1.1  lukem 		} else if ( argc > 2 ) {
     77      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
     78      1.1  lukem 					"[%s:%d] extra fields in rewriteEngine"
     79      1.1  lukem 					" will be discarded\n%s",
     80      1.1  lukem 					fname, lineno, "" );
     81      1.1  lukem 		}
     82      1.1  lukem 
     83      1.1  lukem 		if ( strcasecmp( argv[ 1 ], "on" ) == 0 ) {
     84      1.1  lukem 			info->li_state = REWRITE_ON;
     85      1.1  lukem 
     86      1.1  lukem 		} else if ( strcasecmp( argv[ 1 ], "off" ) == 0 ) {
     87      1.1  lukem 			info->li_state = REWRITE_OFF;
     88      1.1  lukem 
     89      1.1  lukem 		} else {
     90      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
     91      1.1  lukem 					"[%s:%d] unknown 'state' in rewriteEngine;"
     92      1.1  lukem 					" assuming 'on'\n%s",
     93      1.1  lukem 					fname, lineno, "" );
     94      1.1  lukem 			info->li_state = REWRITE_ON;
     95      1.1  lukem 		}
     96      1.1  lukem 		rc = REWRITE_SUCCESS;
     97      1.1  lukem 
     98      1.1  lukem 	/*
     99      1.1  lukem 	 * Alter max passes
    100      1.1  lukem 	 */
    101      1.1  lukem 	} else if ( strcasecmp( argv[ 0 ], "rewriteMaxPasses" ) == 0 ) {
    102      1.1  lukem 		if ( argc < 2 ) {
    103      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    104      1.1  lukem 					"[%s:%d] rewriteMaxPasses needs 'value'\n%s",
    105      1.1  lukem 					fname, lineno, "" );
    106      1.1  lukem 			return -1;
    107      1.1  lukem 		}
    108      1.1  lukem 
    109      1.1  lukem 		if ( lutil_atoi( &info->li_max_passes, argv[ 1 ] ) != 0 ) {
    110      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    111      1.1  lukem 					"[%s:%d] unable to parse rewriteMaxPasses=\"%s\"\n",
    112      1.1  lukem 					fname, lineno, argv[ 1 ] );
    113      1.1  lukem 			return -1;
    114      1.1  lukem 		}
    115      1.1  lukem 
    116      1.1  lukem 		if ( info->li_max_passes <= 0 ) {
    117      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    118      1.1  lukem 					"[%s:%d] negative or null rewriteMaxPasses\n",
    119      1.1  lukem 					fname, lineno, 0 );
    120      1.1  lukem 			return -1;
    121      1.1  lukem 		}
    122      1.1  lukem 
    123      1.1  lukem 		if ( argc > 2 ) {
    124      1.1  lukem 			if ( lutil_atoi( &info->li_max_passes_per_rule, argv[ 2 ] ) != 0 ) {
    125      1.1  lukem 				Debug( LDAP_DEBUG_ANY,
    126      1.1  lukem 						"[%s:%d] unable to parse rewriteMaxPassesPerRule=\"%s\"\n",
    127      1.1  lukem 						fname, lineno, argv[ 2 ] );
    128      1.1  lukem 				return -1;
    129      1.1  lukem 			}
    130      1.1  lukem 
    131      1.1  lukem 			if ( info->li_max_passes_per_rule <= 0 ) {
    132      1.1  lukem 				Debug( LDAP_DEBUG_ANY,
    133      1.1  lukem 						"[%s:%d] negative or null rewriteMaxPassesPerRule\n",
    134      1.1  lukem 						fname, lineno, 0 );
    135      1.1  lukem 				return -1;
    136      1.1  lukem 			}
    137      1.1  lukem 
    138      1.1  lukem 		} else {
    139      1.1  lukem 			info->li_max_passes_per_rule = info->li_max_passes;
    140      1.1  lukem 		}
    141      1.1  lukem 		rc = REWRITE_SUCCESS;
    142      1.1  lukem 
    143      1.1  lukem 	/*
    144      1.1  lukem 	 * Start a new rewrite context and set current context
    145      1.1  lukem 	 */
    146      1.1  lukem 	} else if ( strcasecmp( argv[ 0 ], "rewriteContext" ) == 0 ) {
    147      1.1  lukem 		if ( argc < 2 ) {
    148      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    149      1.1  lukem 					"[%s:%d] rewriteContext needs 'name'\n%s",
    150      1.1  lukem 					fname, lineno, "" );
    151      1.1  lukem 			return -1;
    152      1.1  lukem 		}
    153      1.1  lukem 
    154      1.1  lukem 		/*
    155      1.1  lukem 		 * Checks for existence (lots of contexts should be
    156      1.1  lukem 		 * available by default ...)
    157      1.1  lukem 		 */
    158      1.1  lukem 		 rewrite_int_curr_context = rewrite_context_find( info, argv[ 1 ] );
    159      1.1  lukem 		 if ( rewrite_int_curr_context == NULL ) {
    160      1.1  lukem 			 rewrite_int_curr_context = rewrite_context_create( info,
    161      1.1  lukem 					 argv[ 1 ] );
    162      1.1  lukem 		 }
    163      1.1  lukem 		 if ( rewrite_int_curr_context == NULL ) {
    164      1.1  lukem 			 return -1;
    165      1.1  lukem 		 }
    166      1.1  lukem 
    167      1.1  lukem 		 if ( argc > 2 ) {
    168      1.1  lukem 
    169      1.1  lukem 			 /*
    170      1.1  lukem 			  * A context can alias another (e.g., the `builtin'
    171      1.1  lukem 			  * contexts for backend operations, if not defined,
    172      1.1  lukem 			  * alias the `default' rewrite context (with the
    173      1.1  lukem 			  * notable exception of the searchResult context,
    174      1.1  lukem 			  * which can be undefined)
    175      1.1  lukem 			  */
    176      1.1  lukem 			 if ( strcasecmp( argv[ 2 ], "alias" ) == 0 ) {
    177      1.1  lukem 				 struct rewrite_context *aliased;
    178      1.1  lukem 
    179      1.1  lukem 				 if ( argc == 3 ) {
    180      1.1  lukem 					 Debug( LDAP_DEBUG_ANY,
    181      1.1  lukem 							 "[%s:%d] rewriteContext"
    182      1.1  lukem 							 " needs 'name' after"
    183      1.1  lukem 							 " 'alias'\n%s",
    184      1.1  lukem 							 fname, lineno, "" );
    185      1.1  lukem 					 return -1;
    186      1.1  lukem 
    187      1.1  lukem 				 } else if ( argc > 4 ) {
    188      1.1  lukem 					 Debug( LDAP_DEBUG_ANY,
    189      1.1  lukem 							 "[%s:%d] extra fields in"
    190      1.1  lukem 							 " rewriteContext"
    191      1.1  lukem 							 " after aliased name"
    192      1.1  lukem 							 " will be"
    193      1.1  lukem 							 " discarded\n%s",
    194      1.1  lukem 							 fname, lineno, "" );
    195      1.1  lukem 				 }
    196      1.1  lukem 
    197      1.1  lukem 				 aliased = rewrite_context_find( info,
    198      1.1  lukem 						 argv[ 3 ] );
    199      1.1  lukem 				 if ( aliased == NULL ) {
    200      1.1  lukem 					 Debug( LDAP_DEBUG_ANY,
    201      1.1  lukem 							 "[%s:%d] aliased"
    202      1.1  lukem 							 " rewriteContext '%s'"
    203      1.1  lukem 							 " does not exists\n",
    204      1.1  lukem 							 fname, lineno,
    205      1.1  lukem 							 argv[ 3 ] );
    206      1.1  lukem 					 return -1;
    207      1.1  lukem 				 }
    208      1.1  lukem 
    209      1.1  lukem 				 rewrite_int_curr_context->lc_alias = aliased;
    210      1.1  lukem 				 rewrite_int_curr_context = aliased;
    211      1.1  lukem 
    212      1.1  lukem 			 } else {
    213      1.1  lukem 				 Debug( LDAP_DEBUG_ANY,
    214      1.1  lukem 						 "[%s:%d] extra fields"
    215      1.1  lukem 						 " in rewriteContext"
    216      1.1  lukem 						 " will be discarded\n%s",
    217      1.1  lukem 						 fname, lineno, "" );
    218      1.1  lukem 			 }
    219      1.1  lukem 		 }
    220      1.1  lukem 		 rc = REWRITE_SUCCESS;
    221      1.1  lukem 
    222      1.1  lukem 	/*
    223      1.1  lukem 	 * Compile a rule in current context
    224      1.1  lukem 	 */
    225      1.1  lukem 	} else if ( strcasecmp( argv[ 0 ], "rewriteRule" ) == 0 ) {
    226      1.1  lukem 		if ( argc < 3 ) {
    227      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    228      1.1  lukem 					"[%s:%d] rewriteRule needs 'pattern'"
    229      1.1  lukem 					" 'subst' ['flags']\n%s",
    230      1.1  lukem 					fname, lineno, "" );
    231      1.1  lukem 			return -1;
    232      1.1  lukem 
    233      1.1  lukem 		} else if ( argc > 4 ) {
    234      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    235      1.1  lukem 					"[%s:%d] extra fields in rewriteRule"
    236      1.1  lukem 					" will be discarded\n%s",
    237      1.1  lukem 					fname, lineno, "" );
    238      1.1  lukem 		}
    239      1.1  lukem 
    240      1.1  lukem 		if ( rewrite_int_curr_context == NULL ) {
    241      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    242      1.1  lukem 					"[%s:%d] rewriteRule outside a"
    243      1.1  lukem 					" context; will add to default\n%s",
    244      1.1  lukem 					fname, lineno, "" );
    245      1.1  lukem 			rewrite_int_curr_context = rewrite_context_find( info,
    246      1.1  lukem 					REWRITE_DEFAULT_CONTEXT );
    247      1.1  lukem 
    248      1.1  lukem 			/*
    249      1.1  lukem 			 * Default context MUST exist in a properly initialized
    250      1.1  lukem 			 * struct rewrite_info
    251      1.1  lukem 			 */
    252      1.1  lukem 			assert( rewrite_int_curr_context != NULL );
    253      1.1  lukem 		}
    254      1.1  lukem 
    255      1.1  lukem 		rc = rewrite_rule_compile( info, rewrite_int_curr_context, argv[ 1 ],
    256      1.1  lukem 				argv[ 2 ], ( argc == 4 ? argv[ 3 ] : "" ) );
    257      1.1  lukem 
    258      1.1  lukem 	/*
    259      1.1  lukem 	 * Add a plugin map to the map tree
    260      1.1  lukem 	 */
    261      1.1  lukem 	} else if ( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 ) {
    262      1.1  lukem 		if ( argc < 3 ) {
    263      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    264      1.1  lukem 					"[%s:%d] rewriteMap needs at least 'type'"
    265      1.1  lukem 					" and 'name' ['args']\n%s",
    266      1.1  lukem 					fname, lineno, "" );
    267      1.1  lukem 			return -1;
    268      1.1  lukem 		}
    269      1.1  lukem 
    270      1.1  lukem 		rc = rewrite_parse_builtin_map( info, fname, lineno,
    271      1.1  lukem 				argc, argv );
    272      1.1  lukem 
    273      1.1  lukem 	/*
    274      1.1  lukem 	 * Set the value of a global scope parameter
    275      1.1  lukem 	 */
    276      1.1  lukem 	} else if ( strcasecmp( argv[ 0 ], "rewriteParam" ) == 0 ) {
    277      1.1  lukem 		if ( argc < 3 ) {
    278      1.1  lukem 			Debug( LDAP_DEBUG_ANY,
    279      1.1  lukem 					"[%s:%d] rewriteParam needs 'name'"
    280      1.1  lukem 					" and 'value'\n%s",
    281      1.1  lukem 					fname, lineno, "" );
    282      1.1  lukem 			return -1;
    283      1.1  lukem 		}
    284      1.1  lukem 
    285      1.1  lukem 		rc = rewrite_param_set( info, argv[ 1 ], argv[ 2 ] );
    286      1.1  lukem 
    287      1.1  lukem 	/*
    288      1.1  lukem 	 * Error
    289      1.1  lukem 	 */
    290      1.1  lukem 	} else {
    291      1.1  lukem 		Debug( LDAP_DEBUG_ANY,
    292      1.1  lukem 				"[%s:%d] unknown command '%s'\n",
    293      1.1  lukem 				fname, lineno, "" );
    294      1.1  lukem 		return -1;
    295      1.1  lukem 	}
    296      1.1  lukem 
    297      1.1  lukem 	return rc;
    298      1.1  lukem }
    299      1.1  lukem 
    300      1.1  lukem /*
    301      1.1  lukem  * Compares two maps
    302      1.1  lukem  */
    303      1.1  lukem static int
    304      1.1  lukem rewrite_builtin_map_cmp(
    305      1.1  lukem 		const void *c1,
    306      1.1  lukem                 const void *c2
    307      1.1  lukem )
    308      1.1  lukem {
    309      1.1  lukem 	const struct rewrite_builtin_map *m1, *m2;
    310      1.1  lukem 
    311      1.1  lukem         m1 = ( const struct rewrite_builtin_map * )c1;
    312      1.1  lukem         m2 = ( const struct rewrite_builtin_map * )c2;
    313      1.1  lukem 
    314      1.1  lukem         assert( m1 != NULL );
    315      1.1  lukem         assert( m2 != NULL );
    316      1.1  lukem         assert( m1->lb_name != NULL );
    317      1.1  lukem         assert( m2->lb_name != NULL );
    318      1.1  lukem 
    319      1.1  lukem         return strcasecmp( m1->lb_name, m2->lb_name );
    320      1.1  lukem }
    321      1.1  lukem 
    322      1.1  lukem /*
    323      1.1  lukem  * Duplicate map ?
    324      1.1  lukem  */
    325      1.1  lukem static int
    326      1.1  lukem rewrite_builtin_map_dup(
    327      1.1  lukem 	                void *c1,
    328      1.1  lukem 	                void *c2
    329      1.1  lukem )
    330      1.1  lukem {
    331      1.1  lukem         struct rewrite_builtin_map *m1, *m2;
    332      1.1  lukem 
    333      1.1  lukem         m1 = ( struct rewrite_builtin_map * )c1;
    334      1.1  lukem         m2 = ( struct rewrite_builtin_map * )c2;
    335      1.1  lukem 
    336      1.1  lukem         assert( m1 != NULL );
    337      1.1  lukem         assert( m2 != NULL );
    338      1.1  lukem         assert( m1->lb_name != NULL );
    339      1.1  lukem         assert( m2->lb_name != NULL );
    340      1.1  lukem 
    341      1.1  lukem         return ( strcasecmp( m1->lb_name, m2->lb_name ) == 0 ? -1 : 0 );
    342      1.1  lukem }
    343      1.1  lukem 
    344      1.1  lukem /*
    345      1.1  lukem  * Adds a map to the info map tree
    346      1.1  lukem  */
    347      1.1  lukem static int
    348      1.1  lukem rewrite_builtin_map_insert(
    349      1.1  lukem 		struct rewrite_info *info,
    350      1.1  lukem 		struct rewrite_builtin_map *map
    351      1.1  lukem )
    352      1.1  lukem {
    353      1.1  lukem 	/*
    354      1.1  lukem 	 * May need a mutex?
    355      1.1  lukem 	 */
    356      1.1  lukem 	return avl_insert( &info->li_maps, ( caddr_t )map,
    357      1.1  lukem 			rewrite_builtin_map_cmp,
    358      1.1  lukem 		       	rewrite_builtin_map_dup );
    359      1.1  lukem }
    360      1.1  lukem 
    361      1.1  lukem /*
    362      1.1  lukem  * Retrieves a map
    363      1.1  lukem  */
    364      1.1  lukem struct rewrite_builtin_map *
    365      1.1  lukem rewrite_builtin_map_find(
    366      1.1  lukem 		struct rewrite_info *info,
    367      1.1  lukem 		const char *name
    368      1.1  lukem )
    369      1.1  lukem {
    370      1.1  lukem 	struct rewrite_builtin_map tmp;
    371      1.1  lukem 
    372      1.1  lukem 	assert( info != NULL );
    373      1.1  lukem 	assert( name != NULL );
    374      1.1  lukem 
    375      1.1  lukem 	tmp.lb_name = ( char * )name;
    376      1.1  lukem 
    377      1.1  lukem 	return ( struct rewrite_builtin_map * )avl_find( info->li_maps,
    378      1.1  lukem 			( caddr_t )&tmp, rewrite_builtin_map_cmp );
    379      1.1  lukem }
    380      1.1  lukem 
    381      1.1  lukem /*
    382      1.1  lukem  * Parses a plugin map
    383      1.1  lukem  */
    384      1.1  lukem static int
    385      1.1  lukem rewrite_parse_builtin_map(
    386      1.1  lukem 		struct rewrite_info *info,
    387      1.1  lukem 		const char *fname,
    388      1.1  lukem 		int lineno,
    389      1.1  lukem 		int argc,
    390      1.1  lukem 		char **argv
    391      1.1  lukem )
    392      1.1  lukem {
    393      1.1  lukem 	struct rewrite_builtin_map *map;
    394      1.1  lukem 
    395      1.1  lukem #define MAP_TYPE	1
    396      1.1  lukem #define MAP_NAME	2
    397      1.1  lukem 
    398      1.1  lukem 	assert( info != NULL );
    399      1.1  lukem 	assert( fname != NULL );
    400      1.1  lukem 	assert( argc > 2 );
    401      1.1  lukem 	assert( argv != NULL );
    402      1.1  lukem 	assert( strcasecmp( argv[ 0 ], "rewriteMap" ) == 0 );
    403      1.1  lukem 
    404      1.1  lukem 	map = calloc( sizeof( struct rewrite_builtin_map ), 1 );
    405      1.1  lukem 	if ( map == NULL ) {
    406      1.1  lukem 		return REWRITE_ERR;
    407      1.1  lukem 	}
    408      1.1  lukem 
    409      1.1  lukem 	map->lb_name = strdup( argv[ MAP_NAME ] );
    410      1.1  lukem 	if ( map->lb_name == NULL ) {
    411      1.1  lukem 		free( map );
    412      1.1  lukem 		return REWRITE_ERR;
    413      1.1  lukem 	}
    414      1.1  lukem 
    415      1.1  lukem 	/*
    416      1.1  lukem 	 * Built-in ldap map
    417      1.1  lukem 	 */
    418      1.1  lukem 	if (( map->lb_mapper = rewrite_mapper_find( argv[ MAP_TYPE ] ))) {
    419      1.1  lukem 		map->lb_type = REWRITE_BUILTIN_MAP;
    420      1.1  lukem 
    421      1.1  lukem #ifdef USE_REWRITE_LDAP_PVT_THREADS
    422      1.1  lukem 		if ( ldap_pvt_thread_mutex_init( & map->lb_mutex ) ) {
    423      1.1  lukem 			free( map->lb_name );
    424      1.1  lukem 			free( map );
    425      1.1  lukem 			return REWRITE_ERR;
    426      1.1  lukem 		}
    427      1.1  lukem #endif /* USE_REWRITE_LDAP_PVT_THREADS */
    428      1.1  lukem 
    429      1.1  lukem 		map->lb_private = map->lb_mapper->rm_config( fname, lineno,
    430      1.1  lukem 				argc - 3, argv + 3 );
    431      1.1  lukem 
    432      1.1  lukem 	/*
    433      1.1  lukem 	 * Error
    434      1.1  lukem 	 */
    435      1.1  lukem 	} else {
    436      1.1  lukem 		free( map );
    437      1.1  lukem 		Debug( LDAP_DEBUG_ANY, "[%s:%d] unknown map type\n%s",
    438      1.1  lukem 				fname, lineno, "" );
    439      1.1  lukem 		return -1;
    440      1.1  lukem 	}
    441      1.1  lukem 
    442      1.1  lukem 	return rewrite_builtin_map_insert( info, map );
    443      1.1  lukem }
    444