/*
 * nasd_rpcgen_output_marshall.c
 *
 * Output marshall .c and .h files from .rpc specs
 *
 * 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 *marshall_hold_comp = NULL;

void output_marshall_funcs(
  FILE                *f,
  nasd_rpcgen_type_t  *t,
  char                *t_otw_name);

void
output_marshall_guts(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  char                *type_otw_name,
  int                  lvl,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall);

void
output_marshall_guts_struct(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  nasd_rpcgen_type_t  *struct_type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall);

void
output_marshall_guts_basic(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall);

void
output_marshall_guts_array(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  nasd_rpcgen_type_t  *array_type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall);

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

  output_cpp_comment_header(f, filename);

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

void
output_old_marshall_c_trailer(
   FILE  *f)
{
}

void
output_old_marshall_c_type(
  FILE                *f,
  nasd_rpcgen_type_t  *type)
{
  nasd_rpcgen_type_t *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    return;
  }

  fprintf(f, "void\n");
  fprintf(f, "%s_marshall(\n", t->name);
  fprintf(f, "  %s  *in,\n", t->name);
  fprintf(f, "  %s   out)\n", s);
  fprintf(f, "{\n");
  fprintf(f, "  %s_to_net(in, out);\n", t->name);
  fprintf(f, "}\n");
  fprintf(f, "\n");

  fprintf(f, "void\n");
  fprintf(f, "%s_unmarshall(\n", t->name);
  fprintf(f, "  %s   in,\n", s);
  fprintf(f, "  %s  *out)\n", t->name);
  fprintf(f, "{\n");
  fprintf(f, "  %s_from_net(in, out);\n", t->name);
  fprintf(f, "}\n");
  fprintf(f, "\n");

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

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

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

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

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

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

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

void
output_old_marshall_c_marshall(
  FILE                    *f,
  nasd_rpcgen_marshall_t  *marshall)
{
  nasd_rpcgen_type_t *type, *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    fprintf(oerr, "ERROR: %s not defined, cannot marshall %s\n",
      s, type->name);
    output_error();
    return;
  }

  fprintf(f, "\n");
  fprintf(f, "void\n");
  fprintf(f, "%s_marshall(\n", t->name);
  fprintf(f, "  %s  *in,\n", t->name);
  fprintf(f, "  %s   out)\n", s);
  fprintf(f, "{\n");
  fprintf(f, "  %s_to_net(in, out);\n", t->name);
  fprintf(f, "}\n");

  fprintf(f, "\n");
  fprintf(f, "void\n");
  fprintf(f, "%s_unmarshall(\n", t->name);
  fprintf(f, "  %s   in,\n", s);
  fprintf(f, "  %s  *out)\n", t->name);
  fprintf(f, "{\n");
  fprintf(f, "  %s_from_net(in, out);\n", t->name);
  fprintf(f, "}\n");

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_old_marshall_c(
  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_old_marshall_c_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_old_marshall_c_type(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_IMPORT:
        output_old_marshall_c_import(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CONST:
        output_old_marshall_c_const(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_STRUCT:
        output_old_marshall_c_struct(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CALL:
        output_old_marshall_c_call(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_UUID:
        output_old_marshall_c_uuid(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_DCE_ENDPOINT:
        /* we do NOTHING with this */
        break;
      case NASD_RPCGEN_DECL_VERSION:
        output_old_marshall_c_version(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_MARSHALL:
        output_old_marshall_c_marshall(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_BASEID:
        break;
      default:
        NASD_PANIC();
    }
  }

  output_old_marshall_c_trailer(f);

  fclose(f);
  printf("Wrote %s as old-style marshalling .c file\n", filename);
}

void
output_marshall_h_header(
  FILE  *f,
  char  *filename)
{
  static char tmp[MAXPATHLEN];
  nasd_rpcgen_filename_t *fn;
  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;
  }
  marshall_hold_comp = s;

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

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

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

void
output_marshall_h_type(
  FILE                *f,
  nasd_rpcgen_type_t  *type)
{
  nasd_rpcgen_type_t *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    return;
  }

  fprintf(f, "void %s_marshall(%s *in, %s out);\n",
    t->name, t->name, s);
  fprintf(f, "void %s_unmarshall(%s in, %s *out);\n",
    t->name, s, t->name);

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

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

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

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

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

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

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

