1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0.  If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*! \file */
15 
16 #include <isc/commandline.h>
17 #include <isc/lex.h>
18 #include <isc/mem.h>
19 #include <isc/print.h>
20 #include <isc/util.h>
21 
22 isc_mem_t *mctx;
23 isc_lex_t *lex;
24 
25 isc_lexspecials_t specials;
26 
27 static void
print_token(isc_token_t * tokenp,FILE * stream)28 print_token(isc_token_t *tokenp, FILE *stream) {
29 	switch (tokenp->type) {
30 	case isc_tokentype_unknown:
31 		fprintf(stream, "UNKNOWN");
32 		break;
33 	case isc_tokentype_string:
34 		fprintf(stream, "STRING %.*s",
35 			(int)tokenp->value.as_region.length,
36 			tokenp->value.as_region.base);
37 		break;
38 	case isc_tokentype_number:
39 		fprintf(stream, "NUMBER %lu", tokenp->value.as_ulong);
40 		break;
41 	case isc_tokentype_qstring:
42 		fprintf(stream, "QSTRING \"%.*s\"",
43 			(int)tokenp->value.as_region.length,
44 			tokenp->value.as_region.base);
45 		break;
46 	case isc_tokentype_eol:
47 		fprintf(stream, "EOL");
48 		break;
49 	case isc_tokentype_eof:
50 		fprintf(stream, "EOF");
51 		break;
52 	case isc_tokentype_initialws:
53 		fprintf(stream, "INITIALWS");
54 		break;
55 	case isc_tokentype_special:
56 		fprintf(stream, "SPECIAL %c", tokenp->value.as_char);
57 		break;
58 	case isc_tokentype_nomore:
59 		fprintf(stream, "NOMORE");
60 		break;
61 	default:
62 		FATAL_ERROR(__FILE__, __LINE__, "Unexpected type %d",
63 			    tokenp->type);
64 	}
65 }
66 
67 int
main(int argc,char * argv[])68 main(int argc, char *argv[]) {
69 	isc_token_t token;
70 	isc_result_t result;
71 	int quiet = 0;
72 	int c;
73 	int masterfile = 1;
74 	int stats = 0;
75 	unsigned int options = 0;
76 	int done = 0;
77 
78 	while ((c = isc_commandline_parse(argc, argv, "qmcs")) != -1) {
79 		switch (c) {
80 		case 'q':
81 			quiet = 1;
82 			break;
83 		case 'm':
84 			masterfile = 1;
85 			break;
86 		case 'c':
87 			masterfile = 0;
88 			break;
89 		case 's':
90 			stats = 1;
91 			break;
92 		}
93 	}
94 
95 	isc_mem_create(&mctx);
96 	RUNTIME_CHECK(isc_lex_create(mctx, 256, &lex) == ISC_R_SUCCESS);
97 
98 	if (masterfile) {
99 		/* Set up to lex DNS master file. */
100 
101 		specials['('] = 1;
102 		specials[')'] = 1;
103 		specials['"'] = 1;
104 		isc_lex_setspecials(lex, specials);
105 		options = ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE |
106 			  ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING |
107 			  ISC_LEXOPT_NOMORE;
108 		isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
109 	} else {
110 		/* Set up to lex DNS config file. */
111 
112 		specials['{'] = 1;
113 		specials['}'] = 1;
114 		specials[';'] = 1;
115 		specials['/'] = 1;
116 		specials['"'] = 1;
117 		specials['!'] = 1;
118 		specials['*'] = 1;
119 		isc_lex_setspecials(lex, specials);
120 		options = ISC_LEXOPT_EOF | ISC_LEXOPT_QSTRING |
121 			  ISC_LEXOPT_NUMBER | ISC_LEXOPT_NOMORE;
122 		isc_lex_setcomments(lex, (ISC_LEXCOMMENT_C |
123 					  ISC_LEXCOMMENT_CPLUSPLUS |
124 					  ISC_LEXCOMMENT_SHELL));
125 	}
126 
127 	RUNTIME_CHECK(isc_lex_openstream(lex, stdin) == ISC_R_SUCCESS);
128 
129 	while ((result = isc_lex_gettoken(lex, options, &token)) ==
130 		       ISC_R_SUCCESS &&
131 	       !done)
132 	{
133 		if (!quiet) {
134 			char *name = isc_lex_getsourcename(lex);
135 			print_token(&token, stdout);
136 			printf(" line = %lu file = %s\n",
137 			       isc_lex_getsourceline(lex),
138 			       (name == NULL) ? "<none>" : name);
139 		}
140 		if (token.type == isc_tokentype_eof) {
141 			isc_lex_close(lex);
142 		}
143 		if (token.type == isc_tokentype_nomore) {
144 			done = 1;
145 		}
146 	}
147 	if (result != ISC_R_SUCCESS) {
148 		printf("Result: %s\n", isc_result_totext(result));
149 	}
150 
151 	isc_lex_close(lex);
152 	isc_lex_destroy(&lex);
153 	if (!quiet && stats) {
154 		isc_mem_stats(mctx, stdout);
155 	}
156 	isc_mem_destroy(&mctx);
157 
158 	return (0);
159 }
160