/*
 * Process the jswrap input files and generate output.
 * Copyright (c) 1998 New Generation Software (NGS) Oy
 *
 * Author: Markku Rossi <mtr@ngs.fi>
 */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 */

/*
 * $Source: /usr/local/cvsroot/ngs/js/jswrap/process.js,v $
 * $Id: process.js,v 1.9 1998/10/27 07:40:40 mtr Exp $
 */

/*
 * Constants and definitions.
 */

/* Tokens. */

tEOF 		= 1000;

tFUNCTION 	= 1001;
tIDENTIFIER 	= 1002;

tCSTRING 	= 2001;
tDOUBLE		= 2002;
tINT		= 2003;
tSTRING		= 2004;
tVOID		= 2005;

tIN		= 2010;
tOUT		= 2011;
tINOUT		= 2012;

tSTATIC		= 2020;

function is_type_token (token)
{
  return (token == tCSTRING || token == tDOUBLE || token == tINT
	  || token == tSTRING || token == tVOID);
}

function is_copy_type_token (token)
{
  return (token == tIN || token == tOUT || token == tINOUT);
}

function typename (token)
{
  if (token == tCSTRING)
    return "cstring";
  else if (token == tDOUBLE)
    return "double";
  else if (token == tINT)
    return "int";
  else if (token == tSTRING)
    return "string";
  else if (token == tVOID)
    return "void";
  else if (token == tIN)
    return "in";
  else if (token == tOUT)
    return "out";
  else if (token == tINOUT)
    return "inout";
  else
    return "";
}

function c_typename (token)
{
  if (token == tCSTRING)
    return "char *";
  else if (token == tDOUBLE)
    return "double ";
  else if (token == tINT)
    return "long ";
  else if (token == tVOID)
    return "void ";
  else if (token == tOUT || token == tINOUT)
    return "*";
  else
    return "";
}

function jsint_typename (token)
{
  if (token == tCSTRING)
    return "JS_STRING";
  else if (token == tDOUBLE)
    return "JS_FLOAT";
  else if (token == tINT)
    return "JS_INTEGER";
  else if (token == tSTRING)
    return "JS_STRING";
  else
    return "";
}

valid_c_identifier_re = new RegExp ("^[A-Za-z_][A-Za-z_0-9]*$");

end_brace_re = new RegExp ("^}[ \t]*$");

/*
 * Variables.
 */

/* The input file line number. */
linenum = 1;

token_linenum = 1;

token_value = null;

/*
 * Functions.
 */

function process ()
{
  if (false)
    System.print (program, ": processing file `", input_file,
		  "', header=`", header_file,
		  "', output=`", output_file,
		  "', reentrant=", opt_reentrant, "\n");

  linenum = 1;

  /* Open input file. */
  ifp = new File (input_file);
  if (!ifp.open ("r"))
    {
      System.error (program, ": couldn't open input file `", input_file,
		    "': ", System.strerror (System.errno), "\n");
      System.exit (1);
    }

  /* Create output files. */

  ofp_c = new File (output_file);
  if (!ofp_c.open ("w"))
    {
      System.error (program, ": couldn't create output file `", output_file,
		    "': ", System.strerror (System.errno), "\n");
      System.exit (1);
    }

  ofp_h = new File (header_file);
  if (!ofp_h.open ("w"))
    {
      ofp_c.close ();
      File.remove (output_file);

      System.error (program, ": couldn't create header file `", header_file,
		    "': ", System.strerror (System.errno), "\n");
      System.exit (1);
    }

  if (false)
    {
      ofp_js = new File (js_file);
      if (!ofp_js.open ("w"))
	{
	  ofp_c.close ();
	  ofp_h.close ();
	  File.remove (output_file);
	  File.remove (header_file);

	  System.error (program, ": couldn't create JS file `", js_file,
			"': ", System.strerror (System.errno), "\n");
	  System.exit (1);
	}
    }

  /* Parse the input. */
  parse ();

  /* Cleanup. */

  ofp_c.close ();
  ofp_h.close ();
}


/*
 * The Func class to hold function definitions.
 */

function Func ()
{
}

new Func ();

function Func$generate_js ()
{
  this.code = new String ("function " + this.name + " (");
  var i;
  for (i = 0; i < this.args.length; i++)
    {
      this.code.append (this.args[i].name);
      if (i + 1 < this.args.length)
	this.code.append (", ");
    }
  this.code.append (")\n{");
  this.code.append (this.body);
  this.code.append ("}\n");
}
Func.prototype.generate_js = Func$generate_js;