void
output_marshall_h_marshall(
  FILE                    *f,
  nasd_rpcgen_marshall_t  *marshall)
{
  nasd_rpcgen_type_t *type, *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    return;
  }

  fprintf(f, "void %s_marshall(%s *in, %s out);\n",
    t->name, t->name, s);
  fprintf(f, "void %s_unmarshall(%s in, %s *out);\n",
    t->name, s, t->name);

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_marshall_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_marshall_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_marshall_h_type(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_IMPORT:
        output_marshall_h_import(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CONST:
        output_marshall_h_const(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_STRUCT:
        output_marshall_h_struct(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CALL:
        output_marshall_h_call(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_UUID:
        output_marshall_h_uuid(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_DCE_ENDPOINT:
        /* we do NOTHING with this */
        break;
      case NASD_RPCGEN_DECL_VERSION:
        output_marshall_h_version(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_MARSHALL:
        output_marshall_h_marshall(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_BASEID:
        break;
      default:
        NASD_PANIC();
    }
  }

  output_marshall_h_trailer(f);

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

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

  output_cpp_comment_header(f, filename);

  fprintf(f, "\n");
  fprintf(f, "#include <nasd/nasd_options.h>\n");
  fprintf(f, "#include <nasd/nasd_common.h>\n");
  fprintf(f, "#include <nasd/nasd_general.h>\n");
  if (global_spec.usc_import_list) {
    for(fn=global_spec.usc_import_list;fn;fn=fn->next) {
      fprintf(f, "#include <%s>\n", fn->filename);
    }
  }
}

void
output_marshall_c_trailer(
   FILE  *f)
{
}

void
output_marshall_c_type(
  FILE                *f,
  nasd_rpcgen_type_t  *type)
{
  nasd_rpcgen_type_t *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    return;
  }

  output_marshall_funcs(f, t, s);

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_marshall_c_import(
  FILE                  *f,
  nasd_rpcgen_import_t  *import)
{
  fprintf(f, "#include <%s.h>\n",
    import->filename);
}

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

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

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

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

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

void
output_marshall_c_marshall(
  FILE                    *f,
  nasd_rpcgen_marshall_t  *marshall)
{
  nasd_rpcgen_type_t *type, *t, *bt, *mt;
  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_prepend_suffix(t->name, "_otw", &s);

  if (!strcmp(t->name, s)) {
    free(s);
    return;
  }

  mt = lookup_type(s);
  if (mt == NULL) {
    free(s);
    fprintf(oerr, "ERROR: %s not defined, cannot marshall %s\n",
      s, type->name);
    output_error();
    return;
  }

  output_marshall_funcs(f, t, s);

  free(s);

  type->out_flags |= NASD_RPCGEN_OUT_FLAGS_MARSHALL;
}

void
output_marshall_c(
  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_marshall_c_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_marshall_c_type(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_IMPORT:
        output_marshall_c_import(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CONST:
        output_marshall_c_const(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_STRUCT:
        output_marshall_c_struct(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_CALL:
        output_marshall_c_call(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_UUID:
        output_marshall_c_uuid(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_DCE_ENDPOINT:
        /* we do NOTHING with this */
        break;
      case NASD_RPCGEN_DECL_VERSION:
        output_marshall_c_version(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_MARSHALL:
        output_marshall_c_marshall(f, decl->decl);
        break;
      case NASD_RPCGEN_DECL_BASEID:
        break;
      default:
        NASD_PANIC();
    }
  }

  output_marshall_c_trailer(f);

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

void
output_marshall_guts_struct(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  nasd_rpcgen_type_t  *struct_type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall)
{
  nasd_rpcgen_type_t *elem, *bt;
  char *strs, *strd;
  int l;

  l = 1024;
  strs = (char *)malloc(l);
  if (strs == NULL) {
    fprintf(oerr, "ERROR: out of memory\n");
    parse_error();
    return;
  }
  strd = (char *)malloc(l);
  if (strd == NULL) {
    free(strs);
    fprintf(oerr, "ERROR: out of memory\n");
    parse_error();
    return;
  }

  NASD_ASSERT(struct_type->type_is == NASD_RPCGEN_TYPE_STRUCT);
  for(elem=struct_type->struct_list;elem;elem=elem->struct_next) {
    sprintf(strs, "%s.%s", src_name, elem->name);
    sprintf(strd, "%s.%s", dst_name, elem->name);
    switch(elem->type_is) {
      case NASD_RPCGEN_TYPE_DERIVED:
        bt = basic_type_of_extended(elem);
        NASD_ASSERT(bt != NULL);
        switch(bt->type_is) {
          case NASD_RPCGEN_TYPE_INT8:
          case NASD_RPCGEN_TYPE_UINT8:
          case NASD_RPCGEN_TYPE_INT16:
          case NASD_RPCGEN_TYPE_UINT16:
          case NASD_RPCGEN_TYPE_INT32:
          case NASD_RPCGEN_TYPE_UINT32:
          case NASD_RPCGEN_TYPE_INT64:
          case NASD_RPCGEN_TYPE_UINT64:
          case NASD_RPCGEN_TYPE_STRUCT:
          case NASD_RPCGEN_TYPE_STRING:
          case NASD_RPCGEN_TYPE_FLOAT:
          case NASD_RPCGEN_TYPE_DOUBLE:
            output_marshall_guts_basic(f, elem, lvl,
              indentstr, strs, strd, cook_chars, unmarshall);
            break;
          case NASD_RPCGEN_TYPE_ARRAY:
            output_marshall_guts_array(f, elem, bt,
              lvl, indentstr, strs, strd, cook_chars, unmarshall);
            break;
          default:
            NASD_PANIC();
        }
        break;
      case NASD_RPCGEN_TYPE_ARRAY:
        output_marshall_guts_array(f, elem, elem, lvl,
          indentstr, strs, strd, cook_chars, unmarshall);
        break;
      default:
        NASD_PANIC();
    }
  }

  free(strs);
  free(strd);
}

void
output_marshall_guts_basic(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall)
{
  nasd_rpcgen_type_t *bt;
  char *t64;

  bt = basic_type_of_extended(type);
  NASD_ASSERT(bt != NULL);
  switch(bt->type_is) {
    case NASD_RPCGEN_TYPE_INT8:
    case NASD_RPCGEN_TYPE_UINT8:
      fprintf(f, "%s%s = %s;\n", indentstr,
        dst_name, src_name);
      break;
    case NASD_RPCGEN_TYPE_INT16:
    case NASD_RPCGEN_TYPE_UINT16:
      fprintf(f, "%s%s = nasd_%s16(%s);\n", indentstr,
        dst_name, cook_chars, src_name);
      break;
    case NASD_RPCGEN_TYPE_INT32:
    case NASD_RPCGEN_TYPE_UINT32:
      fprintf(f, "%s%s = nasd_%s32(%s);\n", indentstr,
        dst_name, cook_chars, src_name);
      break;
#if NASD_ALIGN_OTW_TYPES > 0
      /*
       * This is more efficient, but assumes that the _otw_t has
       * alignment requirements equal to the original type.
       */
    case NASD_RPCGEN_TYPE_INT64:
    case NASD_RPCGEN_TYPE_UINT64:
      if (bt->type_is == NASD_RPCGEN_TYPE_INT64)
        t64 = "int";
      else if (bt->type_is == NASD_RPCGEN_TYPE_UINT64)
        t64 = "uint";
      else
        NASD_PANIC();
      fprintf(f, "%s{\n", indentstr);
      if (unmarshall == 0) {
        /*
         * MARSHALL TO NETWORK
         */
        fprintf(f, "%s  nasd_%s32 hi, lo, *t;\n", indentstr, t64);
        fprintf(f, "\n");
        fprintf(f, "%s  hi = (nasd_%s32)((nasd_%s64)((%s)>>32));\n",
          indentstr, t64, t64, src_name);
        fprintf(f, "%s  lo = "
          "(nasd_%s32)((nasd_%s64)((%s)&nasd_%s64cast(0xffffffff)));\n",
          indentstr, t64, t64, src_name, t64);
        fprintf(f, "%s  t = (nasd_%s32 *)&(%s);\n",
          indentstr, t64, dst_name);
        fprintf(f, "%s  t[0] = nasd_%s32(hi);\n", indentstr, cook_chars);
        fprintf(f, "%s  t[1] = nasd_%s32(lo);\n", indentstr, cook_chars);
        fprintf(f, "%s}\n", indentstr);
      }
      else {
        /*
         * UNMARSHALL FROM NETWORK
         */
        fprintf(f, "%s  nasd_%s32 hi, lo, *t;\n", indentstr, t64);
        fprintf(f, "\n");
        fprintf(f, "%s  t = (nasd_%s32 *)&(%s);\n",
          indentstr, t64, src_name);
        fprintf(f, "%s  hi = nasd_%s32(t[0]);\n", indentstr, cook_chars);
        fprintf(f, "%s  lo = nasd_%s32(t[1]);\n", indentstr, cook_chars);
        fprintf(f, "%s  %s = ((((nasd_%s64)hi)&nasd_%s64cast(0xffffffff))<<32)"
          "&nasd_%s64cast(0xffffffff00000000);\n",
          indentstr, dst_name, t64, t64, t64);
        fprintf(f, "%s  %s |= ((nasd_%s64)lo)"
          "&nasd_%s64cast(0xffffffff);\n",
          indentstr, dst_name, t64, t64);
        fprintf(f, "%s}\n", indentstr);
      }
      break;
#else /* NASD_ALIGN_OTW_TYPES > 0 */
    case NASD_RPCGEN_TYPE_UINT64:
    case NASD_RPCGEN_TYPE_INT64:
      if (bt->type_is == NASD_RPCGEN_TYPE_INT64)
        t64 = "int";
      else if (bt->type_is == NASD_RPCGEN_TYPE_UINT64)
        t64 = "uint";
      else
        NASD_PANIC();
      fprintf(f, "%s{\n", indentstr);
      if (unmarshall == 0) {
        /*
         * MARSHALL TO NETWORK
         */
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[0] = %s"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[1] = ((%s)>>8)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[2] = ((%s)>>16)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[3] = ((%s)>>24)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[4] = ((%s)>>32)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[5] = ((%s)>>40)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[6] = ((%s)>>48)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  ((nasd_byte_t *)&(%s))[7] = ((%s)>>56)"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
      }
      else {
        /*
         * UNMARSHALL FROM NETWORK
         */
        fprintf(f, "%s  %s = ((nasd_byte_t *)&(%s))[7]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[6]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[5]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[4]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[3]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[2]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[1]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
        fprintf(f, "%s  %s <<= 8;\n", indentstr, dst_name);
        fprintf(f, "%s  %s |= ((nasd_byte_t *)&(%s))[0]"
          "&nasd_%s64cast(0xff);\n",
          indentstr, dst_name, src_name, t64);
      }
      fprintf(f, "%s}\n", indentstr);
      break;
#endif /* NASD_ALIGN_OTW_TYPES > 0 */
    case NASD_RPCGEN_TYPE_STRUCT:
      output_marshall_guts_struct(f, type, bt, lvl, indentstr,
        src_name, dst_name, cook_chars, unmarshall);
      break;
    case NASD_RPCGEN_TYPE_STRING:
      fprintf(f, "%sstrcpy(out_template, out);\n", indentstr);
      break;
    case NASD_RPCGEN_TYPE_ARRAY:
      output_marshall_guts_array(f, type, bt,
        lvl, indentstr, src_name, dst_name, cook_chars,
        unmarshall);
      break;
    case NASD_RPCGEN_TYPE_FLOAT:
    case NASD_RPCGEN_TYPE_DOUBLE:
      /* hope for IEEE */
      fprintf(f, "%s*out_template = *out;\n", indentstr);
      break;
    default:
      NASD_PANIC();
  }
}

void
output_marshall_guts_array(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  nasd_rpcgen_type_t  *array_type,
  int                  lvl,
  char                *indentstr,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall)
{
  char *indent2str, *strs, *strd, *is[NASD_RPCGEN_MAX_ARRDIM+1];
  int j, l, i, n[NASD_RPCGEN_MAX_ARRDIM];
  nasd_rpcgen_type_t *bt;

  NASD_ASSERT(array_type->type_is == NASD_RPCGEN_TYPE_ARRAY);

  l = strlen(indentstr) + 3;
  indent2str = (char *)malloc(l);
  if (indent2str == NULL) {
    fprintf(oerr, "ERROR: out of memory\n");
    output_error();
    return;
  }
  strcpy(indent2str, indentstr);
  strcat(indent2str, "  ");

  bt = basic_type_of_extended(array_type->derived_from);
  NASD_ASSERT(bt != NULL);
  switch(bt->type_is) {
    case NASD_RPCGEN_TYPE_INT8:
    case NASD_RPCGEN_TYPE_UINT8:
      if (array_type->ispad) {
        fprintf(f, "%sbzero((char *)(%s), %d);\n", indentstr, dst_name,
          array_type->size);
      }
      else {
        fprintf(f, "%sbcopy((char *)(%s), (char *)(%s), %d);\n",
          indentstr, src_name, dst_name,
          array_type->size);
      }
      break;
    case NASD_RPCGEN_TYPE_INT16:
    case NASD_RPCGEN_TYPE_UINT16:
    case NASD_RPCGEN_TYPE_INT32:
    case NASD_RPCGEN_TYPE_UINT32:
    case NASD_RPCGEN_TYPE_INT64:
    case NASD_RPCGEN_TYPE_UINT64:
    case NASD_RPCGEN_TYPE_STRUCT:
    case NASD_RPCGEN_TYPE_STRING:
    case NASD_RPCGEN_TYPE_FLOAT:
    case NASD_RPCGEN_TYPE_DOUBLE:
      l = 1024;
      strs = (char *)malloc(l);
      strd = (char *)malloc(l);
      if ((strs == NULL) || (strd == NULL)) {
        fprintf(oerr, "ERROR: out of memory\n");
        parse_error();
        return;
      }
      if ((array_type->size / array_type->derived_from->size)
        < global_spec.array_thresh)
      {
        for(i=0;i<array_type->ndim;i++) {
          n[i] = 0;
        }
        do {
          strcpy(strs, src_name);
          strcpy(strd, dst_name);
          for(i=0;i<array_type->ndim;i++) {
            sprintf(strs, "%s[%d]", strs, n[i]);
            sprintf(strd, "%s[%d]", strd, n[i]);
          }
          output_marshall_guts_basic(f, array_type->derived_from, lvl,
            indentstr, strs, strd, cook_chars, unmarshall);
          i = array_type->ndim - 1;
          do {
            n[i]++;
            if (n[i] < array_type->nelements[i])
              break;
            n[i] = 0;
            i--;
          } while(i >= 0);
        } while((n[0] < array_type->nelements[0]) && (i >= 0));
      }
      else {
        l = strlen(indent2str)+1;
        for(i=0;i<=array_type->ndim;i++) {
          is[i] = (char *)malloc(l);
          if (is[i] == NULL) {
            fprintf(oerr, "ERROR: out of memory\n");
            output_error();
            return;
          }
          if (i) {
            strcpy(is[i], is[i-1]);
            strcat(is[i], "  ");
          }
          else {
            strcpy(is[i], indent2str);
          }
          l += 2;
        }
        fprintf(f, "%s{\n", indentstr);
        for(i=0;i<array_type->ndim;i++) {
          fprintf(f, "%sint i%d;\n", indentstr, i);
        }
        fprintf(f, "\n");
        for(i=0;i<array_type->ndim;i++) {
          fprintf(f, "%sfor(i%d=0;i%d<%d;i%d++) {\n",
            is[i], i, i, array_type->nelements[i], i);
          strcpy(strs, src_name);
          strcpy(strd, dst_name);
          for(j=0;j<array_type->ndim;j++) {
            sprintf(strs, "%s[i%d]", strs, j);
            sprintf(strd, "%s[i%d]", strd, j);
          }
          output_marshall_guts_basic(f, array_type->derived_from, lvl,
            is[i+1], strs, strd, cook_chars, unmarshall);
          fprintf(f, "%s}\n", is[i]);
        }
        fprintf(f, "%s}\n", indentstr);
        for(i=0;i<=array_type->ndim;i++) {
          free(is[i]);
        }
      }
      free(strs);
      free(strd);
      break;
    default:
      NASD_PANIC();
  }

  free(indent2str);
}

void
output_marshall_guts(
  FILE                *f,
  nasd_rpcgen_type_t  *type,
  char                *type_otw_name,
  int                  lvl,
  char                *src_name,
  char                *dst_name,
  char                *cook_chars,
  int                  unmarshall)
{
  char *indentstr, *strs, *strd;
  int i, l, freeindentstrs;
  nasd_rpcgen_type_t *bt;

  l = (lvl*2) + 1;
  indentstr = (char *)malloc(l);
  if (indentstr == NULL) {
    indentstr = "";
    freeindentstrs = 0;
  }
  else {
    freeindentstrs = 1;
  }
  for(i=0;i<(l-1);i++) {
    indentstr[i] = ' ';
  }
  indentstr[i] = '\0';

  switch(type->type_is) {
    case NASD_RPCGEN_TYPE_DERIVED:
      bt = basic_type_of_extended(type);
      NASD_ASSERT(bt != NULL);
      switch(bt->type_is) {
        case NASD_RPCGEN_TYPE_INT8:
        case NASD_RPCGEN_TYPE_UINT8:
        case NASD_RPCGEN_TYPE_INT16:
        case NASD_RPCGEN_TYPE_UINT16:
        case NASD_RPCGEN_TYPE_INT32:
        case NASD_RPCGEN_TYPE_UINT32:
        case NASD_RPCGEN_TYPE_INT64:
        case NASD_RPCGEN_TYPE_UINT64:
        case NASD_RPCGEN_TYPE_FLOAT:
        case NASD_RPCGEN_TYPE_DOUBLE:
        case NASD_RPCGEN_TYPE_STRUCT:
          l = 1024;
          strs = (char *)malloc(l);
          strd = (char *)malloc(l);
          sprintf(strs, "(*%s)", src_name);
          sprintf(strd, "(*%s)", dst_name);
          output_marshall_guts_basic(f, type, lvl,
            indentstr, strs, strd, cook_chars, unmarshall);
          free(strs);
          free(strd);
          break;
        case NASD_RPCGEN_TYPE_STRING:
          output_marshall_guts_basic(f, type, lvl,
            indentstr, src_name, dst_name, cook_chars, unmarshall);
          break;
        case NASD_RPCGEN_TYPE_ARRAY:
          output_marshall_guts_array(f, type, bt,
            lvl, indentstr, src_name, dst_name, cook_chars, unmarshall);
          break;
        default:
          NASD_PANIC();
      }
      break;
    case NASD_RPCGEN_TYPE_ARRAY:
      output_marshall_guts_array(f, type, type, lvl,
        indentstr, src_name, dst_name, cook_chars, unmarshall);
      break;
    default:
      NASD_PANIC();
  }

  if (freeindentstrs) {
    free(indentstr);
  }
}

void
output_marshall_funcs(
  FILE                *f,
  nasd_rpcgen_type_t  *t,
  char                *t_otw_name)
{
  fprintf(f, "\n");
  fprintf(f, "void\n");
  fprintf(f, "%s_marshall(\n", t->name);
  fprintf(f, "  %s  *in,\n", t->name);
  fprintf(f, "  %s   out)\n", t_otw_name);
  fprintf(f, "{\n");
  fprintf(f, "  %s *out_template;\n", t->name);
  fprintf(f, "\n");
  fprintf(f, "  out_template = (%s *)out;\n", t->name);
  fprintf(f, "\n");
  output_marshall_guts(f, t, t_otw_name, 1, "in", "out_template", "hton", 0);
  fprintf(f, "}\n");

  fprintf(f, "\n");
  fprintf(f, "void\n");
  fprintf(f, "%s_unmarshall(\n", t->name);
  fprintf(f, "  %s   in,\n", t_otw_name);
  fprintf(f, "  %s  *out)\n", t->name);
  fprintf(f, "{\n");
  fprintf(f, "  %s *in_template;\n", t->name);
  fprintf(f, "\n");
  fprintf(f, "  in_template = (%s *)in;\n", t->name);
  fprintf(f, "\n");
  output_marshall_guts(f, t, t_otw_name, 1, "in_template", "out", "ntoh", 1);
  fprintf(f, "}\n");
}

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