/*
 * nasd_rpcgen_output_usc.c
 *
 * Output various usc-related files from NASD rpc file spec
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#include <nasd/nasd_options.h>

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "nasd_rpcgen.h"

char *hold_comp = NULL;

void
output_net_convert_h_header(
  FILE  *f,
  char  *filename)
{
  static char tmp[MAXPATHLEN];
  char *s, *s0;
  int i, l;

  output_cpp_comment_header(f, filename);

  strcpy(tmp, filename);
  s0 = s = tmp;
  l = strlen(tmp);
  for(i=0;i<l;i++) {
    if (tmp[i] == '.') {
      tmp[i] = '_';
    }
    else if (tmp[i] == NASD_RPCGEN_PATHSEP) {
      s0 = s;
      s = &tmp[i+1];
    }
  }
  l = strlen(s);
  if (l == 0) {
    s = s0;
  }
  hold_comp = s;

  fprintf(f, "#ifndef _%s\n", hold_comp);
  fprintf(f, "#define _%s\n", hold_comp);
  fprintf(f, "\n");
}

void
output_net_convert_h_trailer(
   FILE  *f)
{
  fprintf(f, "\n");
  fprintf(f, "#endif /* !_%s */\n", hold_comp);
}

void
output_net_convert_h_type(
  FILE                *f,
  nasd_rpcgen_type_t  *type)
{
  nasd_rpcgen_type_t *t, *bt;
  char *s;

  if (type->out_flags & NASD_RPCGEN_OUT_FLAGS_MARSHALL)
    return;

  t = type;
  bt = NULL;
  while(t) {
    if (t->type_is != NASD_RPCGEN_TYPE_DERIVED)
      return;
    bt = t->derived_from;
    if (bt->type_is == NASD_RPCGEN_TYPE_STRUCT)
      break;
    t = bt;
  }
  NASD_ASSERT(bt != NULL);

  if (t != type)
    return;
  if (bt->nomarshall)
    return;

  str_append_prefix(t->name, "otw_", &s);
  fprintf(f, "typedef nasd_byte %s;\n", s);
  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_net_convert_h_import(
  FILE                  *f,
  nasd_rpcgen_import_t  *import)
{
}

void
output_net_convert_h_const(
  FILE                 *f,
  nasd_rpcgen_const_t  *cnst)
{
}

void
output_net_convert_h_struct(
  FILE                *f,
  nasd_rpcgen_type_t  *st)
{
}

void
output_net_convert_h_call(
  FILE                *f,
  nasd_rpcgen_call_t  *call)
{
}

void
output_net_convert_h_uuid(
  FILE               *f,
  nasd_rpcgen_val_t  *strval)
{
}

void
output_net_convert_h_version(
  FILE               *f,
  nasd_rpcgen_val_t  *strval)
{
}

void
output_net_convert_h_marshall(
  FILE                    *f,
  nasd_rpcgen_marshall_t  *marshall)
{
  nasd_rpcgen_type_t *type, *bt, *t;
  char *s;

  type = marshall->type;
  if (type->out_flags & NASD_RPCGEN_OUT_FLAGS_MARSHALL)
    return;

  bt = t = type;
  while(bt->type_is == NASD_RPCGEN_TYPE_DERIVED) {
    bt = bt->derived_from;
  }

  str_append_prefix(t->name, "otw_", &s);
  fprintf(f, "typedef nasd_byte %s;\n", s);
  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_net_convert_h(
  char  *filename)
{
  nasd_rpcgen_decl_t *decl;
  FILE *f;

  if (filename[0] == '.') {
    fprintf(oerr, "ERROR: invalid filename \"%s\"\n", filename);
    output_error();
    return;
  }

  f = fopen(filename, "w");
  if (f == NULL) {
    fprintf(oerr, "ERROR: cannot open %s for output\n", filename);
    output_error();
    return;
  }

  output_net_convert_h_header(f, filename);

  for(decl=global_decls.gnext;decl!=&global_decls;decl=decl->gnext) {
    if (global_spec.annotate) {
      fprintf(f, "/* %s:%d (internal %d) */\n", decl->define_file,
        decl->define_line, decl->decl_type);
    }
    switch(decl->decl_type) {
      case NASD_RPCGEN_DECL_TYPE:
        output_net_convert_h_type(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_IMPORT:
        output_net_convert_h_import(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CONST:
        output_net_convert_h_const(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_STRUCT:
        output_net_convert_h_struct(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CALL:
        output_net_convert_h_call(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_UUID:
        output_net_convert_h_uuid(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_DCE_ENDPOINT:
        /* we do NOTHING with this */
        break;
      case NASD_RPCGEN_DECL_VERSION:
        output_net_convert_h_version(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_MARSHALL:
        output_net_convert_h_marshall(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_BASEID:
        break;
      default:
        NASD_PANIC();
    }
  }

  output_net_convert_h_trailer(f);

  fclose(f);
  printf("Wrote %s as net_convert header\n", filename);
}

void
output_usc_header(
  FILE  *f,
  char  *filename)
{
  nasd_rpcgen_filename_t *fn;

  output_cpp_comment_header(f, filename);

  fn = global_spec.usc_import_list;
  if (fn) {
    fprintf(f, "#include \"%s\"\n", fn->filename);
    fprintf(f, "\n");
    fn = fn->next;
  }

  fprintf(f, "\n");
  fprintf(f, "%%%%\n");
  fprintf(f, "\n");
  for(;fn;fn=fn->next) {
    fprintf(f, "#include \"%s\"\n", fn->filename);
    fprintf(f, "\n");
  }
}

void
output_usc_trailer(
   FILE  *f)
{
  fprintf(f, "\n");
  fprintf(f, "%%%%\n");
  fprintf(f, "\n");
}

void
output_usc_type(
  FILE                *f,
  nasd_rpcgen_type_t  *type)
{
  nasd_rpcgen_type_t *t, *bt;
  char *s;

  if (type->out_flags & NASD_RPCGEN_OUT_FLAGS_MARSHALL)
    return;

  t = type;
  bt = NULL;
  while(t) {
    if (t->type_is != NASD_RPCGEN_TYPE_DERIVED)
      return;
    bt = t->derived_from;
    if (bt->type_is == NASD_RPCGEN_TYPE_STRUCT)
      break;
    t = bt;
  }
  NASD_ASSERT(bt != NULL);

  if (t != type)
    return;
  if (bt->nomarshall)
    return;

  str_append_prefix(t->name, "otw_", &s);
  fprintf(f, "void %s_to_net(%s *in, %s *out) { *out = *in; }\n",
    t->name, t->name, s);
  fprintf(f, "void %s_from_net(%s *in, %s *out) { *out = *in; }\n",
    t->name, s, t->name);
  fprintf(f, "\n");
  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_usc_import(
  FILE                  *f,
  nasd_rpcgen_import_t  *import)
{
}

void
output_usc_const(
  FILE                 *f,
  nasd_rpcgen_const_t  *cnst)
{
}

void
output_usc_struct(
  FILE                *f,
  nasd_rpcgen_type_t  *st)
{
}

void
output_usc_call(
  FILE                *f,
  nasd_rpcgen_call_t  *call)
{
}

void
output_usc_uuid(
  FILE               *f,
  nasd_rpcgen_val_t  *strval)
{
}

void
output_usc_version(
  FILE               *f,
  nasd_rpcgen_val_t  *strval)
{
}

void
output_usc_marshall(
  FILE                    *f,
  nasd_rpcgen_marshall_t  *marshall)
{
  nasd_rpcgen_type_t *type, *t, *bt;
  char *s;

  type = marshall->type;
  if (type->out_flags & NASD_RPCGEN_OUT_FLAGS_MARSHALL)
    return;

  bt = t = type;
  while(bt->type_is == NASD_RPCGEN_TYPE_DERIVED) {
    bt = bt->derived_from;
  }

  str_append_prefix(t->name, "otw_", &s);
  fprintf(f, "void %s_to_net(%s *in, %s *out) { *out = *in; }\n",
    t->name, t->name, s);
  fprintf(f, "void %s_from_net(%s *in, %s *out) { *out = *in; }\n",
    t->name, s, t->name);
  fprintf(f, "\n");
  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_usc(
  char  *filename)
{
  nasd_rpcgen_decl_t *decl;
  FILE *f;

  if (filename[0] == '.') {
    fprintf(oerr, "ERROR: invalid filename \"%s\"\n", filename);
    output_error();
    return;
  }

  f = fopen(filename, "w");
  if (f == NULL) {
    fprintf(oerr, "ERROR: cannot open %s for output\n", filename);
    output_error();
    return;
  }

  output_usc_header(f, filename);

  for(decl=global_decls.gnext;decl!=&global_decls;decl=decl->gnext) {
    if (global_spec.annotate) {
      fprintf(f, "/* %s:%d (internal %d) */\n", decl->define_file,
        decl->define_line, decl->decl_type);
    }
    switch(decl->decl_type) {
      case NASD_RPCGEN_DECL_TYPE:
        output_usc_type(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_IMPORT:
        output_usc_import(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CONST:
        output_usc_const(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_STRUCT:
        output_usc_struct(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CALL:
        output_usc_call(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_UUID:
        output_usc_uuid(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_DCE_ENDPOINT:
        /* we do NOTHING with this */
        break;
      case NASD_RPCGEN_DECL_VERSION:
        output_usc_version(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_MARSHALL:
        output_usc_marshall(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_BASEID:
        break;
      default:
        NASD_PANIC();
    }
  }

  output_usc_trailer(f);

  fclose(f);
  printf("Wrote %s as usc file\n", filename);
}

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
