xref: /illumos-gate/usr/src/lib/udapl/libdat/common/udat_sr_parser.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24  */
25 
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /*
32  *
33  * MODULE: dat_sr_parser.c
34  *
35  * PURPOSE: static registry parser
36  *
37  * $Id: udat_sr_parser.c,v 1.1 2003/07/31 14:04:19 jlentini Exp $
38  */
39 
40 
41 #include "udat_sr_parser.h"
42 #include "dat_sr.h"
43 
44 
45 /*
46  *
47  * Constants
48  *
49  */
50 
51 #define	DAT_SR_CONF_ENV 		"DAT_OVERRIDE"
52 #define	DAT_SR_CONF_DEFAULT 		"/etc/dat/dat.conf"
53 
54 #define	DAT_SR_TOKEN_THREADSAFE 	"threadsafe"
55 #define	DAT_SR_TOKEN_NONTHREADSAFE 	"nonthreadsafe"
56 #define	DAT_SR_TOKEN_DEFAULT 		"default"
57 #define	DAT_SR_TOKEN_NONDEFAULT 	"nondefault"
58 
59 #define	DAT_SR_CHAR_NEWLINE 		'\n'
60 #define	DAT_SR_CHAR_COMMENT 		'#'
61 #define	DAT_SR_CHAR_QUOTE 		'"'
62 #define	DAT_SR_CHAR_BACKSLASH 		'\\'
63 
64 
65 /*
66  *
67  * Enumerations
68  *
69  */
70 
71 typedef enum
72 {
73 	DAT_SR_TOKEN_STRING,	/* text field (both quoted or unquoted)	*/
74 	DAT_SR_TOKEN_EOR,	/* end of record (newline)		*/
75 	DAT_SR_TOKEN_EOF 	/* end of file				*/
76 } DAT_SR_TOKEN_TYPE;
77 
78 typedef enum
79 {
80 	DAT_SR_API_UDAT,
81 	DAT_SR_API_KDAT
82 } DAT_SR_API_TYPE;
83 
84 
85 /*
86  *
87  * Structures
88  *
89  */
90 
91 typedef struct
92 {
93     DAT_SR_TOKEN_TYPE 	type;
94     char		*value; /* valid if type is DAT_SR_TOKEN_STRING */
95     DAT_OS_SIZE 	value_len;
96 } DAT_SR_TOKEN;
97 
98 typedef struct DAT_SR_STACK_NODE
99 {
100     DAT_SR_TOKEN 		token;
101     struct DAT_SR_STACK_NODE    *next;
102 } DAT_SR_STACK_NODE;
103 
104 typedef struct
105 {
106     DAT_UINT32 			major;
107     DAT_UINT32 			minor;
108 } DAT_SR_VERSION;
109 
110 typedef struct
111 {
112     char			*id;
113     DAT_SR_VERSION 		version;
114 } DAT_SR_PROVIDER_VERSION;
115 
116 typedef struct
117 {
118     DAT_SR_API_TYPE 		type;
119     DAT_SR_VERSION 		version;
120 } DAT_SR_API_VERSION;
121 
122 typedef struct
123 {
124     char			*ia_name;
125     DAT_SR_API_VERSION 		api_version;
126     DAT_BOOLEAN 		is_thread_safe;
127     DAT_BOOLEAN 		is_default;
128     char 			*lib_path;
129     DAT_SR_PROVIDER_VERSION 	provider_version;
130     char 			*ia_params;
131     char  			*platform_params;
132 } DAT_SR_CONF_ENTRY;
133 
134 
135 /*
136  *
137  * Internal Function Declarations
138  *
139  */
140 
141 static DAT_RETURN
142 dat_sr_load_entry(
143     DAT_SR_CONF_ENTRY *entry);
144 
145 static DAT_BOOLEAN
146 dat_sr_is_valid_entry(
147     DAT_SR_CONF_ENTRY *entry);
148 
149 static char *
150 dat_sr_type_to_str(
151     DAT_SR_TOKEN_TYPE type);
152 
153 static DAT_RETURN
154 dat_sr_parse_eof(
155     DAT_OS_FILE *file);
156 
157 static DAT_RETURN
158 dat_sr_parse_entry(
159     DAT_OS_FILE *file);
160 
161 static DAT_RETURN
162 dat_sr_parse_ia_name(
163     DAT_OS_FILE *file,
164     DAT_SR_CONF_ENTRY *entry);
165 
166 static DAT_RETURN
167 dat_sr_parse_api(
168     DAT_OS_FILE *file,
169     DAT_SR_CONF_ENTRY *entry);
170 
171 static DAT_RETURN
172 dat_sr_parse_thread_safety(
173     DAT_OS_FILE *file,
174     DAT_SR_CONF_ENTRY *entry);
175 
176 static DAT_RETURN
177 dat_sr_parse_default(
178     DAT_OS_FILE *file,
179     DAT_SR_CONF_ENTRY *entry);
180 
181 static DAT_RETURN
182 dat_sr_parse_lib_path(
183     DAT_OS_FILE *file,
184     DAT_SR_CONF_ENTRY *entry);
185 
186 static DAT_RETURN
187 dat_sr_parse_provider_version(
188     DAT_OS_FILE *file,
189     DAT_SR_CONF_ENTRY *entry);
190 
191 static DAT_RETURN
192 dat_sr_parse_ia_params(
193     DAT_OS_FILE *file,
194     DAT_SR_CONF_ENTRY *entry);
195 
196 static DAT_RETURN
197 dat_sr_parse_platform_params(
198     DAT_OS_FILE *file,
199     DAT_SR_CONF_ENTRY *entry);
200 
201 static DAT_RETURN
202 dat_sr_parse_eoe(
203     DAT_OS_FILE *file,
204     DAT_SR_CONF_ENTRY *entry);
205 
206 static DAT_RETURN
207 dat_sr_convert_api(
208     char *str,
209     DAT_SR_API_VERSION *api_version);
210 
211 static DAT_RETURN
212 dat_sr_convert_thread_safety(
213     char *str,
214     DAT_BOOLEAN *is_thread_safe);
215 
216 static DAT_RETURN
217 dat_sr_convert_default(
218     char *str,
219     DAT_BOOLEAN *is_default);
220 
221 static DAT_RETURN
222 dat_sr_convert_provider_version(
223     char *str,
224     DAT_SR_PROVIDER_VERSION *provider_version);
225 
226 static DAT_RETURN
227 dat_sr_get_token(
228     DAT_OS_FILE *file,
229     DAT_SR_TOKEN *token);
230 
231 static DAT_RETURN
232 dat_sr_put_token(
233     DAT_OS_FILE *file,
234     DAT_SR_TOKEN *token);
235 
236 static DAT_RETURN
237 dat_sr_read_token(
238     DAT_OS_FILE *file,
239     DAT_SR_TOKEN *token);
240 
241 static DAT_RETURN
242 dat_sr_read_str(
243     DAT_OS_FILE *file,
244     DAT_SR_TOKEN *token,
245     DAT_OS_SIZE token_len);
246 
247 static DAT_RETURN
248 dat_sr_read_quoted_str(
249     DAT_OS_FILE *file,
250     DAT_SR_TOKEN *token,
251     DAT_OS_SIZE token_len,
252     DAT_COUNT num_escape_seq);
253 
254 static void
255 dat_sr_read_comment(
256     DAT_OS_FILE *file);
257 
258 
259 /*
260  *
261  * Global Variables
262  *
263  */
264 
265 static DAT_SR_STACK_NODE 	*g_token_stack = NULL;
266 
267 
268 /*
269  *
270  * External Function Definitions
271  *
272  */
273 
274 /*
275  * Function: dat_sr_load
276  */
277 
278 DAT_RETURN
279 dat_sr_load(void)
280 {
281 	char 			*sr_path;
282 	DAT_OS_FILE 		*sr_file;
283 
284 	sr_path = dat_os_getenv(DAT_SR_CONF_ENV);
285 	if (sr_path == NULL) {
286 		sr_path = DAT_SR_CONF_DEFAULT;
287 	}
288 
289 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
290 	    "DAT Registry: static registry file <%s> \n", sr_path);
291 
292 	sr_file = dat_os_fopen(sr_path);
293 	if (sr_file == NULL) {
294 		return (DAT_INTERNAL_ERROR);
295 	}
296 
297 	for (;;) {
298 		if (DAT_SUCCESS == dat_sr_parse_eof(sr_file)) {
299 			break;
300 		} else if (DAT_SUCCESS == dat_sr_parse_entry(sr_file)) {
301 			continue;
302 		} else {
303 			dat_os_assert(!"unable to parse static registry file");
304 			break;
305 		}
306 	}
307 
308 	if (0 != dat_os_fclose(sr_file)) {
309 		return (DAT_INTERNAL_ERROR);
310 	}
311 
312 	return (DAT_SUCCESS);
313 }
314 
315 
316 /*
317  *
318  * Internal Function Definitions
319  *
320  */
321 
322 /*
323  * Function: dat_sr_is_valid_entry
324  */
325 
326 DAT_BOOLEAN
327 dat_sr_is_valid_entry(
328     DAT_SR_CONF_ENTRY *entry)
329 {
330 	if ((DAT_SR_API_UDAT == entry->api_version.type) &&
331 	    (entry->is_default)) {
332 		return (DAT_TRUE);
333 	} else {
334 		return (DAT_FALSE);
335 	}
336 }
337 
338 
339 /*
340  * Function: dat_sr_load_entry
341  */
342 
343 DAT_RETURN
344 dat_sr_load_entry(
345     DAT_SR_CONF_ENTRY *conf_entry)
346 {
347 	DAT_SR_ENTRY entry;
348 
349 	if (DAT_NAME_MAX_LENGTH < (strlen(conf_entry->ia_name) + 1)) {
350 		dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
351 		    "DAT Registry: ia name %s is longer than "
352 		    "DAT_NAME_MAX_LENGTH (%i)\n",
353 		    conf_entry->ia_name, DAT_NAME_MAX_LENGTH);
354 
355 		return (DAT_INSUFFICIENT_RESOURCES);
356 	}
357 
358 	(void) dat_os_strncpy(entry.info.ia_name, conf_entry->ia_name,
359 	    DAT_NAME_MAX_LENGTH);
360 	entry.info.dapl_version_major = conf_entry->api_version.version.major;
361 	entry.info.dapl_version_minor = conf_entry->api_version.version.minor;
362 	entry.info.is_thread_safe = conf_entry->is_thread_safe;
363 	entry.lib_path = conf_entry->lib_path;
364 	entry.ia_params = conf_entry->ia_params;
365 	entry.lib_handle = NULL;
366 	entry.ref_count = 0;
367 
368 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
369 	    "DAT Registry: loading provider for %s\n",
370 	    conf_entry->ia_name);
371 
372 	return (dat_sr_insert(&entry.info, &entry));
373 }
374 
375 
376 /*
377  * Function: dat_sr_type_to_str
378  */
379 
380 char *
381 dat_sr_type_to_str(
382     DAT_SR_TOKEN_TYPE type)
383 {
384 	static char *str_array[] = { "string", "eor", "eof" };
385 
386 	if ((type < 0) || (2 < type)) {
387 		return ("error: invalid token type");
388 	}
389 
390 	return (str_array[type]);
391 }
392 
393 
394 /*
395  * Function: dat_sr_parse_eof
396  */
397 
398 DAT_RETURN
399 dat_sr_parse_eof(
400 	DAT_OS_FILE 		*file)
401 {
402 	DAT_SR_TOKEN 	token;
403 
404 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
405 		return (DAT_INTERNAL_ERROR);
406 	}
407 
408 	if (DAT_SR_TOKEN_EOF == token.type) {
409 		return (DAT_SUCCESS);
410 	} else {
411 		(void) dat_sr_put_token(file, &token);
412 		return (DAT_INTERNAL_ERROR);
413 	}
414 }
415 
416 
417 /*
418  * Function: dat_sr_parse_ia_name
419  */
420 
421 DAT_RETURN
422 dat_sr_parse_entry(
423     DAT_OS_FILE 		*file)
424 {
425 	DAT_SR_CONF_ENTRY		entry;
426 	DAT_RETURN 			status;
427 
428 	(void) dat_os_memset(&entry, 0, sizeof (DAT_SR_CONF_ENTRY));
429 
430 	if ((DAT_SUCCESS == dat_sr_parse_ia_name(file, &entry)) &&
431 	    (DAT_SUCCESS == dat_sr_parse_api(file, &entry)) &&
432 	    (DAT_SUCCESS == dat_sr_parse_thread_safety(file, &entry)) &&
433 	    (DAT_SUCCESS == dat_sr_parse_default(file, &entry)) &&
434 	    (DAT_SUCCESS == dat_sr_parse_lib_path(file, &entry)) &&
435 	    (DAT_SUCCESS == dat_sr_parse_provider_version(file, &entry)) &&
436 	    (DAT_SUCCESS == dat_sr_parse_ia_params(file, &entry)) &&
437 	    (DAT_SUCCESS == dat_sr_parse_platform_params(file, &entry)) &&
438 	    (DAT_SUCCESS == dat_sr_parse_eoe(file, &entry))) {
439 		dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
440 		    "\n"
441 		    "DAT Registry: entry \n"
442 		    " ia_name %s\n"
443 		    " api_version\n"
444 		    "     type 0x%X\n"
445 		    "     major.minor %d.%d\n"
446 		    " is_thread_safe %d\n"
447 		    " is_default %d\n"
448 		    " lib_path %s\n"
449 		    " provider_version\n"
450 		    "     id %s\n"
451 		    "     major.minor %d.%d\n"
452 		    " ia_params %s\n"
453 		    "\n",
454 		    entry.ia_name,
455 		    entry.api_version.type,
456 		    entry.api_version.version.major,
457 		    entry.api_version.version.minor,
458 		    entry.is_thread_safe,
459 		    entry.is_default,
460 		    entry.lib_path,
461 		    entry.provider_version.id,
462 		    entry.provider_version.version.major,
463 		    entry.provider_version.version.minor,
464 		    entry.ia_params);
465 
466 		if (DAT_TRUE == dat_sr_is_valid_entry(&entry)) {
467 			/*
468 			 * The static registry configuration file may have
469 			 * multiple entries with the same IA name. The first
470 			 * entry will be installed in the static registry
471 			 * causing subsequent attempts to register the same IA
472 			 * name to fail. Therefore the return code from
473 			 * dat_sr_load_entry() is ignored.
474 			 */
475 			(void) dat_sr_load_entry(&entry);
476 		}
477 
478 		status = DAT_SUCCESS;
479 	} else { /* resync */
480 		DAT_SR_TOKEN 		token;
481 
482 		/*
483 		 * The static registry format is specified in the DAT
484 		 * specification. While the registry file's contents may change
485 		 * between revisions of the specification, there is no way to
486 		 * determine the specification version to which the
487 		 * configuration file conforms. If an entry is found that does
488 		 * not match the expected format, the entry is discarded
489 		 * and the parsing of the file continues. There is no way to
490 		 * determine if the entry was an error or an entry confirming
491 		 * to an alternate version of specification.
492 		 */
493 
494 		for (;;) {
495 			if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
496 				status = DAT_INTERNAL_ERROR;
497 				break;
498 			}
499 
500 			if (DAT_SR_TOKEN_STRING != token.type) {
501 				status = DAT_SUCCESS;
502 				break;
503 			} else {
504 				dat_os_free(token.value,
505 				    (sizeof (char) *
506 					dat_os_strlen(token.value)) + 1);
507 				continue;
508 			}
509 		}
510 	}
511 
512 	/* free resources */
513 	if (NULL != entry.ia_name) {
514 		dat_os_free(entry.ia_name,
515 		    sizeof (char) * (dat_os_strlen(entry.ia_name) + 1));
516 	}
517 	if (NULL != entry.lib_path) {
518 		dat_os_free(entry.lib_path,
519 		    sizeof (char) * (dat_os_strlen(entry.lib_path) + 1));
520 	}
521 
522 	if (NULL != entry.provider_version.id) {
523 		dat_os_free(entry.provider_version.id,
524 		    sizeof (char) *
525 		    (dat_os_strlen(entry.provider_version.id) + 1));
526 	}
527 
528 	if (NULL != entry.ia_params) {
529 		dat_os_free(entry.ia_params,
530 		    sizeof (char) * (dat_os_strlen(entry.ia_params) + 1));
531 	}
532 
533 	return (status);
534 }
535 
536 
537 /*
538  * Function: dat_sr_parse_ia_name
539  */
540 
541 DAT_RETURN
542 dat_sr_parse_ia_name(
543     DAT_OS_FILE 	*file,
544     DAT_SR_CONF_ENTRY 	*entry)
545 {
546 	DAT_SR_TOKEN 	token;
547 	DAT_RETURN 	status;
548 
549 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
550 		return (DAT_INTERNAL_ERROR);
551 	}
552 
553 	if (DAT_SR_TOKEN_STRING != token.type) {
554 		status = DAT_INTERNAL_ERROR;
555 	} else {
556 		entry->ia_name = token.value;
557 
558 		status = DAT_SUCCESS;
559 	}
560 
561 	if (DAT_SUCCESS != status) {
562 		DAT_RETURN 	status_success;
563 
564 		status_success = dat_sr_put_token(file, &token);
565 		dat_os_assert(DAT_SUCCESS == status_success);
566 	}
567 
568 	return (status);
569 }
570 
571 
572 /*
573  * Function: dat_sr_parse_ia_name
574  */
575 
576 DAT_RETURN
577 dat_sr_parse_api(
578     DAT_OS_FILE 	*file,
579     DAT_SR_CONF_ENTRY 	*entry)
580 {
581 	DAT_SR_TOKEN 	token;
582 	DAT_RETURN 	status;
583 
584 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
585 		return (DAT_INTERNAL_ERROR);
586 	}
587 
588 	if (DAT_SR_TOKEN_STRING != token.type) {
589 		status = DAT_INTERNAL_ERROR;
590 	} else if (DAT_SUCCESS != dat_sr_convert_api(
591 		token.value, &entry->api_version)) {
592 		status = DAT_INTERNAL_ERROR;
593 	} else {
594 		dat_os_free(token.value,
595 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
596 
597 		status = DAT_SUCCESS;
598 	}
599 
600 	if (DAT_SUCCESS != status) {
601 		DAT_RETURN 	status_success;
602 
603 		status_success = dat_sr_put_token(file, &token);
604 		dat_os_assert(DAT_SUCCESS == status_success);
605 	}
606 
607 	return (status);
608 }
609 
610 
611 /*
612  * Function: dat_sr_parse_thread_safety
613  */
614 
615 static DAT_RETURN
616 dat_sr_parse_thread_safety(
617     DAT_OS_FILE 	*file,
618     DAT_SR_CONF_ENTRY 	*entry)
619 {
620 	DAT_SR_TOKEN 	token;
621 	DAT_RETURN 	status;
622 
623 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
624 		return (DAT_INTERNAL_ERROR);
625 	}
626 
627 	if (DAT_SR_TOKEN_STRING != token.type) {
628 		status = DAT_INTERNAL_ERROR;
629 	} else if (DAT_SUCCESS != dat_sr_convert_thread_safety(
630 		token.value, &entry->is_thread_safe)) {
631 		status = DAT_INTERNAL_ERROR;
632 	} else {
633 		dat_os_free(token.value,
634 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
635 
636 		status = DAT_SUCCESS;
637 	}
638 
639 	if (DAT_SUCCESS != status) {
640 		DAT_RETURN 	status_success;
641 
642 		status_success = dat_sr_put_token(file, &token);
643 		dat_os_assert(DAT_SUCCESS == status_success);
644 	}
645 
646 	return (status);
647 }
648 
649 
650 /*
651  * Function: dat_sr_parse_default
652  */
653 
654 DAT_RETURN
655 dat_sr_parse_default(
656     DAT_OS_FILE 	*file,
657     DAT_SR_CONF_ENTRY 	*entry)
658 {
659 	DAT_SR_TOKEN 	token;
660 	DAT_RETURN 	status;
661 
662 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
663 		return (DAT_INTERNAL_ERROR);
664 	}
665 
666 	if (DAT_SR_TOKEN_STRING != token.type) {
667 		status = DAT_INTERNAL_ERROR;
668 	} else if (DAT_SUCCESS != dat_sr_convert_default(
669 		token.value, &entry->is_default)) {
670 		status = DAT_INTERNAL_ERROR;
671 	} else {
672 		dat_os_free(token.value,
673 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
674 
675 		status = DAT_SUCCESS;
676 	}
677 
678 	if (DAT_SUCCESS != status) {
679 		DAT_RETURN 	status_success;
680 
681 		status_success = dat_sr_put_token(file, &token);
682 		dat_os_assert(DAT_SUCCESS == status_success);
683 	}
684 
685 	return (status);
686 }
687 
688 
689 /*
690  * Function: dat_sr_parse_lib_path
691  */
692 
693 DAT_RETURN
694 dat_sr_parse_lib_path(
695     DAT_OS_FILE 	*file,
696     DAT_SR_CONF_ENTRY 	*entry)
697 {
698 	DAT_SR_TOKEN 	token;
699 	DAT_RETURN 	status;
700 
701 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
702 		return (DAT_INTERNAL_ERROR);
703 	}
704 
705 	if (DAT_SR_TOKEN_STRING != token.type) {
706 		status = DAT_INTERNAL_ERROR;
707 	} else {
708 		entry->lib_path = token.value;
709 
710 		status = DAT_SUCCESS;
711 	}
712 
713 	if (DAT_SUCCESS != status) {
714 		DAT_RETURN 	status_success;
715 
716 		status_success = dat_sr_put_token(file, &token);
717 		dat_os_assert(DAT_SUCCESS == status_success);
718 	}
719 
720 	return (status);
721 }
722 
723 /*
724  * Function: dat_sr_parse_provider_version
725  */
726 
727 DAT_RETURN
728 dat_sr_parse_provider_version(
729     DAT_OS_FILE 	*file,
730     DAT_SR_CONF_ENTRY 	*entry)
731 {
732 	DAT_SR_TOKEN 	token;
733 	DAT_RETURN 	status;
734 
735 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
736 		return (DAT_INTERNAL_ERROR);
737 	}
738 
739 	if (DAT_SR_TOKEN_STRING != token.type) {
740 		status = DAT_INTERNAL_ERROR;
741 	} else if (DAT_SUCCESS != dat_sr_convert_provider_version(
742 		token.value, &entry->provider_version)) {
743 		status = DAT_INTERNAL_ERROR;
744 	} else {
745 		dat_os_free(token.value,
746 		    (sizeof (char) * dat_os_strlen(token.value)) + 1);
747 
748 		status = DAT_SUCCESS;
749 	}
750 
751 	if (DAT_SUCCESS != status) {
752 		DAT_RETURN 	status_success;
753 
754 		status_success = dat_sr_put_token(file, &token);
755 		dat_os_assert(DAT_SUCCESS == status_success);
756 	}
757 
758 	return (status);
759 }
760 
761 
762 /*
763  * Function: dat_sr_parse_ia_params
764  */
765 
766 DAT_RETURN
767 dat_sr_parse_ia_params(
768     DAT_OS_FILE *file,
769     DAT_SR_CONF_ENTRY *entry)
770 {
771 	DAT_SR_TOKEN 	token;
772 	DAT_RETURN 	status;
773 
774 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
775 		return (DAT_INTERNAL_ERROR);
776 	}
777 
778 	if (DAT_SR_TOKEN_STRING != token.type) {
779 		status = DAT_INTERNAL_ERROR;
780 	} else {
781 		entry->ia_params = token.value;
782 
783 		status = DAT_SUCCESS;
784 	}
785 
786 	if (DAT_SUCCESS != status) {
787 		DAT_RETURN 	status_success;
788 
789 		status_success = dat_sr_put_token(file, &token);
790 		dat_os_assert(DAT_SUCCESS == status_success);
791 	}
792 
793 	return (status);
794 }
795 
796 
797 /*
798  * Function: dat_sr_parse_platform_params
799  */
800 
801 DAT_RETURN
802 dat_sr_parse_platform_params(
803     DAT_OS_FILE *file,
804     DAT_SR_CONF_ENTRY *entry)
805 {
806 	DAT_SR_TOKEN 	token;
807 	DAT_RETURN 	status;
808 
809 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
810 		return (DAT_INTERNAL_ERROR);
811 	}
812 
813 	if (DAT_SR_TOKEN_STRING != token.type) {
814 		status = DAT_INTERNAL_ERROR;
815 	} else {
816 		entry->platform_params = token.value;
817 
818 		status = DAT_SUCCESS;
819 	}
820 
821 	if (DAT_SUCCESS != status) {
822 		DAT_RETURN 	status_success;
823 
824 		status_success = dat_sr_put_token(file, &token);
825 		dat_os_assert(DAT_SUCCESS == status_success);
826 	}
827 
828 	return (status);
829 }
830 
831 
832 /*
833  * Function: dat_sr_parse_eoe
834  */
835 
836 DAT_RETURN
837 dat_sr_parse_eoe(
838     DAT_OS_FILE *file,
839 	DAT_SR_CONF_ENTRY *entry) /*ARGSUSED*/
840 {
841 	DAT_SR_TOKEN 	token;
842 	DAT_RETURN 	status;
843 
844 	if (DAT_SUCCESS != dat_sr_get_token(file, &token)) {
845 		return (DAT_INTERNAL_ERROR);
846 	}
847 
848 	if ((DAT_SR_TOKEN_EOF != token.type) &&
849 	    (DAT_SR_TOKEN_EOR != token.type)) {
850 		status = DAT_INTERNAL_ERROR;
851 	} else {
852 		status = DAT_SUCCESS;
853 	}
854 
855 	if (DAT_SUCCESS != status) {
856 		DAT_RETURN 	status_success;
857 
858 		status_success = dat_sr_put_token(file, &token);
859 		dat_os_assert(DAT_SUCCESS == status_success);
860 	}
861 
862 	return (status);
863 }
864 
865 
866 /*
867  * Function: dat_sr_convert_api
868  */
869 
870 DAT_RETURN
871 dat_sr_convert_api(
872     char *str,
873     DAT_SR_API_VERSION *api_version)
874 {
875 	int i;
876 	int minor_i;
877 
878 	dat_os_assert(0 < dat_os_strlen(str));
879 
880 	if ('u' == str[0]) {
881 		api_version->type = DAT_SR_API_UDAT;
882 	} else if ('k' == str[0]) {
883 		api_version->type = DAT_SR_API_KDAT;
884 	} else {
885 		return (DAT_INTERNAL_ERROR);
886 	}
887 
888 	for (i = 1 /* move past initial [u|k] */; '\0' != str[i]; i++) {
889 		if ('.' == str[i]) {
890 			break;
891 		} else if (DAT_TRUE != dat_os_isdigit(str[i])) {
892 			return (DAT_INTERNAL_ERROR);
893 		}
894 	}
895 
896 	api_version->version.major = (DAT_UINT32)dat_os_strtol(str + 1, NULL,
897 	    10);
898 
899 	/* move past '.' */
900 	minor_i = ++i;
901 
902 	for (; '\0' != str[i]; i++) {
903 		if (DAT_TRUE != dat_os_isdigit(str[i])) {
904 			return (DAT_INTERNAL_ERROR);
905 		}
906 	}
907 
908 	api_version->version.minor = (DAT_UINT32)dat_os_strtol(str + minor_i,
909 	    NULL, 10);
910 
911 	if ('\0' != str[i]) {
912 		return (DAT_INTERNAL_ERROR);
913 	}
914 
915 	return (DAT_SUCCESS);
916 }
917 
918 
919 /*
920  * Function: dat_sr_convert_thread_safety
921  */
922 
923 static DAT_RETURN
924 dat_sr_convert_thread_safety(
925     char *str,
926     DAT_BOOLEAN *is_thread_safe)
927 {
928 	if (!dat_os_strncmp(str,
929 	    DAT_SR_TOKEN_THREADSAFE,
930 	    dat_os_strlen(DAT_SR_TOKEN_THREADSAFE))) {
931 		*is_thread_safe = DAT_TRUE;
932 		return (DAT_SUCCESS);
933 	} else if (!dat_os_strncmp(str,
934 	    DAT_SR_TOKEN_NONTHREADSAFE,
935 	    dat_os_strlen(DAT_SR_TOKEN_NONTHREADSAFE))) {
936 		*is_thread_safe = DAT_FALSE;
937 		return (DAT_SUCCESS);
938 	} else {
939 		return (DAT_INTERNAL_ERROR);
940 	}
941 }
942 
943 
944 /*
945  * Function: dat_sr_convert_default
946  */
947 
948 static DAT_RETURN
949 dat_sr_convert_default(
950     char *str,
951     DAT_BOOLEAN *is_default)
952 {
953 	if (!dat_os_strncmp(str,
954 	    DAT_SR_TOKEN_DEFAULT,
955 	    dat_os_strlen(DAT_SR_TOKEN_DEFAULT))) {
956 		*is_default = DAT_TRUE;
957 		return (DAT_SUCCESS);
958 	} else if (!dat_os_strncmp(str,
959 	    DAT_SR_TOKEN_NONDEFAULT,
960 	    dat_os_strlen(DAT_SR_TOKEN_NONDEFAULT))) {
961 		*is_default = DAT_FALSE;
962 		return (DAT_SUCCESS);
963 	} else {
964 		return (DAT_INTERNAL_ERROR);
965 	}
966 }
967 
968 
969 /*
970  * Function: dat_sr_convert_provider_version
971  */
972 
973 DAT_RETURN
974 dat_sr_convert_provider_version(
975     char *str,
976     DAT_SR_PROVIDER_VERSION *provider_version)
977 {
978 	DAT_RETURN 	status;
979 	int 		i;
980 	int 		decimal_i;
981 
982 	dat_os_assert(0 < dat_os_strlen(str));
983 	dat_os_assert(NULL == provider_version->id);
984 
985 	status = DAT_SUCCESS;
986 
987 	for (i = 0; '\0' != str[i]; i++) {
988 		if ('.' == str[i]) {
989 			break;
990 		}
991 	}
992 
993 	/* if no id value was found */
994 	if (0 == i) {
995 		status = DAT_INTERNAL_ERROR;
996 		goto exit;
997 	}
998 
999 	if (NULL == (provider_version->id = dat_os_alloc(sizeof (char) *
1000 	    (i + 1)))) {
1001 		status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY;
1002 		goto exit;
1003 	}
1004 
1005 	(void) dat_os_strncpy(provider_version->id, str, i);
1006 	provider_version->id[i] = '\0';
1007 
1008 	/* move past '.' */
1009 	decimal_i = ++i;
1010 
1011 	for (; '\0' != str[i]; i++) {
1012 		if ('.' == str[i]) {
1013 			break;
1014 		} else if (DAT_TRUE != dat_os_isdigit(str[i])) {
1015 			status = DAT_INTERNAL_ERROR;
1016 			goto exit;
1017 		}
1018 	}
1019 
1020 	/* if no version value was found */
1021 	if (decimal_i == i) {
1022 		status = DAT_INTERNAL_ERROR;
1023 		goto exit;
1024 	}
1025 
1026 	provider_version->version.major = (DAT_UINT32)
1027 	    dat_os_strtol(str + decimal_i, NULL, 10);
1028 
1029 	/* move past '.' */
1030 	decimal_i = ++i;
1031 
1032 	for (; '\0' != str[i]; i++) {
1033 		if (DAT_TRUE != dat_os_isdigit(str[i])) {
1034 			status = DAT_INTERNAL_ERROR;
1035 			goto exit;
1036 		}
1037 	}
1038 
1039 	/* if no version value was found */
1040 	if (decimal_i == i) {
1041 		status = DAT_INTERNAL_ERROR;
1042 		goto exit;
1043 	}
1044 
1045 	provider_version->version.minor = (DAT_UINT32)
1046 	    dat_os_strtol(str + decimal_i, NULL, 10);
1047 
1048 	if ('\0' != str[i]) {
1049 		status = DAT_INTERNAL_ERROR;
1050 		goto exit;
1051 	}
1052 
1053 exit:
1054 	if (DAT_SUCCESS != status) {
1055 		if (NULL != provider_version->id) {
1056 			dat_os_free(provider_version->id,
1057 			    sizeof (char) *
1058 			    (dat_os_strlen(provider_version->id) + 1));
1059 			provider_version->id = NULL;
1060 		}
1061 	}
1062 
1063 	return (status);
1064 }
1065 
1066 
1067 /*
1068  * Function: dat_sr_get_token
1069  */
1070 
1071 DAT_RETURN
1072 dat_sr_get_token(
1073     DAT_OS_FILE *file,
1074     DAT_SR_TOKEN *token)
1075 {
1076 	if (NULL == g_token_stack) {
1077 		return (dat_sr_read_token(file, token));
1078 	} else {
1079 		DAT_SR_STACK_NODE *top;
1080 
1081 		top = g_token_stack;
1082 
1083 		*token = top->token;
1084 		g_token_stack = top->next;
1085 
1086 		dat_os_free(top, sizeof (DAT_SR_STACK_NODE));
1087 
1088 		return (DAT_SUCCESS);
1089 	}
1090 }
1091 
1092 
1093 /*
1094  * Function: dat_sr_put_token
1095  */
1096 
1097 DAT_RETURN
1098 dat_sr_put_token(
1099     DAT_OS_FILE *file,
1100 	DAT_SR_TOKEN *token) /*ARGSUSED*/
1101 {
1102 	DAT_SR_STACK_NODE *top;
1103 
1104 	if (NULL == (top = dat_os_alloc(sizeof (DAT_SR_STACK_NODE)))) {
1105 		return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
1106 	}
1107 
1108 	top->token = *token;
1109 	top->next = g_token_stack;
1110 	g_token_stack = top;
1111 
1112 	return (DAT_SUCCESS);
1113 }
1114 
1115 
1116 /*
1117  * Function: dat_sr_read_token
1118  */
1119 
1120 DAT_RETURN
1121 dat_sr_read_token(
1122     DAT_OS_FILE 		*file,
1123     DAT_SR_TOKEN 		*token)
1124 {
1125 	DAT_OS_FILE_POS 	pos;
1126 	DAT_OS_SIZE 		token_len;
1127 	DAT_COUNT 		num_escape_seq;
1128 	DAT_BOOLEAN 		is_quoted_str;
1129 	DAT_BOOLEAN 		is_prev_char_backslash;
1130 
1131 	/*
1132 	 * The DAT standard does not specify a maximum size for quoted strings.
1133 	 * Therefore the tokenizer must be able to read in a token of arbitrary
1134 	 * size. Instead of allocating a fixed length buffer, the tokenizer
1135 	 * first scans the input a single character at a time looking for the
1136 	 * begining and end of the token. Once the these positions are found,
1137 	 * the entire token is read into memory. By using this algorithm, the
1138 	 * implementation does not place an arbitrary maximum on the token size.
1139 	 */
1140 
1141 	token_len = 0;
1142 	num_escape_seq = 0;
1143 	is_quoted_str = DAT_FALSE;
1144 	is_prev_char_backslash = DAT_FALSE;
1145 
1146 	for (;;) {
1147 		DAT_OS_FILE_POS cur_pos;
1148 		int c;
1149 
1150 		/* if looking for start of the token */
1151 		if (0 == token_len) {
1152 			if (DAT_SUCCESS != dat_os_fgetpos(file, &cur_pos)) {
1153 				return (DAT_INTERNAL_ERROR);
1154 			}
1155 		}
1156 
1157 		c = dat_os_fgetc(file);
1158 
1159 		/* if looking for start of the token */
1160 		if (0 == token_len) {
1161 			if (EOF == c) {
1162 				token->type = DAT_SR_TOKEN_EOF;
1163 				token->value = NULL;
1164 				token->value_len = 0;
1165 				goto success;
1166 			} else if (DAT_SR_CHAR_NEWLINE == c) {
1167 				token->type = DAT_SR_TOKEN_EOR;
1168 				token->value = NULL;
1169 				token->value_len = 0;
1170 				goto success;
1171 			} else if (dat_os_isblank(c)) {
1172 				continue;
1173 			} else if (DAT_SR_CHAR_COMMENT == c) {
1174 				dat_sr_read_comment(file);
1175 				continue;
1176 			} else {
1177 				if (DAT_SR_CHAR_QUOTE == c) {
1178 					is_quoted_str = DAT_TRUE;
1179 				}
1180 
1181 				pos = cur_pos;
1182 				token_len++;
1183 			}
1184 		} else { /* looking for the end of the token */
1185 			if (EOF == c) {
1186 				break;
1187 			} else if (DAT_SR_CHAR_NEWLINE == c) {
1188 				/* put back the newline */
1189 				(void) dat_os_fungetc(file);
1190 				break;
1191 			} else if (!is_quoted_str && dat_os_isblank(c)) {
1192 				break;
1193 			} else {
1194 				token_len++;
1195 
1196 				if ((DAT_SR_CHAR_QUOTE == c) &&
1197 				    !is_prev_char_backslash) {
1198 					break;
1199 				} else if ((DAT_SR_CHAR_BACKSLASH == c) &&
1200 				    !is_prev_char_backslash) {
1201 					is_prev_char_backslash = DAT_TRUE;
1202 					num_escape_seq++;
1203 				} else {
1204 					is_prev_char_backslash = DAT_FALSE;
1205 				}
1206 			}
1207 		}
1208 	}
1209 
1210 	/* the token was a string */
1211 	if (DAT_SUCCESS != dat_os_fsetpos(file, &pos)) {
1212 		return (DAT_INTERNAL_ERROR);
1213 	}
1214 
1215 	if (is_quoted_str) {
1216 		if (DAT_SUCCESS != dat_sr_read_quoted_str(file,
1217 		    token,
1218 		    token_len,
1219 		    num_escape_seq)) {
1220 			return (DAT_INTERNAL_ERROR);
1221 		}
1222 	} else {
1223 		if (DAT_SUCCESS != dat_sr_read_str(file,
1224 		    token,
1225 		    token_len)) {
1226 			return (DAT_INTERNAL_ERROR);
1227 		}
1228 	}
1229 
1230 success:
1231 	dat_os_dbg_print(DAT_OS_DBG_TYPE_SR,
1232 	    "\n"
1233 	    "DAT Registry: token\n"
1234 	    " type  %s\n"
1235 	    " value <%s>\n"
1236 	    "\n",
1237 	    dat_sr_type_to_str(token->type),
1238 	    ((DAT_SR_TOKEN_STRING == token->type) ? token->value : ""));
1239 
1240 	return (DAT_SUCCESS);
1241 }
1242 
1243 
1244 /*
1245  * Function: dat_sr_read_str
1246  */
1247 
1248 DAT_RETURN
1249 dat_sr_read_str(
1250     DAT_OS_FILE *file,
1251     DAT_SR_TOKEN *token,
1252     DAT_OS_SIZE token_len)
1253 {
1254 	token->type = DAT_SR_TOKEN_STRING;
1255 	/* +1 for null termination */
1256 	token->value_len = sizeof (char) * (token_len + 1);
1257 	if (NULL == (token->value = dat_os_alloc(token->value_len))) {
1258 		return (DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY);
1259 	}
1260 
1261 	if (token_len != dat_os_fread(file, token->value, token_len)) {
1262 		dat_os_free(token->value, token->value_len);
1263 		token->value = NULL;
1264 
1265 		return (DAT_INTERNAL_ERROR);
1266 	}
1267 
1268 	token->value[token->value_len - 1] = '\0';
1269 
1270 	return (DAT_SUCCESS);
1271 }
1272 
1273 
1274 /*
1275  * Function: dat_sr_read_quoted_str
1276  */
1277 
1278 DAT_RETURN
1279 dat_sr_read_quoted_str(
1280     DAT_OS_FILE 	*file,
1281     DAT_SR_TOKEN 	*token,
1282     DAT_OS_SIZE 	token_len,
1283     DAT_COUNT 		num_escape_seq)
1284 {
1285 	DAT_OS_SIZE 	str_len;
1286 	DAT_OS_SIZE 	i;
1287 	DAT_OS_SIZE 	j;
1288 	int 		c;
1289 	DAT_RETURN 	status;
1290 	DAT_BOOLEAN 	is_prev_char_backslash;
1291 
1292 	str_len = token_len - 2; /* minus 2 " characters */
1293 	is_prev_char_backslash = DAT_FALSE;
1294 	status = DAT_SUCCESS;
1295 
1296 	token->type = DAT_SR_TOKEN_STRING;
1297 	/* +1 for null termination */
1298 	token->value_len = sizeof (char) * (str_len - num_escape_seq + 1);
1299 
1300 	if (NULL == (token->value = dat_os_alloc(token->value_len))) {
1301 		status = DAT_INSUFFICIENT_RESOURCES | DAT_RESOURCE_MEMORY;
1302 		goto exit;
1303 	}
1304 
1305 	/* throw away " */
1306 	if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) {
1307 		status = DAT_INTERNAL_ERROR;
1308 		goto exit;
1309 	}
1310 
1311 	for (i = 0, j = 0; i < str_len; i++) {
1312 		c = dat_os_fgetc(file);
1313 
1314 		if (EOF == c) {
1315 			status = DAT_INTERNAL_ERROR;
1316 			goto exit;
1317 		} else if ((DAT_SR_CHAR_BACKSLASH == c) &&
1318 		    !is_prev_char_backslash) {
1319 			is_prev_char_backslash = DAT_TRUE;
1320 		} else {
1321 			token->value[j] = c;
1322 			j++;
1323 
1324 			is_prev_char_backslash = DAT_FALSE;
1325 		}
1326 	}
1327 
1328 	/* throw away " */
1329 	if (DAT_SR_CHAR_QUOTE != dat_os_fgetc(file)) {
1330 		status = DAT_INTERNAL_ERROR;
1331 		goto exit;
1332 	}
1333 
1334 	token->value[token->value_len - 1] = '\0';
1335 
1336 exit:
1337 	if (DAT_SUCCESS != status) {
1338 		if (NULL != token->value) {
1339 			dat_os_free(token->value, token->value_len);
1340 			token->value = NULL;
1341 		}
1342 	}
1343 
1344 	return (status);
1345 }
1346 
1347 
1348 /*
1349  * Function: dat_sr_read_comment
1350  */
1351 
1352 void
1353 dat_sr_read_comment(
1354     DAT_OS_FILE *file)
1355 {
1356 	int c;
1357 
1358 	/* read up to an EOR or EOF to move past the comment */
1359 	do {
1360 		c = dat_os_fgetc(file);
1361 	} while ((DAT_SR_CHAR_NEWLINE != c) && (EOF != c));
1362 
1363 	/* put back the newline */
1364 	(void) dat_os_fungetc(file);
1365 }
1366