function Func$print_js (stream)
{
  stream.write (this.code);
}
Func.prototype.print_js = Func$print_js;

function Func$print_h (stream, header)
{
  stream.write ("\n");
  stream.write (c_typename (this.return_type) + this.name + " (");

  if (opt_reentrant)
    {
      /* The first argument is the interpreter handle. */
      stream.write ("\n\tJSInterpPtr interp");
      if (this.args.length > 0)
	stream.write (",");
    }

  var i;
  for (i = 0; i < this.args.length; i++)
    {
      stream.write ("\n\t");
      if (this.args[i].type == tSTRING)
	{
	  stream.write ("unsigned char *"
			+ c_typename (this.args[i].copy_type)
			+ this.args[i].name + ",\n\t"
			+ "unsigned int "
			+ c_typename (this.args[i].copy_type)
			+ this.args[i].name + "_len");
	}
      else
	{
	  stream.write (c_typename (this.args[i].type)
			+ c_typename (this.args[i].copy_type));
	  stream.write (this.args[i].name);
	}

      if (i + 1 < this.args.length)
	stream.write (", ");
    }
  stream.write ("\n\t)");

  if (header)
    stream.write (";");

  stream.write ("\n");
}
Func.prototype.print_h = Func$print_h;

function Func$print_c (stream)
{
  this.compile ();
  this.dump_bc (stream);

  this.print_h (stream, false);

  stream.write ("{\n");

  if (!opt_reentrant)
    stream.write ("  JSInterpPtr interp = jswrap_interp;\n");

  stream.write ("  JSVirtualMachine *vm = interp->vm;\n");

  stream.write ("  JSNode argv["
		+ (this.args.length + 1).toString ()
		+ "];\n");
  stream.write ("  int result;\n");

  if (this.return_type == tCSTRING)
    stream.write ("  char *cp;\n");

  stream.write ("\n");

  /* Argument count. */
  stream.write ("  argv[0].type = JS_INTEGER;\n");
  stream.write ("  argv[0].u.vinteger = "
		+ this.args.length.toString ()
		+ ";\n");

  /* Arguments. */

  /* Construct the argv array. */
  for (i = 0; i < this.args.length; i++)
    {
      var arg = this.args[i];
      var cspec = "";

      stream.write ("\n");

      var argnum = (i + 1).toString ();

      if (arg.copy_type == tOUT)
	{
	  stream.write ("  argv[" + argnum + "].type = JS_UNDEFINED;\n");
	}
      else
	{
	  if (arg.copy_type == tINOUT)
	    cspec = "*";

	  if (arg.type == tCSTRING)
	    {
	      stream.write ("  js_vm_make"
			    + (arg.staticp ? "_static" : "")
			    + "_string (vm, &argv["
			    + argnum + "], "
			    + cspec + arg.name + ", strlen ("
			    + cspec + arg.name + "));\n");
	    }
	  else if (arg.type == tDOUBLE)
	    {
	      stream.write ("  argv[" + argnum + "].type = JS_FLOAT;\n");
	      stream.write ("  argv[" + argnum + "].u.vfloat = "
			    + cspec + arg.name + ";\n");
	    }
	  else if (arg.type == tINT)
	    {
	      stream.write ("  argv[" + argnum + "].type = JS_INTEGER;\n");
	      stream.write ("  argv[" + argnum + "].u.vinteger = "
			    + cspec + arg.name + ";\n");
	    }
	  else if (arg.type == tSTRING)
	    {
	      stream.write ("  js_vm_make_static_string (vm, &argv["
			    + argnum + "], "
			    + cspec + arg.name + ", "
			    + cspec + arg.name + "_len);\n");
	    }
	  else
	    VM.stackTrace ();
	}
    }

  /* Call the function. */
  stream.write ("\

 retry:

  result = js_vm_apply (vm, \"" + this.name + "\", NULL, "
		+ (i + 1).toString () + ", argv);
  if (result == 0)
    {
      JSNode *n = &vm->globals[js_vm_intern (vm, \"" + this.name + "\")];

      if (n->type != JS_FUNC)
        {
          JSByteCode *bc = js_bc_read_data (" + this.name + "_bc,
                                            sizeof (" + this.name + "_bc));
          result = js_vm_execute (vm, bc);
          js_bc_free (bc);

          if (result == 0)
            jswrap_error (interp, \"initialization of function`"
		+ this.name + "' failed\");
          goto retry;
        }
      jswrap_error (interp, \"execution of function `"
		+ this.name + "' failed\");
    }
");

  /* Handle out and inout parameters. */
  for (i = 0; i < this.args.length; i++)
    {
      var arg = this.args[i];
      if (arg.copy_type == tIN)
	continue;

      var spos = (this.args.length - i).toString ();

      /* Check that we have there a correct type. */
      stream.write ("
  if ((vm->sp - " + spos + ")->type != " + jsint_typename (arg.type) + ")
    jswrap_error (interp,
                  \"wrong return type for argument `"
		    + arg.name + "' of function `" + this.name + "'\");
");

      /* Handle the different types. */
      if (arg.type == tCSTRING)
	{
	  stream.write ("\
  *" + arg.name + " = (char *) js_vm_alloc (vm, (vm->sp - "
			+ spos + ")->u.vstring->len + 1);
  memcpy (*" + arg.name + ", (vm->sp - " + spos + ")->u.vstring->data,
          (vm->sp - " + spos + ")->u.vstring->len);
  " + arg.name + "[(vm->sp - " + spos + ")->u.vstring->len] = '\\0';
");
	}
      else if (arg.type == tDOUBLE)
	{
	  stream.write ("\
  *" + arg.name + " = (vm->sp - " + spos + ")->u.vfloat;\n");
	}
      else if (arg.type == tINT)
	{
	  stream.write ("\
  *" + arg.name + " = (vm->sp - " + spos + ")->u.vinteger;\n");
	}
      else if (arg.type == tSTRING)
	{
	  stream.write ("\
  *" + arg.name + " = (vm->sp - " + spos + ")->u.vstring->data;
  *" + arg.name + "_len = (vm->sp - " + spos + ")->u.vstring->len;
");
	}
    }

  /* Handle the function return value. */
  if (this.return_type != tVOID)
    {
      /* Check that the code returned correct type. */
      stream.write ("
  if (vm->exec_result.type != " + jsint_typename (this.return_type) + ")
    jswrap_error (interp, \"return type mismatch in function `"
		    + this.name + "'\");

");

      /* Handle the different types. */
      if (this.return_type == tCSTRING)
	{
	  stream.write ("\
  cp = (char *) js_vm_alloc (vm, vm->exec_result.u.vstring->len + 1);
  memcpy (cp, vm->exec_result.u.vstring->data, vm->exec_result.u.vstring->len);
  cp[vm->exec_result.u.vstring->len] = '\\0';

  return cp;
");
	}
      else if (this.return_type == tDOUBLE)
	stream.write ("  return vm->exec_result.u.vfloat;\n");
      else if (this.return_type == tINT)
	stream.write ("  return vm->exec_result.u.vinteger;\n");
    }

  stream.write ("}\n");
}
Func.prototype.print_c = Func$print_c;

function Func$compile ()
{
  /* Create the byte-code for this function. */

  var flags = 0;

  if (false)
    flags |= JSC$FLAG_VERBOSE;

  if (opt_debug)
    flags |= JSC$FLAG_GENERATE_DEBUG_INFO;

  flags |= (JSC$FLAG_OPTIMIZE_PEEPHOLE
	    | JSC$FLAG_OPTIMIZE_JUMPS
	    | JSC$FLAG_OPTIMIZE_BC_SIZE);

  flags |= JSC$FLAG_WARN_MASK;

  try
    {
      this.bc = JSC$compile_string (this.code, flags, null, null);
    }
  catch (error)
    {
      System.error (error, "\n");
      System.exit (1);
    }
}
Func.prototype.compile = Func$compile;

function Func$dump_bc (stream)
{
  stream.write ("\nstatic unsigned char " + this.name + "_bc[] = {");

  var i;
  for (i = 0; i < this.bc.length; i++)
    {
      if ((i % 12) == 0)
	stream.write ("\n ");

      var item = this.bc[i].toString (16);
      if (item.length == 1)
	item = "0" + item;

      stream.write (" 0x" + item + ",");
    }

  stream.write ("\n};\n");
}
Func.prototype.dump_bc = Func$dump_bc;

/*
 * The Argument class to hold function argument definitions.
 */

function Argument ()
{
  this.type = false;
  this.copy_type = tIN;
  this.staticp = false;
}

new Argument ();

function Argument$print ()
{
  System.print (typename (this.copy_type), " ", typename (this.type),
		" ", this.name);
}
Argument.prototype.print = Argument$print;



/*
 * The .jsw file parsing.
 */

function parse ()
{
  var token;
  var func;

  headers ();

  while ((token = get_token ()) != tEOF)
    {
      if (token != tFUNCTION)
	syntax_error ();

      func = new Func ();

      /* Possible return type. */
      token = get_token ();
      if (is_type_token (token))
	{
	  if (token == tSTRING)
	    {
	      System.error (input_file, ":", linenum,
			    ": the function return value can't be `string'\n");
	      System.exit (1);
	    }

	  func.return_type = token;

	  token = get_token ();
	}
      else
	func.return_type = tVOID;

      /* The name of the function. */
      if (token != tIDENTIFIER)
	syntax_error ();

      if (!valid_c_identifier_re.test (token_value))
	{
	  System.error (input_file, ":", linenum,
			": function name is not a valid C identifier `",
			token_value, "'\n");
	  System.exit (1);
	}

      func.name = token_value;

      /* Arguments. */
      token = get_token ();
      if (token != #'(')
	syntax_error ();

      var args = new Array ();

      token = get_token ();
      while (token != #')')
	{
	  var arg = new Argument ();

	  while (token != tIDENTIFIER)
	    {
	      if (token == tEOF)
		syntax_error ();

	      if (is_type_token (token))
		arg.type = token;
	      else if (is_copy_type_token (token))
		arg.copy_type = token;
	      else if (token == tSTATIC)
		arg.staticp = true;
	      else
		syntax_error ();

	      token = get_token ();
	    }

	  if (!valid_c_identifier_re.test (token_value))
	    {
	      System.error (input_file, ":", linenum,
			    ": argument name is not a valid C identifier `",
			    token_value, "'\n");
	      System.exit (1);
	    }
	  arg.name = token_value;

	  /* Check some validity conditions. */
	  if (!arg.type)
	    {
	      System.error (input_file, ":", linenum,
			    ": no type specified for argument `",
			    arg.name, "'\n");
	      System.exit (1);
	    }
	  if (arg.staticp)
	    {
	      if (arg.type != tCSTRING && arg.type != tSTRING)
		{
		  System.error (input_file, ":", linenum,
				": type `static' can only be used with `cstring' and `string' arguments\n");
		  System.exit (1);
		}
	      if (arg.copy_type == tOUT)
		System.error (input_file, ":", linenum,
			      ": warning: type `static' is meaningful only with `in' and `inout' arguments\n");
	    }

	  args.push (arg);

	  token = get_token ();
	  if (token == #',')
	    token = get_token ();
	}

      func.args = args;

      /* The opening '{' of the function body. */
      token = get_token ();
      if (token != #'{')
	syntax_error ();

      /* Get the function body. */
      var code = new String ("");
      while (true)
	{
	  var line = ifp.readln ();
	  if (!line)
	    syntax_error ();
	  linenum++;

	  if (end_brace_re.test (line))
	    break;

	  code.append (line + "\n");
	}

      func.body = code;
      func.generate_js ();

      // func.print_js (ofp_js);
      func.print_h (ofp_h, true);
      func.print_c (ofp_c);
    }

  trailers ();
}

function get_token ()
{
  var ch;

  while ((ch = ifp.readByte ()) != -1)
    {
      if (ch == #' ' || ch == #'\t' || ch == #'\v' || ch == #'\r'
	  || ch == #'\f')
	continue;

      if (ch == #'\n')
	{
	  linenum++;
	  continue;
	}

      token_linenum = linenum;

      if (ch == #'/' && peek_char () == #'*')
	{
	  /* Multi line comment. */
	  ifp.readByte ();
	  while ((ch = ifp.readByte ()) != -1
		 && (ch != #'*' || peek_char () != #'/'))
	    if (ch == #'\n')
	      linenum++;

	  /* Consume the peeked #'/' character. */
	  ifp.readByte ();
	}

      /* Identifiers and keywords. */
      else if (JSC$lexer_is_identifier_letter (ch))
	{
	  /* An identifier. */
	  var id = String.fromCharCode (ch);

	  while ((ch = ifp.readByte ()) != -1
		 && (JSC$lexer_is_identifier_letter (ch)
		     || JSC$lexer_is_decimal_digit (ch)))
	    id.append (File.byteToString (ch));
	  ifp.ungetByte (ch);

	  /* Keywords. */
	  if (id == "function")
	    return tFUNCTION;

	  /* Types. */
	  else if (id == "cstring")
	    return tCSTRING;
	  else if (id == "double")
	    return tDOUBLE;
	  else if (id == "int")
	    return tINT;
	  else if (id == "string")
	    return tSTRING;
	  else if (id == "void")
	    return tVOID;
	  else if (id == "in")
	    return tIN;
	  else if (id == "out")
	    return tOUT;
	  else if (id == "inout")
	    return tINOUT;
	  else if (id == "static")
	    return tSTATIC;

	  else
	    {
	      /* It really is an identifier. */
	      token_value = id;
	      return tIDENTIFIER;
	    }
	}

      /* Just return the character as-is. */
      else
	return ch;
    }

  /* EOF reached. */
  return tEOF;
}

function peek_char ()
{
  var ch = ifp.readByte ();
  ifp.ungetByte (ch);

  return ch;
}

function syntax_error ()
{
  System.error (input_file, ":", linenum, ": syntax error\n");
  System.exit (1);
}

function headers ()
{
  var stream;

  /* The header file. */

  stream = ofp_h;
  header_banner (stream);

  var ppname = path_to_ppname (header_file);
  stream.write ("\n#ifndef " + ppname
		+ "\n#define " + ppname + "\n");

  /* The C file. */
  stream = ofp_c;
  header_banner (stream);
  stream.write ("\n#include <jsint.h>\n");

  if (!opt_reentrant)
    {
      stream.write ("
/*
 * This global interpreter handle can be removed with " + program + "'s
 * option -r, --reentrant.
 */
");
      stream.write ("extern JSInterpPtr jswrap_interp;\n");
    }

  if (opt_no_error_handler)
    {
      stream.write ("
/* Prototype for the error handler of the JS runtime errors. */
");
      stream.write ("void jswrap_error (JSInterpPtr interp, char *error);\n");
    }
  else
    {
      /* Define the default jswrap_error() function. */
      stream.write ("
/*
 * This is the default error handler for the JS runtime errors.  The default
 * handler can be removed with " + program + "'s option -n, --no-error-handler.
 * In this case, your code must define the handler function.
 */
");
      stream.write ("\
static void
jswrap_error (JSInterpPtr interp, char *error)
{
  const char *cp;

  fprintf (stderr, \"JS runtime error: %s\", error);

  cp = js_error_message (interp);
  if (cp[0])
    fprintf (stderr, \": %s\", cp);
  fprintf (stderr, \"\\n\");

  exit (1);
}
");
    }

  stream.write ("

/*
 * The global function definitions.
 */
");
}

function header_banner (stream)
{
  stream.write ("/* This file is automatically generated from `"
		    + input_file + "' by " + program + ". */\n");
}

path_to_ppname_re = new RegExp ("[^A-Za-z_0-9]", "g");

function path_to_ppname (path)
{
  var str = path.toUpperCase ().replace (path_to_ppname_re, "_");
  if (#'0' <= str[0] && str[0] <= #'9')
    str = "_" + str;

  return str;
}

function trailers ()
{
  /* The header file. */
  var stream = ofp_h;
  stream.write ("\n#endif /* not " + path_to_ppname (header_file) + " */\n");
}


/*
Local variables:
mode: c
End:
*/
/*
 * JS C wrapper.
 * Copyright (c) 1998 New Generation Software (NGS) Oy
 *
 * Author: Markku Rossi <mtr@ngs.fi>
 */

/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 */

/*
 * $Source: /usr/local/cvsroot/ngs/js/jswrap/main.js,v $
 * $Id: main.js,v 1.2 1998/10/27 07:40:40 mtr Exp $
 */

/*
 * Variables and definitions.
 */

version_number = "0.0.1";

/*
 * Options.
 */

/*
 * -g, --debug
 *
 * Generate debugging information to the generated JS byte-code.
 */

opt_debug = false;

/*
 * -h FILE, --header FILE
 *
 * Generate the C header to file FILE.
 */

header_file = null;

/*
 * -n, --no-error-handler
 *
 * Do not create the default error handler to the C files.
 */
opt_no_error_handler = false;

/*
 * -o FILE, --output FILE
 *
 * Generate the C output to file FILE.
 */

output_file = null;

/*
 * -r, --reentrant
 *
 * Generate re-entrant C stubs.
 */

opt_reentrant = false;

/*
 * -V, --version
 *
 * Print version information and exit successfully.
 */

/*
 * --help
 *
 * Print short help and exit successfully.
 */


/*
 * Functions.
 */

function main ()
{
  var idx = ARGS[0].lastIndexOf ("/");
  if (idx >= 0)
    program = ARGS[0].substr (idx + 1);
  else
    program = ARGS[0];

  /* Handle arguments. */
  var i;
  for (i = 1; i < ARGS.length; i++)
    {
      if (ARGS[i][0] == #'-')
	{
	  if (ARGS[i] == "-g" || ARGS[i] == "--debug")
	    opt_debug = true;
	  else if (ARGS[i] == "-h" || ARGS[i] == "--header")
	    {
	      if (i + 1 >= ARGS.length)
		{
		  System.error (program,
				": no argument for option --header\n");
		  System.exit (1);
		}

	      header_file = ARGS[++i];
	    }
	  else if (ARGS[i] == "-n" || ARGS[i] == "--no-error-handler")
	    opt_no_error_handler = true;
	  else if (ARGS[i] == "-o" || ARGS[i] == "--output")
	    {
	      if (i + 1 >= ARGS.length)
		{
		  System.error (program,
				": no argument for option --output\n");
		  System.exit (1);
		}

	      output_file = ARGS[++i];
	    }
	  else if (ARGS[i] == "-r" || ARGS[i] == "--reentrant")
	    opt_reentrant = true;
	  else if (ARGS[i] == "-V" || ARGS[i] == "--version")
	    {
	      version ();
	      System.exit (0);
	    }
	  else if (ARGS[i] == "--help")
	    {
	      usage ();
	      System.exit (0);
	    }
	  else
	    {
	      /* Unrecognized option. */
	      System.error (program, ": unrecognized option `",
			    ARGS[i], "'\n");
	      System.error ("Try `", program,
			    " --help' for more information.\n");
	      System.exit (1);
	    }
	}
      else
	{
	  /* End of arguments. */
	  break;
	}
    }

  if (i >= ARGS.length)
    {
      System.error  (program, ": no input file specified\n");
      System.exit (1);
    }
  if (i + 1 < ARGS.length)
    {
      System.error (program, ": extraneous arguments after input file\n");
      System.exit (1);
    }

  input_file = ARGS[i];

  /* Set the defaults. */

  var re = new RegExp ("^(.*)\\.jsw$");
  if (!header_file)
    {
      if (re.test (input_file))
	header_file = RegExp.$1 + ".h";
      else
	header_file = input_file + ".h";
    }
  if (!output_file)
    {
      if (re.test (input_file))
	output_file = RegExp.$1 + ".c";
      else
	output_file = input_file + ".c";
    }
  if (false)
    {
      if (re.test (input_file))
	js_file = RegExp.$1 + ".js";
      else
	js_file = input_file + ".js";
    }

  process ();
}


function usage ()
{
  System.print ("\
Usage: ", program, " [OPTION]... FILE\n\
Mandatory arguments to long options are mandatory for short options too.\n");

  System.print ("\
  -g, --debug                generate debugging information to the generated\n\
                             JS byte-code\n\
  -h, --header FILE          generate the C header to file FILE\n\
  -n, --no-error-handler     do not generate the default error handler\n\
  -o, --output FILE          generate the C output to file FILE\n\
  -r, --reentrant            generate re-entrant C stubs\n\
  -V, --version              print version number\n\
  --help                     print this help and exit\n\
");

  System.print ("\nReport bugs to mtr@ngs.fi.\n");
}


function version ()
{
  System.print ("NGS JavaScript C wrapper generator ", version_number, "\n");
  System.print ("\
Copyright (C) 1998 New Generation Software (NGS) Oy.\n\
NGS JavaScript Interpreter comes with NO WARRANTY, to the extent\n\
permitted by law.  You may redistribute copies of NGS JavaScript\n\
Interpreter under the terms of the GNU Library General Public License.\n\
For more information about these matters, see the files named COPYING.\n\
");
}


main ();


/*
Local variables:
mode: c
End:
*/


syntax highlighted by Code2HTML, v. 0.9.1