<commit_before>/*
 * Copyright (C) 1998, 1999, 2000  Internet Software Consortium.
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/* $Id: gen.c,v 1.43 2000/05/03 20:24:03 gson Exp $ */

#include <config.h>

#include <sys/types.h>

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifdef WIN32
#include "gen-win32.h"
#else
#include "gen-unix.h"
#endif

#define FROMTEXTDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, isc_lex_t *lexer, dns_name_t *origin, isc_boolean_t downcase, isc_buffer_t *target"
#define FROMTEXTARGS "rdclass, type, lexer, origin, downcase, target"
#define FROMTEXTCLASS "rdclass"
#define FROMTEXTTYPE "type"
#define FROMTEXTDEF "use_default = ISC_TRUE"

#define TOTEXTDECL "dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target"
#define TOTEXTARGS "rdata, tctx, target"
#define TOTEXTCLASS "rdata->rdclass"
#define TOTEXTTYPE "rdata->type"
#define TOTEXTDEF "use_default = ISC_TRUE"

#define FROMWIREDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, isc_buffer_t *source, dns_decompress_t *dctx, isc_boolean_t downcase, isc_buffer_t *target"
#define FROMWIREARGS "rdclass, type, source, dctx, downcase, target"
#define FROMWIRECLASS "rdclass"
#define FROMWIRETYPE "type"
#define FROMWIREDEF "use_default = ISC_TRUE"

#define TOWIREDECL "dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target"
#define TOWIREARGS "rdata, cctx, target"
#define TOWIRECLASS "rdata->rdclass"
#define TOWIRETYPE "rdata->type"
#define TOWIREDEF "use_default = ISC_TRUE"

#define FROMSTRUCTDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target"
#define FROMSTRUCTARGS "rdclass, type, source, target"
#define FROMSTRUCTCLASS "rdclass"
#define FROMSTRUCTTYPE "type"
#define FROMSTRUCTDEF "use_default = ISC_TRUE"

#define TOSTRUCTDECL "dns_rdata_t *rdata, void *target, isc_mem_t *mctx"
#define TOSTRUCTARGS "rdata, target, mctx"
#define TOSTRUCTCLASS "rdata->rdclass"
#define TOSTRUCTTYPE "rdata->type"
#define TOSTRUCTDEF "use_default = ISC_TRUE"

#define FREESTRUCTDECL "void *source"
#define FREESTRUCTARGS "source"
#define FREESTRUCTCLASS "common->rdclass"
#define FREESTRUCTTYPE "common->rdtype"
#define FREESTRUCTDEF NULL

#define COMPAREDECL "dns_rdata_t *rdata1, dns_rdata_t *rdata2"
#define COMPAREARGS "rdata1, rdata2"
#define COMPARECLASS "rdata1->rdclass"
#define COMPARETYPE "rdata1->type"
#define COMPAREDEF "use_default = ISC_TRUE"

#define ADDITIONALDATADECL \
	"dns_rdata_t *rdata, dns_additionaldatafunc_t add, void *arg"
#define ADDITIONALDATAARGS "rdata, add, arg"
#define ADDITIONALDATACLASS "rdata->rdclass"
#define ADDITIONALDATATYPE "rdata->type"
#define ADDITIONALDATADEF "use_default = ISC_TRUE"

#define DIGESTDECL \
	"dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg"
#define DIGESTARGS "rdata, digest, arg"
#define DIGESTCLASS "rdata->rdclass"
#define DIGESTTYPE "rdata->type"
#define DIGESTDEF "use_default = ISC_TRUE"

char copyright[] =
"/*\n\
 * Copyright (C) 1998%s Internet Software Consortium.\n\
 *\n\
 * Permission to use, copy, modify, and distribute this software for any\n\
 * purpose with or without fee is hereby granted, provided that the above\n\
 * copyright notice and this permission notice appear in all copies.\n\
 *\n\
 * THE SOFTWARE IS PROVIDED \"AS IS\" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS\n\
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES\n\
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE\n\
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n\
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n\
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n\
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\n\
 * SOFTWARE.\n\
 */\n\
\n\
/* THIS FILE IS AUTOMATICALLY GENERATED: DO NOT EDIT */\n\
\n";

struct cc {
	struct cc *next;
	int rdclass;
	char classname[11];
} *classes;

struct tt {
	struct tt *next;
	int rdclass;
	int type;
	char classname[11];
	char typename[11];
	char dirname[256];		/* XXX Should be max path length */
} *types;

struct ttnam {
	char typename[11];
	char macroname[11];
	char attr[256];
	unsigned int sorted;
} typenames[256];

char *	upper(char *);
char *	funname(char *, char *);
void	doswitch(char *, char *, char *, char *, char *, char *);
void	dodecl(char *, char *, char *);
void	add(int, char *, int, char *, char *);
void	sd(int, char *, char *, char);
void	insert_into_typenames(int, char *, char *);

/*
 * If you use more than 10 of these in, say, a printf(), you'll have problems.
 */
char *
upper(char *s) {
	static int buf_to_use = 0;
	static char buf[10][256];
	char *b;
	int c;

	buf_to_use++;
	if (buf_to_use > 9)
		buf_to_use = 0;

	b = buf[buf_to_use];
	memset(b, 0, 256);

	while ((c = (*s++) & 0xff))
		*b++ = islower(c) ? toupper(c) : c;
	*b = '\0';
	return (buf[buf_to_use]);
}

char *
funname(char *s, char *buf) {
	char *b = buf;
	char c;

	while ((c = *s++)) {
		*b++ = (c == '-') ? '_' : c;
	}
	*b = '\0';
	return (buf);
}

