From:	CSBVAX::MRGATE!RELAY-INFO-VAX@CRVAX.SRI.COM@SMTP  9-AUG-1988 07:22
To:	ARISIA::EVERHART
Subj:	UNSDL Part 1 of 3 parts


Received: From KL.SRI.COM by CRVAX.SRI.COM with TCP; Tue,  9 AUG 88 03:30:58 PDT
Received: from uwavm.acs.washington.edu (oly.acs.washington.edu) by KL.SRI.COM with TCP; Tue, 9 Aug 88 03:08:12 PDT
Received: from UWAVM.ACS.WASHINGTON.EDU by uwavm.acs.washington.edu ; Tue, 09 Aug 88 03:01:50 PDT
Received: from UWAVM.ACS.WASHINGTON.EDU by UWAVM.ACS.WASHINGTON.EDU (Mailer
 X1.24) with BSMTP id 2809; Tue, 09 Aug 88 03:01:46 PDT
P1-Message-Id: US**EDU;UWAVM.ACS.WASHINGTON.EDU:LTbkovyn
Date:         Mon, 8 Aug 88 21:57-0700
X400-Trace:   US**EDU; arrival Mon, 8 Aug 88 21:57-0700 action Relayed
X400-Trace:   US**EDU; arrival Tue, 9 Aug 88 03:01-0700 action Relayed
From:         Joe Meadows</ADMD=/PRMD=BITNET/O=FHCRCVAX/PN=JOE/@US>
Subject:      UNSDL Part 1 of 3 parts
To:           <info-vax@kl.sri.COM>
Message-Id:   <UWAVM.ACS.WASHINGTON.EDU:LTbkovyn*>
X-VMS-To: IN%"info-vax@kl.sri.com"


        The following is part one (of 3 parts) of my UNSDL program. This
program works in conjunction with SDLNPARSE (SDL/NOPARSE) to generate
C language header file from the distributed SDL definitions (contained
in SYS$SHARE:STARLETSD.TLB).

Included in this part are:
        AAAREADME.TXT, SDLCC-CLD.CLD, and SDLCC.C

  Cheers,
  Joe Meadows Jr.
  VAX/VMS System Manager / guru in training
  Fred Hutchinson Cancer Research Center
  1124 Columbia St.
  Seattle Wa. 98104
     bitnet - JOE@FHCRCVAX
     arpa   - JOE%FHCRCVAX.BITNET@OLY.ACS.WASHINGTON.EDU
     voice  - (206) 467-4970

$ create/log AAAREADME.TXT
$DECK
        The files included make up two modules to be used with SDL.
If you have MAKE, the included MAKEFILE can be used to compile and
link all of the modules (the UNSDL program, the CC module and the
DUMP module) by just saying MAKE. You may compile individually by
saying MAKE UNSDL, MAKE CC or MAKE DUMP if you prefer. If you don't
have make, you can use @COMPILE to compile everything.

        To actually use these modules, you need to define SDL$SHARE
to point to the directory in which the executable reside, i.e.
$ DEFINE SDL$SHARE SYS$DISK:[]  ! current directory
You also need to extract the modules from SYS$SHARE:STARLETSD.
For example, if you wanted $JPIDEF you would extract STARDEFFL
out of the library, i.e.
$ LIBRARY/EXTRACT=STARDEFFL/OUT=STARDEFFL.SDI/TEXT SYS$SHARE:STARDEFFL
All of the modules normally found in the STARLET macro library are
chunked together in sections, alphabetically by module name. The above
is the section going from F to L, hence the name.
You will then need to define the UNSDL command after modifying
UNSDL.CLD, i.e. SET COMMAND UNSDL

        UNSDL simply sets up some symbols and then executes the proper
SDL/NOPARSE/LANGUAGE=... command. The symbols are then read by the language
module (the DUMP module ignores them currently) and modifies its actions
accordingly. See UNSDL.CLD for a description of the command qualifiers
and what they affect. Note that not all are necessarily implemented.

        The CC module allows you to specify other options if you
