/*
 * SMI-Compiler (c) J. Friedrich
 * Heavily based on smidump.
 */

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <time.h>

#include "smi.h"

void
print_prefixed(const char *prefix, const char *s)
{
    int i;

    printf("%s", prefix);
    if (s) 
      {
	for (i=0; i < strlen(s); i++) 
	  {
	    if (s[i] != '\n')
		printf("%c", s[i]);
	    else 
	      {
		printf("\n");
		printf("%s", prefix);
	      }
	  }
      }
    printf("\n");
}

char 
*upper_to_c(char *s)
{
    char *ss, *p;

    ss = malloc(strlen(s)+1);
    p = ss;

    while (*s)
      {
	if (*s == '-')
	  *p = '_';
	else
	  *p = toupper(*s);
	p++; s++;
      }
    *p = 0;
    return ss;
}

char 
*name_to_c(char *s)
{
    char *ss, *p;

    ss = malloc(strlen(s)+1);
    p = ss;

    while (*s)
      {
	if (*s == '-')
	  *p = '_';
	else
	  *p = *s;
	p++; s++;
      }
    *p = 0;
    return ss;
}

void 
print_objects(char *modulename)
{
    SmiNode	   *smiNode, *smiTable, *smiRow, *smiColumn;
    SmiType	   *smiType;
    SmiNamedNumber *smiNamedNumber;
    int i;

    /*
     * Global definitions.
     */

    printf("\n");
    printf("typedef struct _value_string {\n");
    printf("  guint32  value;\n");
    printf("  gchar   *strptr;\n");
    printf("} value_string;\n");
    printf("\n");

    /* 
     * Create Macro definitions and a conversion table for ENUMs.
     */

    for(smiNode = smiGetFirstNode(modulename, SMI_NODEKIND_ANY);
	smiNode; smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY))
      {

	if ((smiNode->basetype == SMI_BASETYPE_ENUM) &&
	    smiNode->typename &&
	    (smiType = smiGetType(smiNode->typemodule, smiNode->typename)))
	  {
	    printf("\n/*\n");
	    printf(" * Derived from type of MIB node %s.%s.\n",
		   modulename, smiNode->name);
	    printf(" *\n");
	    print_prefixed(" * ", smiNode->description);
	    printf(" */\n");
	    if (strcmp(smiNode->name, smiType->name))
	      printf("static const value_string %s_%s[] = {\n", 
		     name_to_c(smiNode->name), name_to_c(smiType->name));
	    else
	      printf("static const value_string %s[] = {\n", 
		     name_to_c(smiType->name));
	    for(smiNamedNumber = smiGetFirstNamedNumber(smiType->module,
							smiType->name);
		smiNamedNumber;
		smiNamedNumber = smiGetNextNamedNumber(smiNamedNumber))
	      {
		printf("  { %lu, \"%s\"},\n", 
			smiNamedNumber->value.value.unsigned32,
			smiNamedNumber->name);
	      }
	    printf("  { 0, NULL}};\n");
            printf("\n");
	  }
      }

    /* 
     * Create Macro definitions for objects
     */

    for(smiNode = smiGetFirstNode(modulename, SMI_NODEKIND_ANY);
        smiNode; smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY))
      {
	if (smiNode->oidlen)
	  {
	    printf("#define %s %lu", upper_to_c(smiNode->name), 
		   smiNode->oid[0]);
	    for (i=1; i< smiNode->oidlen; i++)
	      printf(",%lu", smiNode->oid[i]);
	    printf("\n");
          }
      }
}

void smi_compile(char *modulename)
{
    SmiModule	 *smiModule;
    
    smiModule = smiGetModule(modulename);
    if (!smiModule)
      {
	fprintf(stderr, "smilint: cannot locate module `%s'\n", modulename);
	exit(1);
      } 
    else 
      {
	printf("/*\n");
	printf(" * This file has been generated by smi-compile. Do not edit.\n");
	printf(" * It is based on the MIB module %s.\n", smiModule->name);
	printf(" */\n");

	print_objects(smiModule->name);
      }
}

int
main(int argc, char *argv[])
{
    char c;
    char *modulename;
    int opt;

    smiInit();
    opt = 1;

    while (opt < argc) 
      {
	modulename = smiLoadModule(argv[opt]);
	if (modulename) 
	  smi_compile(modulename);
	else 
	  {
	    fprintf(stderr, "smidump: cannot locate module `%s'\n",
		    argv[opt]);
	    exit(1);
	  }
	opt++;
      }
}