void
doswitch(char *name, char *function, char *args,
	 char *tsw, char *csw, char *res)
{
	struct tt *tt;
	int first = 1;
	int lasttype = 0;
	int subswitch = 0;
	char buf1[11], buf2[11];
	char *result = " result =";

	if (res == NULL)
		result = "";

	for (tt = types; tt != NULL ; tt = tt->next) {
		if (first) {
			fprintf(stdout, "\n#define %s \\\n", name);
			fprintf(stdout, "\tswitch (%s) { \\\n" /*}*/, tsw);
			first = 0;
		}
		if (tt->type != lasttype && subswitch) {
			if (res == NULL)
				fprintf(stdout, "\t\tdefault: break; \\\n");
			else
				fprintf(stdout,
					"\t\tdefault: %s; break; \\\n", res);
			fputs(/*{*/ "\t\t} \\\n", stdout);
			fputs("\t\tbreak; \\\n", stdout);
			subswitch = 0;
		}
		if (tt->rdclass && tt->type != lasttype) {
			fprintf(stdout, "\tcase %d: switch (%s) { \\\n" /*}*/,
				tt->type, csw);
			subswitch = 1;
		}
		if (tt->rdclass == 0)
			fprintf(stdout,
				"\tcase %d:%s %s_%s(%s); break;",
				tt->type, result, function,
				funname(tt->typename, buf1), args);
		else
			fprintf(stdout,
			        "\t\tcase %d:%s %s_%s_%s(%s); break;",
				tt->rdclass, result, function, 
				funname(tt->classname, buf1),
				funname(tt->typename, buf2), args);
		fputs(" \\\n", stdout);
		lasttype = tt->type;
	}
	if (subswitch) {
		if (res == NULL)
			fprintf(stdout, "\t\tdefault: break; \\\n");
		else 
			fprintf(stdout, "\t\tdefault: %s; break; \\\n", res);
		fputs(/*{*/ "\t\t} \\\n", stdout);
		fputs("\t\tbreak; \\\n", stdout);
	}
	if (first) {
		if (res == NULL)
			fprintf(stdout, "\n#define %s\n", name);
		else
			fprintf(stdout, "\n#define %s %s;\n", name, res);
	} else {
		if (res == NULL)
			fprintf(stdout, "\tdefault: break; \\\n");
		else
			fprintf(stdout, "\tdefault: %s; break; \\\n", res);
		fputs(/*{*/ "\t}\n", stdout);
	}
}

void
dodecl(char *type, char *function, char *args) {
	struct tt *tt;
	char buf1[11], buf2[11];

	fputs("\n", stdout);
	for (tt = types; tt ; tt = tt->next)
		if (tt->rdclass)
			fprintf(stdout,
				"static inline %s %s_%s_%s(%s);\n",
				type, function,
				funname(tt->classname, buf1),
				funname(tt->typename, buf2), args);
		else
			fprintf(stdout,
				"static inline %s %s_%s(%s);\n",
				type, function, 
				funname(tt->typename, buf1), args);
}

void
insert_into_typenames(int type, char *typename, char *attr)
{
	struct ttnam *ttn;
	int c;
	char tmp[256];

	ttn = &typenames[type];
	if (ttn->typename[0] == 0) {
		if (strlen(typename) > sizeof(ttn->typename) - 1) {
			fprintf(stderr, "Error:  type name %s is too long\n",
				typename);
			exit(1);
		}
		strcpy(ttn->typename, typename);
	} else if (strcmp(typename, ttn->typename) != 0) {
		fprintf(stderr, "Error:  type %d has two names: %s, %s\n",
			type, ttn->typename, typename);
		exit(1);
	}

	strcpy(ttn->macroname, ttn->typename);
	c = strlen(ttn->macroname);
	while (c > 0) {
		if (ttn->macroname[c - 1] == '-')
			ttn->macroname[c - 1] = '_';
		c--;
	}

	if (attr == NULL) {
		sprintf(tmp, "RRTYPE_%s_ATTRIBUTES", upper(ttn->macroname));
		attr = tmp;
	}

	if (ttn->attr[0] != 0 && strcmp(attr, ttn->attr) != 0) {
		fprintf(stderr, "Error:  type %d has different attributes: "
			"%s, %s\n", type, ttn->attr, attr);
		exit(1);
	}

	if (strlen(attr) > sizeof(ttn->attr) - 1) {
		fprintf(stderr, "Error:  attr (%s) [name %s] is too long\n",
			attr, typename);
		exit(1);
	}
	strcpy(ttn->attr, attr);
	ttn->sorted = 0;
}

void
add(int rdclass, char *classname, int type, char *typename, char *dirname) {
	struct tt *newtt = (struct tt *)malloc(sizeof *newtt);
	struct tt *tt, *oldtt;
	struct cc *newcc;
	struct cc *cc, *oldcc;

	insert_into_typenames(type, typename, NULL);

	if (newtt == NULL) {
		fprintf(stderr, "malloc() failed\n");
		exit(1);
	}

	newtt->next = NULL;
	newtt->rdclass = rdclass;
	newtt->type = type;
	strcpy(newtt->classname, classname);
	strcpy(newtt->typename, typename);
	strcpy(newtt->dirname, dirname);

	tt = types;
	oldtt = NULL;

	while ((tt != NULL) && (tt->type < type)) {
		oldtt = tt;
		tt = tt->next;
	}

	while ((tt != NULL) && (tt->type == type) && (tt->rdclass < rdclass)) {
		if (strcmp(tt->typename, typename) != 0)
			exit(1);
		oldtt = tt;
		tt = tt->next;
	}

	if ((tt != NULL) && (tt->type == type) && (tt->rdclass == rdclass))
		exit(1);

	newtt->next = tt;
	if (oldtt != NULL)
		oldtt->next = newtt;
	else
		types = newtt;

	/* do a class switch for this type */
	 
	if (rdclass == 0)
		return;

	newcc = (struct cc *)malloc(sizeof *newcc);
	newcc->rdclass = rdclass;
	strcpy(newcc->classname, classname);
	cc = classes;
	oldcc = NULL;
	
	while ((cc != NULL) && (cc->rdclass < rdclass)) {
		oldcc = cc;
		cc = cc->next;
	}

	if ((cc != NULL) && cc->rdclass == rdclass) {
		free((char *)newcc);
		return;
	}

	newcc->next = cc;
	if (oldcc != NULL)
		oldcc->next = newcc;
	else
		classes = newcc;
}