use UNSDL. To specify these options, you must use a command of the
form UNSDL/LANGUAGE=CC="options", where 'options' is a comma separated
list. The following are the valid options:
        INDENT=value
                number of spaces to indent for structures/unions
        MASK=[HEX | DECIMAL]
                us HEX or DECIMAL masks for #define
        CASE=[ORIGINAL | MIXED | UPPER | LOWER]
                select the case to use, ORIGINAL specifies that the original
                case is to be used, MIXED specifies that #defines will be
                done in uppercase, and structure/union/variable declarations
                will be done in lower case. UPPER specifies that everything
                will be uppercased, and LOWER specifies that everything
                will be lowercased. Note that this does not modify text in
                comments..
        [NO]PROTOTYPES
                specifies that function prototypes are to be used. Note that
                this feature is a use at your own risk adventure. I've noticed
                several functions which were declared wrong in the original
                SDL files.. (i.e. lib$getjpi, lib$getdvi, lib$getsyi)
        [NO]COMMENTS
                specifies wether to include comments or not. Can reduce
                the size significantly if you use NOCOMMENTS
        MODULES=(module-list)
                Allows you to extract a single module (or list of modules).
                The module name(s) can be wildcarded.
        [NO]SEPARATE
                Specifies that separate output files are to be created
                for each module. The files will be named according to
                the module name.
$EOD
$ create/log SDLCC-CLD.CLD
$DECK
module uncc
  define type mask_type
    keyword hex
    keyword decimal
  define type case_type
    keyword original
    keyword mixed
    keyword upper
    keyword lower
  define type cc_type
    keyword indent, value(type=$number)
    keyword mask, value(type=mask_type)
    keyword case, value(type=case_type)
    keyword prototypes, negatable
    keyword comments, negatable, default
    keyword modules, value(list)
    keyword separate, negatable
    keyword infile
  define verb unsdlcc
    parameter p1, value(type=cc_type,list)
$EOD
$ create/log SDLCC.C
$DECK
/* Version 1.3 August 8, 1988
   This program is mapped in by SDLNPARSE, it does not get run directly.
   You may either use the provided UNSDL program, or use SDL/NOPARSE
   directly.


   8/5/88 Fixed handling of structure/union ending.
          removed the check for the 'bottom' flag, now all structures
          and unions are closed after recursively displaying their
          associated fields. This means that the comments meant for the
          next structure will be included at the end of the previous
          structure. Ugly. But it works.

   8/3/88 modified to compile with GCC compiler.

   7/15/88 modified to work with VMS 5.0

   3/11/88 Added #ifdef, supposrt for mixed case, better comments

   2/4/88 Modified a few things, renamed first arg to sdl$output
          from outfile to outputname to avoid conflict with the globally
          declared filehandle of the (previously) same name.

   Future:
        Add better handling for DFloat vs. GFloat
        use #if CC$gfloat to figure out which is in use.
        possibly define D/F and Hfloat with structures that
        actually define the mantissa et al correctly.

*/
#include <stdio.h>
#include <ctype.h>
#include <descrip.h>
#include <jpidef.h>
#include "sdldef.h"

#define CLI$_NEGATED 0X000381F8

int readable();
int uncc();

#define INDENT 4
#define MAXLEVEL 20
#define CASE 0
#define MASK 1
#define COMMENTS 1
#define PROTOTYPES 0
#define SEPARATE 0

static FILE *outfile = 0;
static char out[256];
static int maxlevel;
static char spaces[INDENT*MAXLEVEL+1];
static int column;
static char *datatypes[] = {"int "/*void*/,"int *","char ","char ","char ",
        "char "/*decimal*/,"double float "/*dfloat*/,"float ",
        "double float "/*gfloat*/,"int "/*hfloat*/,"long int ",
        "int "/*octaword*/,"int "/*quadword*/,"unsigned ",
        "short int ","struct ","union ","int "/*anything*/,
        "int (*","DFLOAT_COMPLEX","FFLOAT_COMPLEX","GFLOAT_COMPLEX",
        "HFLOAT_COMPLEX"/* possibly, just guessing */ };

