/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved. */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * * MODULE: dat_sr_parser.c * * PURPOSE: static registry parser * * $Id: udat_sr_parser.c,v 1.1 2003/07/31 14:04:19 jlentini Exp $ */ #include "udat_sr_parser.h" #include "dat_sr.h" /* * * Constants * */ #define DAT_SR_CONF_ENV "DAT_OVERRIDE" #define DAT_SR_CONF_DEFAULT "/etc/dat/dat.conf" #define DAT_SR_TOKEN_THREADSAFE "threadsafe" #define DAT_SR_TOKEN_NONTHREADSAFE "nonthreadsafe" #define DAT_SR_TOKEN_DEFAULT "default" #define DAT_SR_TOKEN_NONDEFAULT "nondefault" #define DAT_SR_CHAR_NEWLINE '\n' #define DAT_SR_CHAR_COMMENT '#' #define DAT_SR_CHAR_QUOTE '"' #define DAT_SR_CHAR_BACKSLASH '\\' /* * * Enumerations * */ typedef enum { DAT_SR_TOKEN_STRING, /* text field (both quoted or unquoted) */ DAT_SR_TOKEN_EOR, /* end of record (newline) */ DAT_SR_TOKEN_EOF /* end of file */ } DAT_SR_TOKEN_TYPE; typedef enum { DAT_SR_API_UDAT, DAT_SR_API_KDAT } DAT_SR_API_TYPE; /* * * Structures * */ typedef struct { DAT_SR_TOKEN_TYPE type; char *value; /* valid if type is DAT_SR_TOKEN_STRING */ DAT_OS_SIZE value_len; } DAT_SR_TOKEN; typedef struct DAT_SR_STACK_NODE { DAT_SR_TOKEN token; struct DAT_SR_STACK_NODE *next; } DAT_SR_STACK_NODE; typedef struct { DAT_UINT32 major; DAT_UINT32 minor; } DAT_SR_VERSION; typedef struct { char *id; DAT_SR_VERSION version; } DAT_SR_PROVIDER_VERSION; typedef struct { DAT_SR_API_TYPE type; DAT_SR_VERSION version; } DAT_SR_API_VERSION; typedef struct { char *ia_name; DAT_SR_API_VERSION api_version; DAT_BOOLEAN is_thread_safe; DAT_BOOLEAN is_default; char *lib_path; DAT_SR_PROVIDER_VERSION provider_version; char *ia_params; char *platform_params; } DAT_SR_CONF_ENTRY; /* * * Internal Function Declarations * */ static DAT_RETURN dat_sr_load_entry( DAT_SR_CONF_ENTRY *entry); static DAT_BOOLEAN dat_sr_is_valid_entry( DAT_SR_CONF_ENTRY *entry); static char * dat_sr_type_to_str( DAT_SR_TOKEN_TYPE type); static DAT_RETURN dat_sr_parse_eof( DAT_OS_FILE *file); static DAT_RETURN dat_sr_parse_entry( DAT_OS_FILE *file); static DAT_RETURN dat_sr_parse_ia_name( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_api( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_thread_safety( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_default( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_lib_path( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_provider_version( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_ia_params( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_platform_params( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_parse_eoe( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry); static DAT_RETURN dat_sr_convert_api( char *str, DAT_SR_API_VERSION *api_version); static DAT_RETURN dat_sr_convert_thread_safety( char *str, DAT_BOOLEAN *is_thread_safe); static DAT_RETURN dat_sr_convert_default( char *str, DAT_BOOLEAN *is_default); static DAT_RETURN dat_sr_convert_provider_version( char *str, DAT_SR_PROVIDER_VERSION *provider_version); static DAT_RETURN dat_sr_get_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token); static DAT_RETURN dat_sr_put_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token); static DAT_RETURN dat_sr_read_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token); static DAT_RETURN dat_sr_read_str( DAT_OS_FILE *file, DAT_SR_TOKEN *token, DAT_OS_SIZE token_len); static DAT_RETURN dat_sr_read_quoted_str( DAT_OS_FILE *file, DAT_SR_TOKEN *token, DAT_OS_SIZE token_len, DAT_COUNT num_escape_seq); static void dat_sr_read_comment( DAT_OS_FILE *file); /* * * Global Variables * */ static DAT_SR_STACK_NODE *g_token_stack = NULL; /* * * External Function Definitions * */ /* * Function: dat_sr_load */ DAT_RETURN dat_sr_load(void) { char *sr_path; DAT_OS_FILE *sr_file; sr_path = dat_os_getenv(DAT_SR_CONF_ENV); if (sr_path == NULL) { sr_path = DAT_SR_CONF_DEFAULT; } dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, "DAT Registry: static registry file <%s> \n", sr_path); sr_file = dat_os_fopen(sr_path); if (sr_file == NULL) { return (DAT_INTERNAL_ERROR); } for (;;) { if (DAT_SUCCESS == dat_sr_parse_eof(sr_file)) { break; } else if (DAT_SUCCESS == dat_sr_parse_entry(sr_file)) { continue; } else { dat_os_assert(!"unable to parse static registry file"); break; } } if (0 != dat_os_fclose(sr_file)) { return (DAT_INTERNAL_ERROR); } return (DAT_SUCCESS); } /* * * Internal Function Definitions * */ /* * Function: dat_sr_is_valid_entry */ DAT_BOOLEAN dat_sr_is_valid_entry( DAT_SR_CONF_ENTRY *entry) { if ((DAT_SR_API_UDAT == entry->api_version.type) && (entry->is_default)) { return (DAT_TRUE); } else { return (DAT_FALSE); } } /* * Function: dat_sr_load_entry */ DAT_RETURN dat_sr_load_entry( DAT_SR_CONF_ENTRY *conf_entry) { DAT_SR_ENTRY entry; if (DAT_NAME_MAX_LENGTH < (strlen(conf_entry->ia_name) + 1)) { dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, "DAT Registry: ia name %s is longer than " "DAT_NAME_MAX_LENGTH (%i)\n", conf_entry->ia_name, DAT_NAME_MAX_LENGTH); return (DAT_INSUFFICIENT_RESOURCES); } (void) dat_os_strncpy(entry.info.ia_name, conf_entry->ia_name, DAT_NAME_MAX_LENGTH); entry.info.dapl_version_major = conf_entry->api_version.version.major; entry.info.dapl_version_minor = conf_entry->api_version.version.minor; entry.info.is_thread_safe = conf_entry->is_thread_safe; entry.lib_path = conf_entry->lib_path; entry.ia_params = conf_entry->ia_params; entry.lib_handle = NULL; entry.ref_count = 0; dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, "DAT Registry: loading provider for %s\n", conf_entry->ia_name); return (dat_sr_insert(&entry.info, &entry)); } /* * Function: dat_sr_type_to_str */ char * dat_sr_type_to_str( DAT_SR_TOKEN_TYPE type) { static char *str_array[] = { "string", "eor", "eof" }; if ((type < 0) || (2 < type)) { return ("error: invalid token type"); } return (str_array[type]); } /* * Function: dat_sr_parse_eof */ DAT_RETURN dat_sr_parse_eof( DAT_OS_FILE *file) { DAT_SR_TOKEN token; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_EOF == token.type) { return (DAT_SUCCESS); } else { (void) dat_sr_put_token(file, &token); return (DAT_INTERNAL_ERROR); } } /* * Function: dat_sr_parse_ia_name */ DAT_RETURN dat_sr_parse_entry( DAT_OS_FILE *file) { DAT_SR_CONF_ENTRY entry; DAT_RETURN status; (void) dat_os_memset(&entry, 0, sizeof (DAT_SR_CONF_ENTRY)); if ((DAT_SUCCESS == dat_sr_parse_ia_name(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_api(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_thread_safety(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_default(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_lib_path(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_provider_version(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_ia_params(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_platform_params(file, &entry)) && (DAT_SUCCESS == dat_sr_parse_eoe(file, &entry))) { dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, "\n" "DAT Registry: entry \n" " ia_name %s\n" " api_version\n" " type 0x%X\n" " major.minor %d.%d\n" " is_thread_safe %d\n" " is_default %d\n" " lib_path %s\n" " provider_version\n" " id %s\n" " major.minor %d.%d\n" " ia_params %s\n" "\n", entry.ia_name, entry.api_version.type, entry.api_version.version.major, entry.api_version.version.minor, entry.is_thread_safe, entry.is_default, entry.lib_path, entry.provider_version.id, entry.provider_version.version.major, entry.provider_version.version.minor, entry.ia_params); if (DAT_TRUE == dat_sr_is_valid_entry(&entry)) { /* * The static registry configuration file may have * multiple entries with the same IA name. The first * entry will be installed in the static registry * causing subsequent attempts to register the same IA * name to fail. Therefore the return code from * dat_sr_load_entry() is ignored. */ (void) dat_sr_load_entry(&entry); } status = DAT_SUCCESS; } else { /* resync */ DAT_SR_TOKEN token; /* * The static registry format is specified in the DAT * specification. While the registry file's contents may change * between revisions of the specification, there is no way to * determine the specification version to which the * configuration file conforms. If an entry is found that does * not match the expected format, the entry is discarded * and the parsing of the file continues. There is no way to * determine if the entry was an error or an entry confirming * to an alternate version of specification. */ for (;;) { if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { status = DAT_INTERNAL_ERROR; break; } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_SUCCESS; break; } else { dat_os_free(token.value, (sizeof (char) * dat_os_strlen(token.value)) + 1); continue; } } } /* free resources */ if (NULL != entry.ia_name) { dat_os_free(entry.ia_name, sizeof (char) * (dat_os_strlen(entry.ia_name) + 1)); } if (NULL != entry.lib_path) { dat_os_free(entry.lib_path, sizeof (char) * (dat_os_strlen(entry.lib_path) + 1)); } if (NULL != entry.provider_version.id) { dat_os_free(entry.provider_version.id, sizeof (char) * (dat_os_strlen(entry.provider_version.id) + 1)); } if (NULL != entry.ia_params) { dat_os_free(entry.ia_params, sizeof (char) * (dat_os_strlen(entry.ia_params) + 1)); } return (status); } /* * Function: dat_sr_parse_ia_name */ DAT_RETURN dat_sr_parse_ia_name( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else { entry->ia_name = token.value; status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_ia_name */ DAT_RETURN dat_sr_parse_api( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else if (DAT_SUCCESS != dat_sr_convert_api( token.value, &entry->api_version)) { status = DAT_INTERNAL_ERROR; } else { dat_os_free(token.value, (sizeof (char) * dat_os_strlen(token.value)) + 1); status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_thread_safety */ static DAT_RETURN dat_sr_parse_thread_safety( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else if (DAT_SUCCESS != dat_sr_convert_thread_safety( token.value, &entry->is_thread_safe)) { status = DAT_INTERNAL_ERROR; } else { dat_os_free(token.value, (sizeof (char) * dat_os_strlen(token.value)) + 1); status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_default */ DAT_RETURN dat_sr_parse_default( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else if (DAT_SUCCESS != dat_sr_convert_default( token.value, &entry->is_default)) { status = DAT_INTERNAL_ERROR; } else { dat_os_free(token.value, (sizeof (char) * dat_os_strlen(token.value)) + 1); status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_lib_path */ DAT_RETURN dat_sr_parse_lib_path( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else { entry->lib_path = token.value; status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_provider_version */ DAT_RETURN dat_sr_parse_provider_version( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else if (DAT_SUCCESS != dat_sr_convert_provider_version( token.value, &entry->provider_version)) { status = DAT_INTERNAL_ERROR; } else { dat_os_free(token.value, (sizeof (char) * dat_os_strlen(token.value)) + 1); status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_ia_params */ DAT_RETURN dat_sr_parse_ia_params( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else { entry->ia_params = token.value; status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_platform_params */ DAT_RETURN dat_sr_parse_platform_params( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if (DAT_SR_TOKEN_STRING != token.type) { status = DAT_INTERNAL_ERROR; } else { entry->platform_params = token.value; status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_parse_eoe */ DAT_RETURN dat_sr_parse_eoe( DAT_OS_FILE *file, DAT_SR_CONF_ENTRY *entry) /*ARGSUSED*/ { DAT_SR_TOKEN token; DAT_RETURN status; if (DAT_SUCCESS != dat_sr_get_token(file, &token)) { return (DAT_INTERNAL_ERROR); } if ((DAT_SR_TOKEN_EOF != token.type) && (DAT_SR_TOKEN_EOR != token.type)) { status = DAT_INTERNAL_ERROR; } else { status = DAT_SUCCESS; } if (DAT_SUCCESS != status) { DAT_RETURN status_success; status_success = dat_sr_put_token(file, &token); dat_os_assert(DAT_SUCCESS == status_success); } return (status); } /* * Function: dat_sr_convert_api */ DAT_RETURN dat_sr_convert_api( char *str, DAT_SR_API_VERSION *api_version) { int i; int minor_i; dat_os_assert(0 < dat_os_strlen(str)); if ('u' == str[0]) { api_version->type = DAT_SR_API_UDAT; } else if ('k' == str[0]) { api_version->type = DAT_SR_API_KDAT; } else { return (DAT_INTERNAL_ERROR); } for (i = 1 /* move past initial [u|k] */; '\0' != str[i]; i++) { if ('.' == str[i]) { break; } else if (DAT_TRUE != dat_os_isdigit(str[i])) { return (DAT_INTERNAL_ERROR); } } api_version->version.major = (DAT_UINT32)dat_os_strtol(str + 1, NULL, 10); /* move past '.' */ minor_i = ++i; for (; '\0' != str[i]; i++) { if (DAT_TRUE != dat_os_isdigit(str[i])) { return (DAT_INTERNAL_ERROR); } } api_version->version.minor = (DAT_UINT32)dat_os_strtol(str + minor_i, NULL, 10); if ('\0' != str[i]) { return (DAT_INTERNAL_ERROR); } return (DAT_SUCCESS); } /* * Function: dat_sr_convert_thread_safety */ static DAT_RETURN dat_sr_convert_thread_safety( char *str, DAT_BOOLEAN *is_thread_safe) { if (!dat_os_strncmp(str, DAT_SR_TOKEN_THREADSAFE, dat_os_strlen(DAT_SR_TOKEN_THREADSAFE))) { *is_thread_safe = DAT_TRUE; return (DAT_SUCCESS); } else if (!dat_os_strncmp(str, DAT_SR_TOKEN_NONTHREADSAFE, dat_os_strlen(DAT_SR_TOKEN_NONTHREADSAFE))) { *is_thread_safe = DAT_FALSE; return (DAT_SUCCESS); } else { return (DAT_INTERNAL_ERROR); } } /* * Function: dat_sr_convert_default */ static DAT_RETURN dat_sr_convert_default( char *str, DAT_BOOLEAN *is_default) { if (!dat_os_strncmp(str, DAT_SR_TOKEN_DEFAULT, dat_os_strlen(DAT_SR_TOKEN_DEFAULT))) { *is_default = DAT_TRUE; return (DAT_SUCCESS); } else if (!dat_os_strncmp(str, DAT_SR_TOKEN_NONDEFAULT, dat_os_strlen(DAT_SR_TOKEN_NONDEFAULT))) { *is_default = DAT_FALSE; return (DAT_SUCCESS); } else { return (DAT_INTERNAL_ERROR); } } /* * Function: dat_sr_convert_provider_version */ DAT_RETURN dat_sr_convert_provider_version( char *str, DAT_SR_PROVIDER_VERSION *provider_version) { DAT_RETURN status; int i; int decimal_i; dat_os_assert(0 < dat_os_strlen(str)); dat_os_assert(NULL == provider_version->id); status = DAT_SUCCESS; for (i = 0; '\0' != str[i]; i++) { if ('.' == str[i]) { break; } } /* if no id value was found */ if (0 == i) { status = DAT_INTERNAL_ERROR; goto exit; } if (NULL == (provider_version->id = dat_os_alloc(sizeof (char) * (i + 1)))) { status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; goto exit; } (void) dat_os_strncpy(provider_version->id, str, i); provider_version->id[i] = '\0'; /* move past '.' */ decimal_i = ++i; for (; '\0' != str[i]; i++) { if ('.' == str[i]) { break; } else if (DAT_TRUE != dat_os_isdigit(str[i])) { status = DAT_INTERNAL_ERROR; goto exit; } } /* if no version value was found */ if (decimal_i == i) { status = DAT_INTERNAL_ERROR; goto exit; } provider_version->version.major = (DAT_UINT32) dat_os_strtol(str + decimal_i, NULL, 10); /* move past '.' */ decimal_i = ++i; for (; '\0' != str[i]; i++) { if (DAT_TRUE != dat_os_isdigit(str[i])) { status = DAT_INTERNAL_ERROR; goto exit; } } /* if no version value was found */ if (decimal_i == i) { status = DAT_INTERNAL_ERROR; goto exit; } provider_version->version.minor = (DAT_UINT32) dat_os_strtol(str + decimal_i, NULL, 10); if ('\0' != str[i]) { status = DAT_INTERNAL_ERROR; goto exit; } exit: if (DAT_SUCCESS != status) { if (NULL != provider_version->id) { dat_os_free(provider_version->id, sizeof (char) * (dat_os_strlen(provider_version->id) + 1)); provider_version->id = NULL; } } return (status); } /* * Function: dat_sr_get_token */ DAT_RETURN dat_sr_get_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token) { if (NULL == g_token_stack) { return (dat_sr_read_token(file, token)); } else { DAT_SR_STACK_NODE *top; top = g_token_stack; *token = top->token; g_token_stack = top->next; dat_os_free(top, sizeof (DAT_SR_STACK_NODE)); return (DAT_SUCCESS); } } /* * Function: dat_sr_put_token */ DAT_RETURN dat_sr_put_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token) /*ARGSUSED*/ { DAT_SR_STACK_NODE *top; if (NULL == (top = dat_os_alloc(sizeof (DAT_SR_STACK_NODE)))) { return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); } top->token = *token; top->next = g_token_stack; g_token_stack = top; return (DAT_SUCCESS); } /* * Function: dat_sr_read_token */ DAT_RETURN dat_sr_read_token( DAT_OS_FILE *file, DAT_SR_TOKEN *token) { DAT_OS_FILE_POS pos; DAT_OS_SIZE token_len; DAT_COUNT num_escape_seq; DAT_BOOLEAN is_quoted_str; DAT_BOOLEAN is_prev_char_backslash; /* * The DAT standard does not specify a maximum size for quoted strings. * Therefore the tokenizer must be able to read in a token of arbitrary * size. Instead of allocating a fixed length buffer, the tokenizer * first scans the input a single character at a time looking for the * begining and end of the token. Once the these positions are found, * the entire token is read into memory. By using this algorithm, the * implementation does not place an arbitrary maximum on the token size. */ token_len = 0; num_escape_seq = 0; is_quoted_str = DAT_FALSE; is_prev_char_backslash = DAT_FALSE; for (;;) { DAT_OS_FILE_POS cur_pos; int c; /* if looking for start of the token */ if (0 == token_len) { if (DAT_SUCCESS != dat_os_fgetpos(file, &cur_pos)) { return (DAT_INTERNAL_ERROR); } } c = dat_os_fgetc(file); /* if looking for start of the token */ if (0 == token_len) { if (EOF == c) { token->type = DAT_SR_TOKEN_EOF; token->value = NULL; token->value_len = 0; goto success; } else if (DAT_SR_CHAR_NEWLINE == c) { token->type = DAT_SR_TOKEN_EOR; token->value = NULL; token->value_len = 0; goto success; } else if (dat_os_isblank(c)) { continue; } else if (DAT_SR_CHAR_COMMENT == c) { dat_sr_read_comment(file); continue; } else { if (DAT_SR_CHAR_QUOTE == c) { is_quoted_str = DAT_TRUE; } pos = cur_pos; token_len++; } } else { /* looking for the end of the token */ if (EOF == c) { break; } else if (DAT_SR_CHAR_NEWLINE == c) { /* put back the newline */ (void) dat_os_fungetc(file); break; } else if (!is_quoted_str && dat_os_isblank(c)) { break; } else { token_len++; if ((DAT_SR_CHAR_QUOTE == c) && !is_prev_char_backslash) { break; } else if ((DAT_SR_CHAR_BACKSLASH == c) && !is_prev_char_backslash) { is_prev_char_backslash = DAT_TRUE; num_escape_seq++; } else { is_prev_char_backslash = DAT_FALSE; } } } } /* the token was a string */ if (DAT_SUCCESS != dat_os_fsetpos(file, &pos)) { return (DAT_INTERNAL_ERROR); } if (is_quoted_str) { if (DAT_SUCCESS != dat_sr_read_quoted_str(file, token, token_len, num_escape_seq)) { return (DAT_INTERNAL_ERROR); } } else { if (DAT_SUCCESS != dat_sr_read_str(file, token, token_len)) { return (DAT_INTERNAL_ERROR); } } success: dat_os_dbg_print(DAT_OS_DBG_TYPE_SR, "\n" "DAT Registry: token\n" " type %s\n" " value <%s>\n" "\n", dat_sr_type_to_str(token->type), ((DAT_SR_TOKEN_STRING == token->type) ? token->value : "")); return (DAT_SUCCESS); } /* * Function: dat_sr_read_str */ DAT_RETURN dat_sr_read_str( DAT_OS_FILE *file, DAT_SR_TOKEN *token, DAT_OS_SIZE token_len) { token->type = DAT_SR_TOKEN_STRING; /* +1 for null termination */ token->value_len = sizeof (char) * (token_len + 1); if (NULL == (token->value = dat_os_alloc(token->value_len))) { return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY); } if (token_len != dat_os_fread(file, token->value, token_len)) { dat_os_free(token->value, token->value_len); token->value = NULL; return (DAT_INTERNAL_ERROR); } token->value[token->value_len - 1] = '\0'; return (DAT_SUCCESS); } /* * Function: dat_sr_read_quoted_str */ DAT_RETURN dat_sr_read_quoted_str( DAT_OS_FILE *file, DAT_SR_TOKEN *token, DAT_OS_SIZE token_len, DAT_COUNT num_escape_seq) { DAT_OS_SIZE str_len; DAT_OS_SIZE i; DAT_OS_SIZE j; int c; DAT_RETURN status; DAT_BOOLEAN is_prev_char_backslash; str_len = token_len - 2; /* minus 2 " characters */ is_prev_char_backslash = DAT_FALSE; status = DAT_SUCCESS; token->type = DAT_SR_TOKEN_STRING; /* +1 for null termination */ token->value_len = sizeof (char) * (str_len - num_escape_seq + 1); if (NULL == (token->value = dat_os_alloc(token->value_len))) { status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY; goto exit; } /* throw away " */ if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) { status = DAT_INTERNAL_ERROR; goto exit; } for (i = 0, j = 0; i < str_len; i++) { c = dat_os_fgetc(file); if (EOF == c) { status = DAT_INTERNAL_ERROR; goto exit; } else if ((DAT_SR_CHAR_BACKSLASH == c) && !is_prev_char_backslash) { is_prev_char_backslash = DAT_TRUE; } else { token->value[j] = c; j++; is_prev_char_backslash = DAT_FALSE; } } /* throw away " */ if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) { status = DAT_INTERNAL_ERROR; goto exit; } token->value[token->value_len - 1] = '\0'; exit: if (DAT_SUCCESS != status) { if (NULL != token->value) { dat_os_free(token->value, token->value_len); token->value = NULL; } } return (status); } /* * Function: dat_sr_read_comment */ void dat_sr_read_comment( DAT_OS_FILE *file) { int c; /* read up to an EOR or EOF to move past the comment */ do { c = dat_os_fgetc(file); } while ((DAT_SR_CHAR_NEWLINE != c) && (EOF != c)); /* put back the newline */ (void) dat_os_fungetc(file); }