void
sd(int rdclass, char *classname, char *dirname, char filetype) {
	char buf[sizeof "0123456789_65535.h"];
	char fmt[sizeof "%10[-0-9a-z]_%d.h"];
	int type;
	char typename[11];
	isc_dir_t dir;

	if (!start_directory(dirname, &dir))
		return;

	sprintf(fmt,"%s%c", "%10[-0-9a-z]_%d.", filetype);
	while (next_file(&dir)) {
		if (sscanf(dir.filename, fmt, typename, &type) != 2)
			continue;
		if ((type > 65535) || (type < 0))
			continue;

		sprintf(buf, "%s_%d.%c", typename, type, filetype);
		if (strcmp(buf, dir.filename) != 0)
			continue;
		add(rdclass, classname, type, typename, dirname);
	}

	end_directory(&dir);
}

static unsigned int
HASH(char *string)
{
	unsigned int n;
	unsigned char a, b;

	n = strlen(string);
	if (n == 0) {
		fprintf(stderr, "n == 0?\n");
		exit(1);
	}
	a = tolower((unsigned char)string[0]);
	b = tolower((unsigned char)string[n - 1]);

	return ((a + n) * b) % 256;
}

int
main(int argc, char **argv) {
	char buf[256];			/* XXX Should be max path length */
	char srcdir[256];		/* XXX Should be max path length */
	int rdclass;
	char classname[11];
	struct tt *tt;
	struct cc *cc;
	struct ttnam *ttn, *ttn2;
	unsigned int hash;
	struct tm *tm;
	time_t now;
	char year[11];
	int lasttype;
	int code = 1;
	int class_enum = 0;
	int type_enum = 0;
	int structs = 0;
	int c, i, j;
	char buf1[11];
	char filetype = 'c';
	FILE *fd;
	char *prefix = NULL;
	char *suffix = NULL;
	isc_dir_t dir;

	for (i = 0 ; i <= 255 ; i++)
		memset(&typenames[i], 0, sizeof(typenames[i]));

	strcpy(srcdir, "");
	while ((c = isc_commandline_parse(argc, argv, "cits:P:S:")) != -1)
		switch (c) {
		case 'c':
			code = 0;
			type_enum = 0;
			class_enum = 1;
			filetype = 'c';
			structs = 0;
			break;
		case 't':
			code = 0;
			class_enum = 0;
			type_enum = 1;
			filetype = 'c';
			structs = 0;
			break;
		case 'i':
			code = 0;
			class_enum = 0;
			type_enum = 0;
			structs = 1;
			filetype = 'h';
			break;
		case 's':
			sprintf(srcdir, "%s/", isc_commandline_argument);
			break;
		case 'P':
			prefix = isc_commandline_argument;
			break;
		case 'S':
			suffix = isc_commandline_argument;
			break;
		case '?':
			exit(1);
		}

	sprintf(buf, "%srdata", srcdir);

	if (!start_directory(buf, &dir))
		exit(1);

	while (next_file(&dir)) {
		if (sscanf(dir.filename, "%10[0-9a-z]_%d",
			   classname, &rdclass) != 2)
			continue;
		if ((rdclass > 65535) || (rdclass < 0))
			continue;

		sprintf(buf, "%srdata/%s_%d", srcdir, classname, rdclass);
		if (strcmp(buf + 6 + strlen(srcdir), dir.filename) != 0)
			continue;
		sd(rdclass, classname, buf, filetype);
	}
	end_directory(&dir);
	sprintf(buf, "%srdata/generic", srcdir);
	sd(0, "", buf, filetype);

	if (time(&now) != -1) {
		if ((tm = localtime(&now)) != NULL && tm->tm_year > 98)
			sprintf(year, "-%d", tm->tm_year + 1900);
		else
			year[0] = 0;
	} else
		year[0] = 0;

	fprintf(stdout, copyright, year);

	if (code) {
		fputs("\n\n", stdout);
		for (tt = types; tt != NULL ; tt = tt->next)
			fprintf(stdout, "#include \"%s/%s_%d.c\"\n",
				tt->dirname, tt->typename, tt->type);
		fputs("\n\n", stdout);

		doswitch("FROMTEXTSWITCH", "fromtext", FROMTEXTARGS,
			 FROMTEXTTYPE, FROMTEXTCLASS, FROMTEXTDEF);
		doswitch("TOTEXTSWITCH", "totext", TOTEXTARGS,
			 TOTEXTTYPE, TOTEXTCLASS, TOTEXTDEF);
		doswitch("FROMWIRESWITCH", "fromwire", FROMWIREARGS,
			 FROMWIRETYPE, FROMWIRECLASS, FROMWIREDEF);
		doswitch("TOWIRESWITCH", "towire", TOWIREARGS,
			 TOWIRETYPE, TOWIRECLASS, TOWIREDEF);
		doswitch("COMPARESWITCH", "compare", COMPAREARGS,
			  COMPARETYPE, COMPARECLASS, COMPAREDEF);
		doswitch("FROMSTRUCTSWITCH", "fromstruct", FROMSTRUCTARGS,
			  FROMSTRUCTTYPE, FROMSTRUCTCLASS, FROMSTRUCTDEF);
		doswitch("TOSTRUCTSWITCH", "tostruct", TOSTRUCTARGS,
			  TOSTRUCTTYPE, TOSTRUCTCLASS, TOSTRUCTDEF);
		doswitch("FREESTRUCTSWITCH", "freestruct", FREESTRUCTARGS,
			  FREESTRUCTTYPE, FREESTRUCTCLASS, FREESTRUCTDEF);
		doswitch("ADDITIONALDATASWITCH", "additionaldata",
			 ADDITIONALDATAARGS, ADDITIONALDATATYPE,
			 ADDITIONALDATACLASS, ADDITIONALDATADEF);
		doswitch("DIGESTSWITCH", "digest",
			 DIGESTARGS, DIGESTTYPE,
			 DIGESTCLASS, DIGESTDEF);

		/*
		 * From here down, we are processing the rdata names and
		 * attributes.
		 */

#define PRINT_COMMA(x) (x == 255 ? "" : ",")

#define METANOTQUESTION  "DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_NOTQUESTION"
#define METAQUESTIONONLY "DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY"
#define RESERVED "DNS_RDATATYPEATTR_RESERVED"

		/*
		 * Add in reserved/special types.  This will let us
		 * sort them without special cases.
		 */
		insert_into_typenames(0, "reserved0", RESERVED);
		insert_into_typenames(31, "eid", RESERVED);
		insert_into_typenames(32, "nimloc", RESERVED);
		insert_into_typenames(34, "atma", RESERVED);
		insert_into_typenames(100, "uinfo", RESERVED);
		insert_into_typenames(101, "uid", RESERVED);
		insert_into_typenames(102, "gid", RESERVED);
		insert_into_typenames(251, "ixfr", METAQUESTIONONLY);
		insert_into_typenames(252, "axfr", METAQUESTIONONLY);
		insert_into_typenames(253, "mailb", METAQUESTIONONLY);
		insert_into_typenames(254, "maila", METAQUESTIONONLY);
		insert_into_typenames(255, "any", METAQUESTIONONLY);

		printf("\ntypedef struct {\n");
		printf("\tchar *name;\n");
		printf("\tunsigned int flags;\n");
		printf("} typeattr_t;\n");
		printf("static typeattr_t typeattr[] = {\n");
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];
			if (ttn->typename[0] == 0) {
				printf("\t{ \"RRTYPE%d\", "
				       "DNS_RDATATYPEATTR_UNKNOWN"
				       "}%s\n", i, PRINT_COMMA(i));
			} else {
				printf("\t{ \"%s\", %s }%s\n",
				       upper(ttn->typename),
				       upper(ttn->attr),
				       PRINT_COMMA(i));
			}
		}
		printf("};\n");

		/*
		 * Run through the list of types and pre-mark the unused
		 * ones as "sorted" so we simply ignore them below.
		 */
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];
			if (ttn->typename[0] == 0)
				ttn->sorted = 1;
		}

		/*
		 * Spit out a quick and dirty hash function.  Here,
		 * we walk through the list of type names, and calculate
		 * a hash.  This isn't perfect, but it will generate "pretty
		 * good" estimates.  Lowercase the characters before
		 * computing in all cases.
		 *
		 * Here, walk the list from top to bottom, calculating
		 * the hash (mod 256) for each name.
		 */
		printf("#define RDATATYPE_COMPARE(_s, _d, _tn, _tp) \\\n");
		printf("\tdo { \\\n");
		printf("\t\tif (strcasecmp(_s,(_tn)) == 0) { \\\n");
		printf("\t\t\tif ((typeattr[_d].flags & DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
		printf("\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n");
		printf("\t\t\t*(_tp) = _d; \\\n");
		printf("\t\t\treturn (ISC_R_SUCCESS); \\\n");
		printf("\t\t} \\\n");
		printf("\t} while (0)\n\n");

		printf("#define RDATATYPE_FROMTEXT_SW(_hash,_typename,_typep) \\\n");
		printf("\tswitch (_hash) { \\\n");
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];

			/*
			 * Skip entries we already processed.
			 */
			if (ttn->sorted != 0)
				continue;

			hash = HASH(ttn->typename);
			printf("\t\tcase %u: \\\n", hash);

			/*
			 * Find all other entries that happen to match
			 * this hash.
			 */
			for (j = 0 ; j <= 255 ; j++) {
				ttn2 = &typenames[j];
				if (ttn2->sorted != 0)
					continue;
				if (hash == HASH(ttn2->typename)) {
					printf("\t\t\tRDATATYPE_COMPARE(\"%s\", %u, _typename, _typep); \\\n",
					       ttn2->typename, j);
					ttn2->sorted = 1;
				}
			}
			printf("\t\t\tbreak; \\\n");
		}
		printf("\t}\n");


		/*
		 * Dump the class names.
		 */

		fputs("\n", stdout);
		fprintf(stdout, "\n#define CLASSNAMES%s\n",
			classes != NULL ? " \\" : "");

		for (cc = classes; cc != NULL; cc = cc->next)
			fprintf(stdout, "\t{ %d, \"%s\", 0 },%s\n",
				cc->rdclass, upper(cc->classname),
				cc->next != NULL ? " \\" : "");

		fputs("\n", stdout);
	} else if (type_enum) {
		fprintf(stdout, "#ifndef TYPEENUM\n");
		fprintf(stdout, "#define TYPEENUM%s\n",
			types != NULL ? " \\" : "");

		lasttype = 0;
		for (tt = types; tt != NULL ; tt = tt->next)
			if (tt->type != lasttype)
				fprintf(stdout, "\t dns_rdatatype_%s = %d,%s\n",
					funname(tt->typename, buf1),
					lasttype = tt->type,
					tt->next != NULL ? " \\" : "");
		fprintf(stdout, "#endif /* TYPEENUM */\n");
	} else if (class_enum) {
		fprintf(stdout, "#ifndef CLASSENUM\n");
		fprintf(stdout, "#define CLASSENUM%s\n",
			classes != NULL ? " \\" : "");

		printf("\t dns_rdataclass_reserved0 = 0, \\\n");
		for (cc = classes; cc != NULL; cc = cc->next) {
			if (cc->rdclass == 4)
				printf("\t dns_rdataclass_chaos = 3, \\\n");
			fprintf(stdout, "\t dns_rdataclass_%s = %d,%s\n",
				funname(cc->classname, buf1),
				cc->rdclass,
				cc->next != NULL ? " \\" : "");
		}
		fprintf(stdout, "#endif /* CLASSENUM */\n");
	} else if (structs) {
		if (prefix != NULL) {
			if ((fd = fopen(prefix,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
		for (tt = types; tt != NULL ; tt = tt->next) {
			sprintf(buf, "%s/%s_%d.h",
				tt->dirname, tt->typename, tt->type);
			if ((fd = fopen(buf,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
		if (suffix != NULL) {
			if ((fd = fopen(suffix,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
	}

	if (ferror(stdout) != 0)
		exit(1);

	return (0);
}
<commit_msg>Be far, far noisier about 'generated file; do not edit' to keep the important message from disappearing between copyright notices (say, in rdatastruct.h)<commit_after>/*
 * Copyright (C) 1998, 1999, 2000  Internet Software Consortium.
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/* $Id: gen.c,v 1.44 2000/05/04 22:49:47 explorer Exp $ */

#include <config.h>

#include <sys/types.h>

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifdef WIN32
#include "gen-win32.h"
#else
#include "gen-unix.h"
#endif

#define FROMTEXTDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, isc_lex_t *lexer, dns_name_t *origin, isc_boolean_t downcase, isc_buffer_t *target"
#define FROMTEXTARGS "rdclass, type, lexer, origin, downcase, target"
#define FROMTEXTCLASS "rdclass"
#define FROMTEXTTYPE "type"
#define FROMTEXTDEF "use_default = ISC_TRUE"

#define TOTEXTDECL "dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, isc_buffer_t *target"
#define TOTEXTARGS "rdata, tctx, target"
#define TOTEXTCLASS "rdata->rdclass"
#define TOTEXTTYPE "rdata->type"
#define TOTEXTDEF "use_default = ISC_TRUE"

#define FROMWIREDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, isc_buffer_t *source, dns_decompress_t *dctx, isc_boolean_t downcase, isc_buffer_t *target"
#define FROMWIREARGS "rdclass, type, source, dctx, downcase, target"
#define FROMWIRECLASS "rdclass"
#define FROMWIRETYPE "type"
#define FROMWIREDEF "use_default = ISC_TRUE"

#define TOWIREDECL "dns_rdata_t *rdata, dns_compress_t *cctx, isc_buffer_t *target"
#define TOWIREARGS "rdata, cctx, target"
#define TOWIRECLASS "rdata->rdclass"
#define TOWIRETYPE "rdata->type"
#define TOWIREDEF "use_default = ISC_TRUE"

#define FROMSTRUCTDECL "dns_rdataclass_t rdclass, dns_rdatatype_t type, void *source, isc_buffer_t *target"
#define FROMSTRUCTARGS "rdclass, type, source, target"
#define FROMSTRUCTCLASS "rdclass"
#define FROMSTRUCTTYPE "type"
#define FROMSTRUCTDEF "use_default = ISC_TRUE"

#define TOSTRUCTDECL "dns_rdata_t *rdata, void *target, isc_mem_t *mctx"
#define TOSTRUCTARGS "rdata, target, mctx"
#define TOSTRUCTCLASS "rdata->rdclass"
#define TOSTRUCTTYPE "rdata->type"
#define TOSTRUCTDEF "use_default = ISC_TRUE"

#define FREESTRUCTDECL "void *source"
#define FREESTRUCTARGS "source"
#define FREESTRUCTCLASS "common->rdclass"
#define FREESTRUCTTYPE "common->rdtype"
#define FREESTRUCTDEF NULL

#define COMPAREDECL "dns_rdata_t *rdata1, dns_rdata_t *rdata2"
#define COMPAREARGS "rdata1, rdata2"
#define COMPARECLASS "rdata1->rdclass"
#define COMPARETYPE "rdata1->type"
#define COMPAREDEF "use_default = ISC_TRUE"

#define ADDITIONALDATADECL \
	"dns_rdata_t *rdata, dns_additionaldatafunc_t add, void *arg"
#define ADDITIONALDATAARGS "rdata, add, arg"
#define ADDITIONALDATACLASS "rdata->rdclass"
#define ADDITIONALDATATYPE "rdata->type"
#define ADDITIONALDATADEF "use_default = ISC_TRUE"

#define DIGESTDECL \
	"dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg"
#define DIGESTARGS "rdata, digest, arg"
#define DIGESTCLASS "rdata->rdclass"
#define DIGESTTYPE "rdata->type"
#define DIGESTDEF "use_default = ISC_TRUE"

char copyright[] =
"/*\n"
" * Copyright (C) 1998%s Internet Software Consortium.\n"
" *\n"
" * Permission to use, copy, modify, and distribute this software for any\n"
" * purpose with or without fee is hereby granted, provided that the above\n"
" * copyright notice and this permission notice appear in all copies.\n"
" *\n"
" * THE SOFTWARE IS PROVIDED \"AS IS\" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS\n"
" * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES\n"
" * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE\n"
" * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\n"
" * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\n"
" * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\n"
" * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\n"
" * SOFTWARE.\n"
" */\n"
"\n"
"/***************\n"
" ***************\n"
" ***************   THIS FILE IS AUTOMATICALLY GENERATED BY gen.c.\n"
" ***************   DO NOT EDIT!\n"
" ***************\n"
" ***************/\n"
"\n";

struct cc {
	struct cc *next;
	int rdclass;
	char classname[11];
} *classes;

struct tt {
	struct tt *next;
	int rdclass;
	int type;
	char classname[11];
	char typename[11];
	char dirname[256];		/* XXX Should be max path length */
} *types;

struct ttnam {
	char typename[11];
	char macroname[11];
	char attr[256];
	unsigned int sorted;
} typenames[256];

char *	upper(char *);
char *	funname(char *, char *);
void	doswitch(char *, char *, char *, char *, char *, char *);
void	dodecl(char *, char *, char *);
void	add(int, char *, int, char *, char *);
void	sd(int, char *, char *, char);
void	insert_into_typenames(int, char *, char *);

/*
 * If you use more than 10 of these in, say, a printf(), you'll have problems.
 */
char *
upper(char *s) {
	static int buf_to_use = 0;
	static char buf[10][256];
	char *b;
	int c;

	buf_to_use++;
	if (buf_to_use > 9)
		buf_to_use = 0;

	b = buf[buf_to_use];
	memset(b, 0, 256);

	while ((c = (*s++) & 0xff))
		*b++ = islower(c) ? toupper(c) : c;
	*b = '\0';
	return (buf[buf_to_use]);
}

char *
funname(char *s, char *buf) {
	char *b = buf;
	char c;

	while ((c = *s++)) {
		*b++ = (c == '-') ? '_' : c;
	}
	*b = '\0';
	return (buf);
}

void
doswitch(char *name, char *function, char *args,
	 char *tsw, char *csw, char *res)
{
	struct tt *tt;
	int first = 1;
	int lasttype = 0;
	int subswitch = 0;
	char buf1[11], buf2[11];
	char *result = " result =";

	if (res == NULL)
		result = "";

	for (tt = types; tt != NULL ; tt = tt->next) {
		if (first) {
			fprintf(stdout, "\n#define %s \\\n", name);
			fprintf(stdout, "\tswitch (%s) { \\\n" /*}*/, tsw);
			first = 0;
		}
		if (tt->type != lasttype && subswitch) {
			if (res == NULL)
				fprintf(stdout, "\t\tdefault: break; \\\n");
			else
				fprintf(stdout,
					"\t\tdefault: %s; break; \\\n", res);
			fputs(/*{*/ "\t\t} \\\n", stdout);
			fputs("\t\tbreak; \\\n", stdout);
			subswitch = 0;
		}
		if (tt->rdclass && tt->type != lasttype) {
			fprintf(stdout, "\tcase %d: switch (%s) { \\\n" /*}*/,
				tt->type, csw);
			subswitch = 1;
		}
		if (tt->rdclass == 0)
			fprintf(stdout,
				"\tcase %d:%s %s_%s(%s); break;",
				tt->type, result, function,
				funname(tt->typename, buf1), args);
		else
			fprintf(stdout,
			        "\t\tcase %d:%s %s_%s_%s(%s); break;",
				tt->rdclass, result, function, 
				funname(tt->classname, buf1),
				funname(tt->typename, buf2), args);
		fputs(" \\\n", stdout);
		lasttype = tt->type;
	}
	if (subswitch) {
		if (res == NULL)
			fprintf(stdout, "\t\tdefault: break; \\\n");
		else 
			fprintf(stdout, "\t\tdefault: %s; break; \\\n", res);
		fputs(/*{*/ "\t\t} \\\n", stdout);
		fputs("\t\tbreak; \\\n", stdout);
	}
	if (first) {
		if (res == NULL)
			fprintf(stdout, "\n#define %s\n", name);
		else
			fprintf(stdout, "\n#define %s %s;\n", name, res);
	} else {
		if (res == NULL)
			fprintf(stdout, "\tdefault: break; \\\n");
		else
			fprintf(stdout, "\tdefault: %s; break; \\\n", res);
		fputs(/*{*/ "\t}\n", stdout);
	}
}

void
dodecl(char *type, char *function, char *args) {
	struct tt *tt;
	char buf1[11], buf2[11];

	fputs("\n", stdout);
	for (tt = types; tt ; tt = tt->next)
		if (tt->rdclass)
			fprintf(stdout,
				"static inline %s %s_%s_%s(%s);\n",
				type, function,
				funname(tt->classname, buf1),
				funname(tt->typename, buf2), args);
		else
			fprintf(stdout,
				"static inline %s %s_%s(%s);\n",
				type, function, 
				funname(tt->typename, buf1), args);
}

void
insert_into_typenames(int type, char *typename, char *attr)
{
	struct ttnam *ttn;
	int c;
	char tmp[256];

	ttn = &typenames[type];
	if (ttn->typename[0] == 0) {
		if (strlen(typename) > sizeof(ttn->typename) - 1) {
			fprintf(stderr, "Error:  type name %s is too long\n",
				typename);
			exit(1);
		}
		strcpy(ttn->typename, typename);
	} else if (strcmp(typename, ttn->typename) != 0) {
		fprintf(stderr, "Error:  type %d has two names: %s, %s\n",
			type, ttn->typename, typename);
		exit(1);
	}

	strcpy(ttn->macroname, ttn->typename);
	c = strlen(ttn->macroname);
	while (c > 0) {
		if (ttn->macroname[c - 1] == '-')
			ttn->macroname[c - 1] = '_';
		c--;
	}

	if (attr == NULL) {
		sprintf(tmp, "RRTYPE_%s_ATTRIBUTES", upper(ttn->macroname));
		attr = tmp;
	}

	if (ttn->attr[0] != 0 && strcmp(attr, ttn->attr) != 0) {
		fprintf(stderr, "Error:  type %d has different attributes: "
			"%s, %s\n", type, ttn->attr, attr);
		exit(1);
	}

	if (strlen(attr) > sizeof(ttn->attr) - 1) {
		fprintf(stderr, "Error:  attr (%s) [name %s] is too long\n",
			attr, typename);
		exit(1);
	}
	strcpy(ttn->attr, attr);
	ttn->sorted = 0;
}

void
add(int rdclass, char *classname, int type, char *typename, char *dirname) {
	struct tt *newtt = (struct tt *)malloc(sizeof *newtt);
	struct tt *tt, *oldtt;
	struct cc *newcc;
	struct cc *cc, *oldcc;

	insert_into_typenames(type, typename, NULL);

	if (newtt == NULL) {
		fprintf(stderr, "malloc() failed\n");
		exit(1);
	}

	newtt->next = NULL;
	newtt->rdclass = rdclass;
	newtt->type = type;
	strcpy(newtt->classname, classname);
	strcpy(newtt->typename, typename);
	strcpy(newtt->dirname, dirname);

	tt = types;
	oldtt = NULL;

	while ((tt != NULL) && (tt->type < type)) {
		oldtt = tt;
		tt = tt->next;
	}

	while ((tt != NULL) && (tt->type == type) && (tt->rdclass < rdclass)) {
		if (strcmp(tt->typename, typename) != 0)
			exit(1);
		oldtt = tt;
		tt = tt->next;
	}

	if ((tt != NULL) && (tt->type == type) && (tt->rdclass == rdclass))
		exit(1);

	newtt->next = tt;
	if (oldtt != NULL)
		oldtt->next = newtt;
	else
		types = newtt;

	/* do a class switch for this type */
	 
	if (rdclass == 0)
		return;

	newcc = (struct cc *)malloc(sizeof *newcc);
	newcc->rdclass = rdclass;
	strcpy(newcc->classname, classname);
	cc = classes;
	oldcc = NULL;
	
	while ((cc != NULL) && (cc->rdclass < rdclass)) {
		oldcc = cc;
		cc = cc->next;
	}

	if ((cc != NULL) && cc->rdclass == rdclass) {
		free((char *)newcc);
		return;
	}

	newcc->next = cc;
	if (oldcc != NULL)
		oldcc->next = newcc;
	else
		classes = newcc;
}

void
sd(int rdclass, char *classname, char *dirname, char filetype) {
	char buf[sizeof "0123456789_65535.h"];
	char fmt[sizeof "%10[-0-9a-z]_%d.h"];
	int type;
	char typename[11];
	isc_dir_t dir;

	if (!start_directory(dirname, &dir))
		return;

	sprintf(fmt,"%s%c", "%10[-0-9a-z]_%d.", filetype);
	while (next_file(&dir)) {
		if (sscanf(dir.filename, fmt, typename, &type) != 2)
			continue;
		if ((type > 65535) || (type < 0))
			continue;

		sprintf(buf, "%s_%d.%c", typename, type, filetype);
		if (strcmp(buf, dir.filename) != 0)
			continue;
		add(rdclass, classname, type, typename, dirname);
	}

	end_directory(&dir);
}

static unsigned int
HASH(char *string)
{
	unsigned int n;
	unsigned char a, b;

	n = strlen(string);
	if (n == 0) {
		fprintf(stderr, "n == 0?\n");
		exit(1);
	}
	a = tolower((unsigned char)string[0]);
	b = tolower((unsigned char)string[n - 1]);

	return ((a + n) * b) % 256;
}

int
main(int argc, char **argv) {
	char buf[256];			/* XXX Should be max path length */
	char srcdir[256];		/* XXX Should be max path length */
	int rdclass;
	char classname[11];
	struct tt *tt;
	struct cc *cc;
	struct ttnam *ttn, *ttn2;
	unsigned int hash;
	struct tm *tm;
	time_t now;
	char year[11];
	int lasttype;
	int code = 1;
	int class_enum = 0;
	int type_enum = 0;
	int structs = 0;
	int c, i, j;
	char buf1[11];
	char filetype = 'c';
	FILE *fd;
	char *prefix = NULL;
	char *suffix = NULL;
	isc_dir_t dir;

	for (i = 0 ; i <= 255 ; i++)
		memset(&typenames[i], 0, sizeof(typenames[i]));

	strcpy(srcdir, "");
	while ((c = isc_commandline_parse(argc, argv, "cits:P:S:")) != -1)
		switch (c) {
		case 'c':
			code = 0;
			type_enum = 0;
			class_enum = 1;
			filetype = 'c';
			structs = 0;
			break;
		case 't':
			code = 0;
			class_enum = 0;
			type_enum = 1;
			filetype = 'c';
			structs = 0;
			break;
		case 'i':
			code = 0;
			class_enum = 0;
			type_enum = 0;
			structs = 1;
			filetype = 'h';
			break;
		case 's':
			sprintf(srcdir, "%s/", isc_commandline_argument);
			break;
		case 'P':
			prefix = isc_commandline_argument;
			break;
		case 'S':
			suffix = isc_commandline_argument;
			break;
		case '?':
			exit(1);
		}

	sprintf(buf, "%srdata", srcdir);

	if (!start_directory(buf, &dir))
		exit(1);

	while (next_file(&dir)) {
		if (sscanf(dir.filename, "%10[0-9a-z]_%d",
			   classname, &rdclass) != 2)
			continue;
		if ((rdclass > 65535) || (rdclass < 0))
			continue;

		sprintf(buf, "%srdata/%s_%d", srcdir, classname, rdclass);
		if (strcmp(buf + 6 + strlen(srcdir), dir.filename) != 0)
			continue;
		sd(rdclass, classname, buf, filetype);
	}
	end_directory(&dir);
	sprintf(buf, "%srdata/generic", srcdir);
	sd(0, "", buf, filetype);

	if (time(&now) != -1) {
		if ((tm = localtime(&now)) != NULL && tm->tm_year > 98)
			sprintf(year, "-%d", tm->tm_year + 1900);
		else
			year[0] = 0;
	} else
		year[0] = 0;

	fprintf(stdout, copyright, year);

	if (code) {
		fputs("\n\n", stdout);
		for (tt = types; tt != NULL ; tt = tt->next)
			fprintf(stdout, "#include \"%s/%s_%d.c\"\n",
				tt->dirname, tt->typename, tt->type);
		fputs("\n\n", stdout);

		doswitch("FROMTEXTSWITCH", "fromtext", FROMTEXTARGS,
			 FROMTEXTTYPE, FROMTEXTCLASS, FROMTEXTDEF);
		doswitch("TOTEXTSWITCH", "totext", TOTEXTARGS,
			 TOTEXTTYPE, TOTEXTCLASS, TOTEXTDEF);
		doswitch("FROMWIRESWITCH", "fromwire", FROMWIREARGS,
			 FROMWIRETYPE, FROMWIRECLASS, FROMWIREDEF);
		doswitch("TOWIRESWITCH", "towire", TOWIREARGS,
			 TOWIRETYPE, TOWIRECLASS, TOWIREDEF);
		doswitch("COMPARESWITCH", "compare", COMPAREARGS,
			  COMPARETYPE, COMPARECLASS, COMPAREDEF);
		doswitch("FROMSTRUCTSWITCH", "fromstruct", FROMSTRUCTARGS,
			  FROMSTRUCTTYPE, FROMSTRUCTCLASS, FROMSTRUCTDEF);
		doswitch("TOSTRUCTSWITCH", "tostruct", TOSTRUCTARGS,
			  TOSTRUCTTYPE, TOSTRUCTCLASS, TOSTRUCTDEF);
		doswitch("FREESTRUCTSWITCH", "freestruct", FREESTRUCTARGS,
			  FREESTRUCTTYPE, FREESTRUCTCLASS, FREESTRUCTDEF);
		doswitch("ADDITIONALDATASWITCH", "additionaldata",
			 ADDITIONALDATAARGS, ADDITIONALDATATYPE,
			 ADDITIONALDATACLASS, ADDITIONALDATADEF);
		doswitch("DIGESTSWITCH", "digest",
			 DIGESTARGS, DIGESTTYPE,
			 DIGESTCLASS, DIGESTDEF);

		/*
		 * From here down, we are processing the rdata names and
		 * attributes.
		 */

#define PRINT_COMMA(x) (x == 255 ? "" : ",")

#define METANOTQUESTION  "DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_NOTQUESTION"
#define METAQUESTIONONLY "DNS_RDATATYPEATTR_META | DNS_RDATATYPEATTR_QUESTIONONLY"
#define RESERVED "DNS_RDATATYPEATTR_RESERVED"

		/*
		 * Add in reserved/special types.  This will let us
		 * sort them without special cases.
		 */
		insert_into_typenames(0, "reserved0", RESERVED);
		insert_into_typenames(31, "eid", RESERVED);
		insert_into_typenames(32, "nimloc", RESERVED);
		insert_into_typenames(34, "atma", RESERVED);
		insert_into_typenames(100, "uinfo", RESERVED);
		insert_into_typenames(101, "uid", RESERVED);
		insert_into_typenames(102, "gid", RESERVED);
		insert_into_typenames(251, "ixfr", METAQUESTIONONLY);
		insert_into_typenames(252, "axfr", METAQUESTIONONLY);
		insert_into_typenames(253, "mailb", METAQUESTIONONLY);
		insert_into_typenames(254, "maila", METAQUESTIONONLY);
		insert_into_typenames(255, "any", METAQUESTIONONLY);

		printf("\ntypedef struct {\n");
		printf("\tchar *name;\n");
		printf("\tunsigned int flags;\n");
		printf("} typeattr_t;\n");
		printf("static typeattr_t typeattr[] = {\n");
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];
			if (ttn->typename[0] == 0) {
				printf("\t{ \"RRTYPE%d\", "
				       "DNS_RDATATYPEATTR_UNKNOWN"
				       "}%s\n", i, PRINT_COMMA(i));
			} else {
				printf("\t{ \"%s\", %s }%s\n",
				       upper(ttn->typename),
				       upper(ttn->attr),
				       PRINT_COMMA(i));
			}
		}
		printf("};\n");

		/*
		 * Run through the list of types and pre-mark the unused
		 * ones as "sorted" so we simply ignore them below.
		 */
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];
			if (ttn->typename[0] == 0)
				ttn->sorted = 1;
		}

		/*
		 * Spit out a quick and dirty hash function.  Here,
		 * we walk through the list of type names, and calculate
		 * a hash.  This isn't perfect, but it will generate "pretty
		 * good" estimates.  Lowercase the characters before
		 * computing in all cases.
		 *
		 * Here, walk the list from top to bottom, calculating
		 * the hash (mod 256) for each name.
		 */
		printf("#define RDATATYPE_COMPARE(_s, _d, _tn, _tp) \\\n");
		printf("\tdo { \\\n");
		printf("\t\tif (strcasecmp(_s,(_tn)) == 0) { \\\n");
		printf("\t\t\tif ((typeattr[_d].flags & DNS_RDATATYPEATTR_RESERVED) != 0) \\\n");
		printf("\t\t\t\treturn (ISC_R_NOTIMPLEMENTED); \\\n");
		printf("\t\t\t*(_tp) = _d; \\\n");
		printf("\t\t\treturn (ISC_R_SUCCESS); \\\n");
		printf("\t\t} \\\n");
		printf("\t} while (0)\n\n");

		printf("#define RDATATYPE_FROMTEXT_SW(_hash,_typename,_typep) \\\n");
		printf("\tswitch (_hash) { \\\n");
		for (i = 0 ; i <= 255 ; i++) {
			ttn = &typenames[i];

			/*
			 * Skip entries we already processed.
			 */
			if (ttn->sorted != 0)
				continue;

			hash = HASH(ttn->typename);
			printf("\t\tcase %u: \\\n", hash);

			/*
			 * Find all other entries that happen to match
			 * this hash.
			 */
			for (j = 0 ; j <= 255 ; j++) {
				ttn2 = &typenames[j];
				if (ttn2->sorted != 0)
					continue;
				if (hash == HASH(ttn2->typename)) {
					printf("\t\t\tRDATATYPE_COMPARE(\"%s\", %u, _typename, _typep); \\\n",
					       ttn2->typename, j);
					ttn2->sorted = 1;
				}
			}
			printf("\t\t\tbreak; \\\n");
		}
		printf("\t}\n");


		/*
		 * Dump the class names.
		 */

		fputs("\n", stdout);
		fprintf(stdout, "\n#define CLASSNAMES%s\n",
			classes != NULL ? " \\" : "");

		for (cc = classes; cc != NULL; cc = cc->next)
			fprintf(stdout, "\t{ %d, \"%s\", 0 },%s\n",
				cc->rdclass, upper(cc->classname),
				cc->next != NULL ? " \\" : "");

		fputs("\n", stdout);
	} else if (type_enum) {
		fprintf(stdout, "#ifndef TYPEENUM\n");
		fprintf(stdout, "#define TYPEENUM%s\n",
			types != NULL ? " \\" : "");

		lasttype = 0;
		for (tt = types; tt != NULL ; tt = tt->next)
			if (tt->type != lasttype)
				fprintf(stdout, "\t dns_rdatatype_%s = %d,%s\n",
					funname(tt->typename, buf1),
					lasttype = tt->type,
					tt->next != NULL ? " \\" : "");
		fprintf(stdout, "#endif /* TYPEENUM */\n");
	} else if (class_enum) {
		fprintf(stdout, "#ifndef CLASSENUM\n");
		fprintf(stdout, "#define CLASSENUM%s\n",
			classes != NULL ? " \\" : "");

		printf("\t dns_rdataclass_reserved0 = 0, \\\n");
		for (cc = classes; cc != NULL; cc = cc->next) {
			if (cc->rdclass == 4)
				printf("\t dns_rdataclass_chaos = 3, \\\n");
			fprintf(stdout, "\t dns_rdataclass_%s = %d,%s\n",
				funname(cc->classname, buf1),
				cc->rdclass,
				cc->next != NULL ? " \\" : "");
		}
		fprintf(stdout, "#endif /* CLASSENUM */\n");
	} else if (structs) {
		if (prefix != NULL) {
			if ((fd = fopen(prefix,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
		for (tt = types; tt != NULL ; tt = tt->next) {
			sprintf(buf, "%s/%s_%d.h",
				tt->dirname, tt->typename, tt->type);
			if ((fd = fopen(buf,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
		if (suffix != NULL) {
			if ((fd = fopen(suffix,"r")) != NULL) {
				while (fgets(buf, sizeof buf, fd) != NULL)
					fputs(buf, stdout);
				fclose(fd);
			}
		}
	}

	if (ferror(stdout) != 0)
		exit(1);

	return (0);
}

{'fraction_non_alphanumeric': 0.17588830612395656, 'fraction_numerical': 0.015414542857846396, 'mean_word_length': 3.63078677309008, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 245, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7409527', 'n_tokens_mistral': 17688, 'n_tokens_neox': 15849, 'n_words': 4101}