static struct dsc$descriptor null =
       {1,DSC$K_DTYPE_T,DSC$K_CLASS_S,"\0"};
static struct dsc$descriptor cmd_prefix =
       {8,DSC$K_DTYPE_T,DSC$K_CLASS_S,"UNSDLCC "};
static struct dsc$descriptor command =
        {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
static struct dsc$descriptor string =
        {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};

static struct Head *main_arg3;
static struct {
    int indent;             /* number of spaces to indent per level */
    unsigned outcase : 2;      /* 0=Original, 1=Natural, 2=Upper, 3=Lower */
    unsigned mask : 1;      /* 0=decimal, 1=hex */
    unsigned comments : 1;  /* 0=no comments, 1=comments */
    unsigned separate : 1;  /* 0=don't separate, 1=do */
    unsigned prototype : 1; /* 0=don't include prototypes, 1=do */
} options;

struct ModuleName {
  struct dsc$descriptor name;
  struct ModuleName *next;
};
static struct ModuleName SelectModules;

sdl$output(outputname,module,root)
  struct sptr *outputname, *module;
  struct Head *root;
{
  struct Node *node;
  char out[256];
  int status,i;
  int four=4;
  int five=5;
  long int imagecount,imagecountsaved;
  struct dsc$descriptor imagecnt =
           {4,DSC$K_DTYPE_T,DSC$K_CLASS_S,&imagecount};
  struct itmlst jpi[2] = {{4,JPI$_IMAGECOUNT,&imagecount,0},{0,0,0,0}};
  struct ModuleName *mod;

  for (i=0; i < (INDENT*MAXLEVEL); i++)
    spaces[i] = ' ';
  spaces[i] = '\0';

  options.indent = INDENT;
  options.mask = MASK;
  options.outcase = CASE;
  options.comments = COMMENTS;
  options.separate = SEPARATE;
  options.prototype = PROTOTYPES;
  /* let's check for the symbol SDL_SYMBOL (defined in sdldef.h),
     if it exists, we should set things up accordingly */
  status = lib_get_symbol(SDL_SYMBOL,&string);
  if (status & 1) {
    /* pull out the first four bytes (the imagecount) and compare it
       with our image count (make sure this isn't an old symbol */
    /* well, get around to it eventually */
    str$left(&imagecnt,&string,&four); /* numeric result in 'imagecount' */
    str$right(&string,&string,&five);

    /* save the image count (plus 1 for new image activation since unsdl) */
    imagecountsaved = imagecount + 1;
    /* get the real imagecount */
    status = sys$getjpiw(0,0,0,&jpi,0,0,0);
    if (!(status & 1)) return(status);
    /* compare the imagecounts - should be equal */
    if (imagecount == imagecountsaved) {
      /* prefix command string with command */
      str$copy_dx(&command,&cmd_prefix);
      str$append(&command,&string);

      /* need to parse the string */
      status = cli$dcl_parse(&command,uncc);
      if (!(status & 1))
        return;

      if (cli_get_value("P1.INDENT",&string) & 1) {
        str$append(&string,&null);
        options.indent = atoi(string.dsc$a_pointer);
      };

      if (cli_present("P1.MASK.DECIMAL") & 1) options.mask = 0;
      if (cli_present("P1.MASK.HEX") & 1) options.mask = 1;
      if (cli_present("P1.CASE.ORIGINAL") & 1) options.outcase = 0;
      if (cli_present("P1.CASE.MIXED") & 1) options.outcase = 1;
      if (cli_present("P1.CASE.UPPER") & 1) options.outcase = 2;
      if (cli_present("P1.CASE.LOWER") & 1) options.outcase = 3;
      status = cli_present("P1.COMMENTS");
      if (status & 1) options.comments = 1;
      if (status == CLI$_NEGATED) options.comments = 0;
      if (cli_present("P1.PROTOTYPES") & 1) options.prototype = 1;
      if (cli_present("P1.SEPARATE") & 1) options.separate = 1;
      if (cli_present("P1.MODULES") & 1) {
        mod = &SelectModules;
        while (cli_get_value("P1.MODULES",&string) & 1) {
          mod->next = calloc(1,sizeof(struct ModuleName));
          mod = mod->next;
          mod->name = string;
          string.dsc$w_length = 0;
          string.dsc$a_pointer = 0;
        };
      };
    };
  };

  maxlevel = (INDENT*MAXLEVEL) / ((options.indent == 0)?1:options.indent);
  printf("Source: %.*s\n",root->banner_len,root->banner);

  if (options.separate == 0) {
    /* get outputname copied into local space, so I can add a zero to it. */
    for (i=0; (i < outputname->len) && (outputname->str[i] != ' '); i++)
      out[i] = outputname->str[i];
    out[i] = '\0';
    /* if no output file name present, use module name. */
    if (i==0) {
      for (i=0; (i < module->len) && (module->str[i] != ' '); i++)
        out[i] = module->str[i];
      out[i] = '.';
      out[i+1] = 'H';
      out[i+2] = '\0';
    };
    printf("Creating file %s\n",out);
    outfile = fopen(out,"w","rfm=var","rat=cr");
    fprintf(outfile,"/* Created by SDL %.*s */\n",10,root->version);
    fprintf(outfile,"/* Source: %.*s */\n",root->banner_len,root->banner);
    out[i] = '_';
    fprintf(outfile,"#ifndef %s\n",out);
    fprintf(outfile,"#define %s\n",out);
    column = 1;
  };
  main_arg3 = root;

  node = root->head;
  if ((readable(node)) && (node->type == SDL$C_NODE_ROOT)) {
    if (readable(node->flink))
      traverse_modules(node->flink); /* this should be the root node */
    else
      printf("INTERNAL ERROR, ROOT NODE FORWARD POINTER CORRUPT\n");
    }
  else
    printf("INTERNAL ERROR, ROOT NODE CORRUPT\n");

  /* delete the symbol */
  lib_delete_symbol(SDL_SYMBOL);

  fprintf(outfile,"#endif\n");
  fclose(outfile);

  /* should reset the dcl parse tables somehow... */
  /* but since that is imposible, the local tables include 'infile' */
}

traverse_modules(node)
  struct Node *node;
{
  while (node->type == SDL$C_NODE_MODULE) {
    printf("Reading module %.*s\n",node->name.len,node->name.str);
    if (check_module(node)) {
      setcase(node,1);
      if (options.separate == 1) {
        if (outfile) {
          fprintf(outfile,"#endif\n");
          fclose(outfile);
        };
        sprintf(out,"%.*s.H",node->name.len,node->name.str);
        outfile = fopen(out,"w","rfm=var","rat=cr");

        printf("Creating file %s\n",out);
        fprintf(outfile,"/* Created by SDL %.*s */\n",
                10,main_arg3->version);
        fprintf(outfile,"/* Source: %.*s */\n",
                main_arg3->banner_len,main_arg3->banner);
        fprintf(outfile,"#ifndef %.*s_H\n",node->name.len,node->name.str);
        fprintf(outfile,"#define %.*s_H\n",node->name.len,node->name.str);
      };
      fprintf(outfile," \n");
      fprintf(outfile,"/*** MODULE %.*s ***/\n",node->name.len,node->name.str);
      column = 1;
      if (node->comment) {
        print_comment(node);
        newline();
      };
      if (readable(node->child))
        traverse_module(node->child,0);
      else {
        printf("INTERNAL ERROR, MODULE NODES CHILD POINTER CORRUPT\n");
        printf("MODULE NOT BEING PROCESSED\n");
      };
    };
    node = node->flink;
    if (!readable(node)) {
      printf("INTERNAL ERROR, MODULE NODE FORWARD POINTER CORRUPT\n");
      printf("ABORTING\n");
      return;
    };
  };
}

traverse_module(node,level)
  struct Node *node;
{
  /* the first node should always be a head node, let's verify that
     and then move forward. Note that we then simply loop until we
     get back to the head node again */
  if (node->type == SDL$C_NODE_HEAD) {
    node = node->flink;
    while(readable(node) && (node->type != SDL$C_NODE_HEAD)) {
      print_module(node,level);
      node = node->flink;
    };
    if (!readable(node))
      printf("INTERNAL ERROR, FORWARD POINTER CORRUPT\n");
  }
  else
    printf("INTERNAL ERROR, NODE NOT A HEAD NODE\n");
}

print_module(node,level)
  struct Node *node;
{
  column = 1;
  switch (node->type) {
    case SDL$C_NODE_COMMENT:
      setcase(node,0);
      if (options.comments) {
        print_comment(node);
        newline();
      };
      break;
    case SDL$C_NODE_CONSTANT:
      setcase(node,1);
      column += fprintf(outfile,"#define ");
      print_name(node);
      column += fprintf(outfile," ");
      if (node->sdl_flag_bits.flag.m_mask && options.mask)
        column += fprintf(outfile,"0x%08X",node->typeinfo);
      else
        column += fprintf(outfile,"%d",node->typeinfo);
      print_comment(node);
      newline();
      break;
    case SDL$C_NODE_ENTRY:
      setcase(node,-1);

      column += fprintf(outfile,"/*+~");
      print_name(node);
      column += fprintf(outfile,"~+*/");
      newline();

      print_predatatype(node);
      print_name(node);
      print_postdatatype(node);

      /* okay, let's see if they want function prototyping */
      if (options.prototype) {
        column += fprintf(outfile,"(");
        if (node->child) { /* any arguments? */
          print_comment(node);
          newline();
          column = 1;
          if (readable(node->child))
            print_prototype(node->child);
          else {
            printf("INTERNAL ERROR, ENTRY NODE CHILD POINTER CORRUPT\n");
            fprintf(outfile,
              "/* INTERNAL ERROR, UNABLE TO INCLUDE PROTOTYPE */\n");
            column = 1;
          };
          column += fprintf(outfile,"%.*s) ;",options.indent,spaces);
        }
        else { /* if not, just display the rest of line */
          column += fprintf(outfile,") ;");
          print_comment(node);
        };
        newline();
      }
      else {
        column += fprintf(outfile,"() ;");
        print_comment(node);
        newline();
      };

      column += fprintf(outfile,"/*~-");
      print_name(node);
      column += fprintf(outfile,"-~*/");
      newline();

      break;
    case SDL$C_NODE_ITEM:
      print_item(node,level);
      break;
  };
}

print_item(node,level)
  struct Node *node;
  int level;
{
  setcase(node,-1);
  if (level > maxlevel)
    level = maxlevel;
  column += fprintf(outfile,"%.*s",level*options.indent,spaces);
  print_predatatype(node);
  switch (node->datatype) {
    case SDL$C_TYPE_STRUCTURE:
    case SDL$C_TYPE_UNION:
      if (level==0) {
        print_name(node);
        column += fprintf(outfile," ");
      };
      print_postdatatype(node);
      if ((level==0) && (node->sdl_flag_bits.flag.m_based) && (node->typeinfo))
        column += fprintf(outfile," /* WARNING: aggregate has origin of %d */",
                node->typeinfo);
      print_comment(node);
      newline();
      column = 1;
      if (readable(node->child))
        traverse_module(node->child,level+1);
      else
        printf("INTERNAL ERROR, ITEM NODE CHILD POINTER CORRUPT\n");
      if (level > 0) {
        column += fprintf(outfile,"%.*s} ",(level+1)*options.indent,spaces);
        print_name(node);
        column += fprintf(outfile,";");
        newline();
      }
      else {
        column += fprintf(outfile,"%.*s} ;",level*options.indent,spaces);
        newline();
      }
      break;
    default:
      print_name(node);
      print_postdatatype(node);
      column += fprintf(outfile,";");
      print_comment(node);
      newline();
      break;
  };
};

print_comment(node)
  struct Node *node;
{
  struct sptr *ptr;
  char *c;
  int l,x;

  if (node->comment && options.comments) {
    /* print leading space if not at start of line */
    if (column > 1)
      column += fprintf(outfile," ");

    /* print white space up to next tab */
    x = 8 - ((column - 1) % 8);
    if (x == 8)
      x = 0;
    if (x)
      column += fprintf(outfile,"%.*s",x,spaces);

    ptr = node->comment;

    column += fprintf(outfile,"/*");
    c = ptr->str;
    l = ptr->len;
    for (x = 0;(x < l) && (c[x] != '\t');++x);
    while (c[x] == '\t') {
      column += fprintf(outfile,"%.*s",x,c);
      ++x;
      c += x;
      l -= x;
      /* print white space up to next tab */
      x = 8 - ((column - 1) % 8);
      if (x == 8)
        x = 0;
      if (x)
        column += fprintf(outfile,"%.*s",x,spaces);
      for (x = 0;(x < l) && (c[x] != '\t');++x);
    };
    column += fprintf(outfile,"%.*s",x,c);

    x = 79 - column; /* pad to 80 columns if possible */
    if (x < 0) {
      x = 8 - ((column + 1) % 8); /* pad to next tab if over 80 chars */
      if (x == 8)
        x = 0;
    };
    column += fprintf(outfile,"%.*s*/",x,spaces);

  };
}

print_name(node)
  struct Node *node;
{
  column += fprintf(outfile,"%.*s",node->name.len,node->name.str);
}

print_predatatype(node)
  struct Node *node;
{
  static char tmpname[9] = "        ";
  static int tmpindx = -1;
  int i;

  if (node->sdl_flag_bits.flag.m_unsigned)
    column += fprintf(outfile,"unsigned ");

  switch (node->datatype) {
    case SDL$C_TYPE_HFLOAT:
    case SDL$C_TYPE_OCTAWORD:
      for (i=0; (i < 8) && (i < node->name.len); i++) {
        if (tmpname[i] != node->name.str[i])
          tmpindx = -1;
        tmpname[i] = node->name.str[i];
      };
      ++tmpindx;
      tmpname[i] = '\0';
      column += fprintf(outfile,"struct {int %s$$ret_%d_ [4];} ",
                tmpname,tmpindx);
      /* hmm, the above name is used by the VWS SDLCC for ENTRY nodes,
         I need to find an example in an ITEM node and see if they do it
         any differently.. Probably they change the "ret" to something else
      */
      break;
    default:
      column += fprintf(outfile,"%s",datatypes[node->datatype]);
      break;
  };
}

print_postdatatype(node)
  struct Node *node;
{
  switch(node->datatype) {
    case SDL$C_TYPE_BITFIELD:
      column += fprintf(outfile," : %d",node->fldsiz);
      break;
    case SDL$C_TYPE_DECIMAL:
      /* I don't know how to do this, I have seen no uses of it yet.
         I would think I need to use node->size or (hidim-lodim)/2 or
         something along those lines. */
      column += fprintf(outfile," [%d]",node->size);
      break;
    case SDL$C_TYPE_QUADWORD:
      column += fprintf(outfile," [2]");
      break;
    case SDL$C_TYPE_OCTAWORD:
      column += fprintf(outfile," [4]");
      break;
    case SDL$C_TYPE_STRUCTURE:
    case SDL$C_TYPE_UNION:
      column += fprintf(outfile,"{");
      break;
    case SDL$C_TYPE_ENTRY:
      column += fprintf(outfile,")()");
      break;
  };
  if (node->sdl_flag_bits.flag.m_dimen)
    column += fprintf(outfile," [%d]",node->hidim - node->lodim + 1);

  if (node->datatype == SDL$C_TYPE_CHARACTER) {
    if (node->typeinfo == 0)
      column += fprintf(outfile," []");
    else
      if (node->typeinfo > 1)
        column += fprintf(outfile," [%d]",node->typeinfo);
  };
}

check_module(node)
  struct Node *node;
{
  static char symbol_name[80];
  static struct dsc$descriptor module =
        {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
  static struct dsc$descriptor string = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
  struct ModuleName *mod;
  int found = 0, i = 0;

  if ((mod = SelectModules.next) == 0)
    return(1);

  module.dsc$w_length = node->name.len;
  module.dsc$a_pointer = node->name.str;
  /* this needs to loop through all the modules and see if one matches */
  while (mod && !found) {
    found = str$match_wild(&module,&(mod->name)) & 1;
    mod = mod->next;
  };
  return(found);
}

print_prototype(node)
  struct Node *node;
{
  int firstparam = 1, firstopt = 1;

  if (node->type == SDL$C_NODE_HEAD) {
    node = node->flink;
    while(readable(node) && (node->type != SDL$C_NODE_HEAD)) {
      if (check_if_args_optional(node)) {
        if (firstparam) {
          print_parameter(node,1);
          firstopt = 0;
        } else {
          if (firstopt) {
            fprintf(outfile,"%.*s...\n",options.indent,spaces);
            column = 1;
            firstopt = 0;
          };
          print_parameter(node,1);
        };
      }
      else
        print_parameter(node,0);
      node = node->flink;
      firstparam = 0;
    };
    if (!readable(node))
      printf("INTERNAL ERROR, FORWARD POINTER CORRUPT\n");
  }
  else
    printf("INTERNAL ERROR, NODE NOT A HEAD NODE\n");
};

check_if_args_optional(node)
  struct Node *node;
{ /* this function check if this node and all further parameter
     nodes are optional, if so, it returns a 1, if not, it returns
     a 0 */
  int optional = 1;

  while(readable(node) && (node->type != SDL$C_NODE_HEAD) && optional) {
    optional = node->sdl_flag_bits.flag.m_optional;
    node = node->flink;
  };
  if (!readable(node))
    printf("INTERNAL ERROR, FORWARD POINTER CORRUPT\n");
  return(optional);
}

print_parameter(node,commented)
  struct Node *node;
  int commented;
{
  setcase(node,-1);
  column += fprintf(outfile,"%.*s",options.indent,spaces);

  if (commented)
    column += fprintf(outfile,"/* ");

  if ((node->sdl_flag_bits.flag.m_in) && !(node->sdl_flag_bits.flag.m_out))
    column += fprintf(outfile,"const ");

  if ((node->sdl_flag_bits.flag.m_descriptor) ||
      (node->sdl_flag_bits.flag.m_rtl_str_desc)) {
    column += fprintf(outfile,"struct dsc$descriptor *");
    print_name(node);
  } else {
    print_predatatype(node);
    if (!(node->sdl_flag_bits.flag.m_value)) /* must be passed by ref. */
      column += fprintf(outfile," *");
    print_name(node);
    print_postdatatype(node);
  };

  if ((node->flink)->type != SDL$C_NODE_HEAD)
    column += fprintf(outfile,",");

  if (commented)
    column += fprintf(outfile," */");

  print_comment(node);
  newline();

}

setcase(node,casetype)
  struct Node *node;
  int casetype;
{
  int i;

  switch (options.outcase) {
    case 0:
      casetype = 0;
      break;
    case 1:
      break;
    case 2:
      casetype = 1;
      break;
    case 3:
      casetype = -1;
      break;
  };
  switch (casetype) {
    case 1: /* uppercase name */
      for (i=0; i<node->name.len; i++)
        node->name.str[i] = toupper(node->name.str[i]);
      break;
    case -1: /* lowercase name */
      for (i=0; i<node->name.len; i++)
        node->name.str[i] = tolower(node->name.str[i]);
      break;
  };
}

newline()
{
  fprintf(outfile,"\n");
  column = 1;
}
$EOD

