[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
[0361]
[0362]
[0363]
[0364]
[0365]
[0366]
[0367]
[0368]
[0369]
[0370]
[0371]
[0372]
[0373]
[0374]
[0375]
[0376]
[0377]
[0378]
[0379]
[0380]
[0381]
[0382]
[0383]
[0384]
[0385]
[0386]
[0387]
[0388]
[0389]
[0390]
[0391]
[0392]
[0393]
[0394]
[0395]
[0396]
[0397]
[0398]
[0399]
[0400]
[0401]
[0402]
[0403]
[0404]
[0405]
[0406]
[0407]
[0408]
[0409]
[0410]
[0411]
[0412]
[0413]
[0414]
[0415]
[0416]
[0417]
[0418]
[0419]
[0420]
[0421]
[0422]
[0423]
[0424]
[0425]
[0426]
[0427]
[0428]
[0429]
[0430]
[0431]
[0432]
[0433]
[0434]
[0435]
[0436]
[0437]
[0438]
[0439]
[0440]
[0441]
[0442]
[0443]
[0444]
[0445]
[0446]
[0447]
[0448]
[0449]
[0450]
[0451]
[0452]
[0453]
[0454]
[0455]
[0456]
[0457]
[0458]
[0459]
[0460]
[0461]
[0462]
[0463]
[0464]
[0465]
[0466]
[0467]
[0468]
[0469]
[0470]
[0471]
[0472]
[0473]
[0474]
[0475]
[0476]
[0477]
[0478]
[0479]
[0480]
[0481]
[0482]
[0483]
[0484]
[0485]
[0486]
[0487]
[0488]
[0489]
[0490]
[0491]
[0492]
[0493]
[0494]
[0495]
[0496]
[0497]
[0498]
[0499]
[0500]
[0501]
[0502]
[0503]
[0504]
[0505]
[0506]
[0507]
[0508]
[0509]
[0510]
[0511]
[0512]
[0513]
[0514]
[0515]
[0516]
[0517]
[0518]
[0519]
[0520]
[0521]
[0522]
[0523]
[0524]
[0525]
[0526]
[0527]
[0528]
[0529]
[0530]
[0531]
[0532]
[0533]
[0534]
[0535]
[0536]
[0537]
[0538]
[0539]
[0540]
[0541]
[0542]
[0543]
[0544]
[0545]
[0546]
[0547]
[0548]
[0549]
[0550]
[0551]
[0552]
[0553]
[0554]
[0555]
[0556]
[0557]
[0558]
[0559]
[0560]
[0561]
[0562]
[0563]
[0564]
[0565]
[0566]
[0567]
[0568]
[0569]
[0570]
[0571]
[0572]
[0573]
[0574]
[0575]
[0576]
[0577]
[0578]
[0579]
[0580]
[0581]
[0582]
[0583]
[0584]
[0585]
[0586]
[0587]
[0588]
[0589]
[0590]
[0591]
[0592]
[0593]
[0594]
[0595]
[0596]
[0597]
[0598]
[0599]
[0600]
[0601]
[0602]
[0603]
[0604]
[0605]
[0606]
[0607]
[0608]
[0609]
[0610]
[0611]
[0612]
[0613]
[0614]
[0615]
[0616]
[0617]
[0618]
[0619]
[0620]
[0621]
[0622]
[0623]
[0624]
[0625]
[0626]
[0627]
[0628]
[0629]
[0630]
[0631]
[0632]
[0633]
[0634]
[0635]
[0636]
[0637]
[0638]
[0639]
[0640]
[0641]
[0642]
[0643]
[0644]
[0645]
[0646]
[0647]
[0648]
[0649]
[0650]
[0651]
[0652]
[0653]
[0654]
[0655]
[0656]
[0657]
[0658]
[0659]
[0660]
[0661]
[0662]
[0663]
[0664]
[0665]
[0666]
[0667]
[0668]
[0669]
[0670]
[0671]
[0672]
[0673]
[0674]
[0675]
[0676]
[0677]
[0678]
[0679]
[0680]
[0681]
[0682]
[0683]
[0684]
[0685]
[0686]
[0687]
[0688]
[0689]
[0690]
[0691]
[0692]
[0693]
[0694]
[0695]
[0696]
[0697]
[0698]
[0699]
[0700]
[0701]
[0702]
[0703]
[0704]
[0705]
[0706]
[0707]
[0708]
[0709]
[0710]
[0711]
[0712]
[0713]
[0714]
[0715]
[0716]
[0717]
[0718]
[0719]
[0720]
[0721]
[0722]
[0723]
[0724]
[0725]
[0726]
[0727]
[0728]
[0729]
[0730]
[0731]
[0732]
[0733]
[0734]
[0735]
[0736]
[0737]
[0738]
[0739]
[0740]
[0741]
[0742]
[0743]
[0744]
[0745]
[0746]
[0747]
[0748]
[0749]
[0750]
[0751]
[0752]
[0753]
[0754]
[0755]
[0756]
[0757]
[0758]
[0759]
[0760]
[0761]
[0762]
[0763]
[0764]
[0765]
[0766]
[0767]
[0768]
[0769]
[0770]
[0771]
[0772]
[0773]
[0774]
[0775]
[0776]
[0777]
[0778]
[0779]
[0780]
[0781]
[0782]
[0783]
[0784]
[0785]
[0786]
[0787]
[0788]
[0789]
[0790]
[0791]
[0792]
[0793]
[0794]
[0795]
[0796]
[0797]
[0798]
[0799]
[0800]
[0801]
[0802]
[0803]
[0804]
[0805]
[0806]
[0807]
[0808]
[0809]
[0810]
[0811]
[0812]
[0813]
[0814]
[0815]
[0816]
[0817]
[0818]
[0819]
[0820]
[0821]
[0822]
[0823]
[0824]
[0825]
[0826]
[0827]
[0828]
[0829]
[0830]
[0831]
[0832]
[0833]
[0834]
[0835]
[0836]
[0837]
[0838]
[0839]
[0840]
[0841]
[0842]
[0843]
[0844]
[0845]
[0846]
[0847]
[0848]
[0849]
[0850]
[0851]
[0852]
[0853]
[0854]
[0855]
[0856]
[0857]
[0858]
[0859]
[0860]
[0861]
[0862]
[0863]
[0864]
[0865]
[0866]
[0867]
[0868]
[0869]
[0870]
[0871]
[0872]
[0873]
[0874]
[0875]
[0876]
[0877]
[0878]
[0879]
[0880]
[0881]
[0882]
[0883]
[0884]
[0885]
[0886]
[0887]
[0888]
[0889]
[0890]
[0891]
[0892]
[0893]
[0894]
[0895]
[0896]
[0897]
[0898]
[0899]
[0900]
[0901]
[0902]
[0903]
[0904]
[0905]
[0906]
[0907]
[0908]
[0909]
[0910]
[0911]
[0912]
[0913]
[0914]
[0915]
[0916]
[0917]
[0918]
[0919]
[0920]
[0921]
[0922]
[0923]
[0924]
[0925]
[0926]
[0927]
[0928]
[0929]
[0930]
[0931]
[0932]
[0933]
[0934]
[0935]
[0936]
[0937]
[0938]
[0939]
[0940]
[0941]
[0942]
[0943]
[0944]
[0945]
[0946]
[0947]
[0948]
[0949]
[0950]
[0951]
[0952]
[0953]
[0954]
[0955]
[0956]
[0957]
[0958]
[0959]
[0960]
/* PROGRAM (for OSU DECthreads httpd)				Set_DCL_Env.c
**		CGI SCRIPT TO SET SYMBOLS FOR DCL ENVIRONMENT.
**
** USAGE:
**	$ set noon
**	$ say = "write net_link"
**	$ crlf = f$fao("!/")
**	$ say "<DNETRECMODE>"	! Set implied carriage control (optional)
**	$ mcr 'f$parse("SET_DCL_ENV.EXE;",f$environment("PROCEDURE"))
**	$ [...]
**   Can pass a base symbol prefix as an argument (default is "WWW_").
**   Can pass a form symbol prefix as a second argument to invoke use
**     of CGI-SYMBOLS-like symbol names (default is the CERN WWW_KEY_foo
**     scheme).
**
**   Set the Content-Type in the DCL script, e.g.:
**	$ say "Content-Type: text/html", crlf	 ! CGI header (two crlf's if
**	$ [...]					   <DNETRECMODE> is not set)
**
**   or via a printf("Content-Type: text/html\n\n") in an executable, e.g.:)
**	$ define sys$output net_link
**	$ WWWquery "''database'" "''query'"
**	$ deassign sys$output
**	$ [...]
**
**   Once this program is run by the initial htbin script, any sequence
**	of executables or other DCL scripts can be called with sys$output
**	assigned to net_link so that their outputs will be sent to the
**	client, and they will all have direct access to the full CGI symbol
**	environment via DCL symbols (accessible via getenv() calls in C
**	programs).
**
**
** AUTHORS:
**	FM	Foteos Macrides		macrides@sci.wfbr.edu
**
** HISTORY:
**	12 Oct 94  FM	Written for use with the OSU DECthreads httpd.
**			(modification of Dave's CGI_SYMBOLS.C for v1.6
**			and my QueryVMS.c).  In addition to setting the
**			base CGI symbols via cgi_set_dcl_env(), it casts
**			HTTP_ACCEPT into a numbered list and count symbol
**			set, coverts POST or GET Form contents into an
**			unescaped, numbered KEY (odd is name, even is
**			value) and count symbol set, or an ISINDEX query
**			into an unescaped, numbered KEY and count symbol
**			set, all as in the DCL symbol support for the
**			CERN httpd.  Note that all symbols are limited
**			to 255 characters for DCL, and strings will be
**			clipped to that limit if longer.  This code does
**			not symbolize POST contents other than from Forms.
**			If a POST Form submission also has a "?<query>" in
**			the RequestURL (rare, but could occur), the KEY
**			symbol pairs for the Form content precede those for
**			the query.
**			This code also fills an "entries" structure with the
**			name/value pairs from Forms (like that in QueryVMS.c)
**			so you can easily add functions to do something useful
**			beyond setting the DCL symbols (to supplement whatever
**			you're doing via the DCL command file).  As you add
**		        such functions, you can include getenv() checks for
**			symbols set by the DCL command file to regulate their
**			implementation. (use the "Check whether we want equal
**			signs appended to names." code as a model).
**			The WWW_PATH_TRANSLATED symbol is not set to "" by
**			cgi_set_dcl_env() if WWW_PATH_INFO is "".  This
**			script does set it to "", you won't get a DCL error
**			if you try to use WWW_PATH_TRANSLATED without first
**			checking if WWW_PATH_INFO .nes. "". 
**
**			Differences from the CERN httpd symbol set:
**			===========================================
**			  1) The "WWW_" base and CERN-style form-content
**			     symbol prefixes can be replaced via a first
**			     argument for Set_DCL_Env.exe.  Any symbols
**			     set by the calling script for regulating
**			     Set_DCL_Env.exe should use the alternate
**			     prefix as well (we'll assume it's "WWW_" in
**			     the following comments).
**			  2) By default, the '=' is not retained on the ends
**			     of the WWW_KEY_<odd_number> symbols for Form
**			     content names. (The count is pointed to by
**			     WWW_KEY_COUNT, equivalently to the CERN httpd.)
**			     You don't need the equal sign to know that it's
**			     the name, and it was a pain to deal with when
**			     formatting text within the script for output
**			     to the client.  The symbol WWW_APPEND_EQUAL_SIGN
**			     can be made non-NULL by the calling script if you
**			     do want the equal sign appended.
**			  3) WWW_HTTP_ACCEPT points to the full, comma
**			     separated list of accepted MIME types, not to
**			     the count of WWW_HTTP_ACCEPT_<number> symbols
**			     as does the CERN httpd.  The count is pointed to
**			     instead by WWW_HTTP_ACCEPT_COUNT.  The comma
**			     separated list is likely to be clipped at 255
**			     characters (so you'd be unwise to parse it rather
**			     than checking the numbered list via a DCL loop,
**			     but cgi_set_dcl_env() sets WWW_HTTP_ACCEPT to
**			     that list, and so I left it that way.  You can
**			     also search the accepted MIME types by using
**			     <DNETHDR>, but that's more work and overhead
**			     than looping through this numbered list.
**			  4) I didn't include WWW_REFERER_URL, because you
**			     can get it as WWW_HTTP_REFERER.
**			  5) The WWW_HTTP_ACCEPT_LANGUAGE symbol is a comma
**			     separated list, as for the CERN server, but is
**			     cast to a WWW_HTTP_ACCEPT_LANGUAGE_COUNT and
**			     WWW_HTTP_ACCEPT_LANGUAGE_<num> symbol set as
**			     well.
**
**	12 Mar 95  FM	Added multi-line TEXTAREA handling, identical to
**			     that for the CERN httpd.
**
**	13 Mar 95  FM   Added option to process POST or GET Form content
**			     equivalently to the v1.7a CGI_SYMBOLS.c, if
**			     Set_DCL_Env.exe is invoked with a second
**			     (Form prefix) argument.  The first argument
**			     must be the base prefix (normally "WWW_").
**			     See comments in do_cgi_form_env() concerning
**			     the limitations of this symbolizing scheme,
**			     but it's easier to use with simple forms.
**			     In addition to CGI_SYMBOL.c's foo_FLD_name
**			     symbols and foo_FIELDS list, this version
**			     includes foo_FLD_COUNT and foo_FIELDS_COUNT
**			     symbols (for error checking).
**
**	18 Mar 95  FM	Added check for WWW_APPEND_EQUAL_SIGN (replace the
**			 "WWW_" with the alternate symbol prefix, if one
**			 has been passed as an argument). 
**
**	22 Apr 95  FM	Added WWW_HTTP_ACCEPT_LANGUAGE symbol and a
**			 WWW_HTTP_ACCEPT_LANGUAGE_COUNT and itemized
**			 WWW_HTTP_ACCEPT_LANGUAGE_<num> symbol set.
**
**	23 Apr 95  FM	Added WWW_AUTH_TYPE handling (is set to the
**			 authentication type, e.g., "Basic", or to "" if
**			 the script was not invoked with authentication.
**			Added code to set the WWW_PATH_TRANSLATED symbol
**			 to "" if no translation is present.
**
**	28 Apr 95  FM	Added code to set WWW_REMOTE_IDENT and
**			 WWW_REMOTE_USER to "" if no translation
**			 is present.
**
**	20 May 95  FM	Treat CRLF, lone LF or lone CR as 'newline' (LF)
**			 when unescaping.
**
**	14 Jan 96  FM	Modified do_cgi_form_env() emulation of CGI_Symbols.c
**			 to create a comma-separated list of VALUEs for fields
**			 which have the same NAME (as in SELECTs with the
**			 MULTIPLE attribute set).
** BUGS:
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <unixlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <descrip.h>
#include <libclidef.h>
#include <string.h>
#include "cgilib.h"
#include "scriptlib.h"

#define MAX_ENTRIES 1000	/* Maximum name/value pairs to handle       */
#define MAX_PREFIX_LEN 100	/* Maximum prefix length (default is "WWW_" */

typedef struct {    		/* Structure for holding name/value pairs   */
    char *name;
    char *val;
} entry;

static entry entries[MAX_ENTRIES];
static char  prefix[256];
static int   prefix_len=0;
static char  Fprefix[256];
static int   Fprefix_len=0;
static char  AcceptCount[20];
static char  KeyCount[20];

static void getword(char *word, char *line, char stop);
static char *makeword(char *line, char stop);
static char *fmakeword(FILE *f, char stop, int *len);
static char x2c(char *what);
static void unescape_url(char *url);
static void plustospace(char *str);
static int strcasecomp(char *a, char *b);
static int strncasecomp(char *a, char *b, int);
static void do_dcl_form_env(int m);
static void do_cgi_form_env(int m);

int main(int argc, char *argv[])
{
    register int x, m=0, line;
    char *cp, *cp1, *METHOD, *ACCEPT;
    int status, cl, len;
    unsigned char append_equal_sign=0;
    FILE *contentf;
    int i, LIB$GET_SYMBOL(), LIB$SET_SYMBOL(), length, virtual_argc;
    int table = LIB$K_CLI_LOCAL_SYM;
    int count=0;
    char *virtual_argv[4];
    char param_name[4], param_value[256], symname[256], symvalue[256];
    $DESCRIPTOR(pname,"");
    $DESCRIPTOR(pvalue,"");
    $DESCRIPTOR(symbol,"");
    $DESCRIPTOR(value,"");
    symbol.dsc$a_pointer = symname;
    /*
     * Check for invalid invocation
     */
    if ( argc > 3 ) {
	printf(
	   "Too many arguments, this program must be run from a DCL script\n");
	exit (20);
    }
    /*
     * Build dummy argument list from P1 through P3 to get the values WWWEXEC 
     * passed to the script.
     */
    virtual_argc = 4;
    virtual_argv[0] = argv[0];		/* for lack of anything better! */
    pname.dsc$w_length = 2;
    pname.dsc$a_pointer = param_name;
    pvalue.dsc$w_length = sizeof(param_value)-1;
    pvalue.dsc$a_pointer = param_value;

    for ( i = 1; i < virtual_argc; i++ ) {
	sprintf ( param_name, "P%d", i );
	length = 0;
	status = LIB$GET_SYMBOL ( &pname, &pvalue, &length );
	if ( (status&1) == 1 ) {
	    /*
	     * Allocate new buffer to hold value.
	     */
	    virtual_argv[i] = malloc ( length+1 );
	    param_value[length] = '\0';
	    strcpy ( virtual_argv[i], param_value );
	}
	else virtual_argv[i] = "";
    }

    /*
     * Load the base CGI environment for conversion to DCL symbols.
     */
    status = cgi_init ( virtual_argc, virtual_argv );
    if ( (status&1) == 0 )
        return status;

    /*
     * Get the CGI symbol prefix and set the basic symbols.
     */
    strncpy( prefix, ((argc > 1) ? argv[1] : "WWW_"), MAX_PREFIX_LEN );
    prefix[MAX_PREFIX_LEN] = '\0';
    prefix_len = strlen ( prefix );
    cgi_set_dcl_env ( prefix );

    /*
     * Check if CGI_SYMBOLS-like parsing of form input is wanted.
     */
    strncpy( Fprefix, ((argc > 2) ? argv[2] : ""), MAX_PREFIX_LEN);
    Fprefix[MAX_PREFIX_LEN] = '\0';
    Fprefix_len = strlen ( Fprefix );

    /*
     * Recast HTTP_ACCEPT to a numbered symbol list.
     */
    if ( (ACCEPT=cgi_info("HTTP_ACCEPT")) != NULL && *ACCEPT != '\0' ) {
        count = 0;
	while ( (cp=strchr(ACCEPT, ',')) != NULL ) {
	    *(cp++) = '\0';
	    while ( isspace(*ACCEPT) )
	        ACCEPT++;
	    sprintf( symname, "%sHTTP_ACCEPT_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = ACCEPT;
	    value.dsc$w_length = strlen( ACCEPT );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	    ACCEPT = cp;
	}
	if (*ACCEPT != '\0') {
	    while ( isspace(*ACCEPT) )
	        ACCEPT++;
	    sprintf( symname, "%sHTTP_ACCEPT_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = ACCEPT;
	    value.dsc$w_length = strlen( ACCEPT );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	}
    }

    /*
     * Set the ACCEPT count.
     */
    sprintf( symname, "%sHTTP_ACCEPT_COUNT", prefix );
    symbol.dsc$w_length = strlen( symname );
    sprintf( AcceptCount, "%d", count );
    value.dsc$a_pointer = AcceptCount;
    value.dsc$w_length = strlen ( AcceptCount );
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );
    count = 0;

    /*
     * Recast HTTP_ACCEPT_LANGUAGE to a numbered symbol list.
     */
    if ( (ACCEPT=cgi_info("HTTP_ACCEPT_LANGUAGE")) != NULL &&
    	 *ACCEPT != '\0' ) {
        count = 0;
	while ( (cp=strchr(ACCEPT, ',')) != NULL ) {
	    *(cp++) = '\0';
	    while ( isspace(*ACCEPT) )
	        ACCEPT++;
	    sprintf( symname, "%sHTTP_ACCEPT_LANGUAGE_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = ACCEPT;
	    value.dsc$w_length = strlen( ACCEPT );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	    ACCEPT = cp;
	}
	if (*ACCEPT != '\0') {
	    while ( isspace(*ACCEPT) )
	        ACCEPT++;
	    sprintf( symname, "%sHTTP_ACCEPT_LANGUAGE_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = ACCEPT;
	    value.dsc$w_length = strlen( ACCEPT );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	}
    }

    /*
     * Set the ACCEPT_LANGUAGE count.
     */
    sprintf( symname, "%sHTTP_ACCEPT_LANGUAGE_COUNT", prefix );
    symbol.dsc$w_length = strlen( symname );
    sprintf( AcceptCount, "%d", count );
    value.dsc$a_pointer = AcceptCount;
    value.dsc$w_length = strlen ( AcceptCount );
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );
    count = 0;

    /*
     * Pick up CGI symbols which the cgilib/scriptlib
     * doesn't presently handle properly.
     */
    sprintf( symname, "%sAUTH_TYPE", prefix );
    if ( getenv( symname ) == NULL ) {
        sprintf( symname, "%sHTTP_AUTHORIZATION", prefix );
        if ( ( cp = getenv( symname ) ) != NULL ) {
            if ( ( cp1 = strchr( cp, ' ' ) ) != NULL )
	        *cp1 = '\0';
	    if ( strlen( cp ) > 255 )
	        cp[255] = '\0';
        }
	else
            cp = "";
	sprintf( symname, "%sAUTH_TYPE", prefix );
	symbol.dsc$w_length = strlen( symname );
	sprintf( symvalue, "%s", cp );
	value.dsc$a_pointer = symvalue;
	value.dsc$w_length = strlen ( symvalue );
	status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	if ( (status&1) == 0 ) fprintf(stderr,
	    "Error defining %s symbol.  status: %d\n", symname, status );
    }
    sprintf( symname, "%sPATH_TRANSLATED", prefix );
    if ( getenv( symname ) == NULL ) {
        symbol.dsc$w_length = strlen( symname );
	symvalue[0] = '\0';
	value.dsc$a_pointer = symvalue;
	value.dsc$w_length = 0;
	status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	if ( (status&1) == 0 ) fprintf(stderr,
	    "Error defining %s symbol.  status: %d\n", symname, status );
    }
    sprintf( symname, "%sREMOTE_IDENT", prefix );
    if ( getenv( symname ) == NULL ) {
        symbol.dsc$w_length = strlen( symname );
	symvalue[0] = '\0';
	value.dsc$a_pointer = symvalue;
	value.dsc$w_length = 0;
	status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	if ( (status&1) == 0 ) fprintf(stderr,
	    "Error defining %s symbol.  status: %d\n", symname, status );
    }
    sprintf( symname, "%sREMOTE_USER", prefix );
    if ( getenv( symname ) == NULL ) {
        symbol.dsc$w_length = strlen( symname );
	symvalue[0] = '\0';
	value.dsc$a_pointer = symvalue;
	value.dsc$w_length = 0;
	status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	if ( (status&1) == 0 ) fprintf(stderr,
	    "Error defining %s symbol.  status: %d\n", symname, status );
    }

    /*
     * Check for Form content.
     */
    if ( (METHOD=cgi_info("REQUEST_METHOD")) != NULL) {
        /*
	 * Check whether we want equal signs appended to names.
	 */
        sprintf( symname, "%sAPPEND_EQUAL_SIGN", prefix );
        if ( getenv( symname ) != NULL )
	    append_equal_sign = 1;

        if ( 0==strcasecomp( METHOD, "POST" ) &&
             (cp=cgi_info( "CONTENT_TYPE" )) != NULL &&
             0==strcasecomp(cp,"application/x-www-form-urlencoded") ) {
            /*
	     * It's a Form with METHOD="POST".
	     */
	    cl = atoi( (cp=cgi_info("CONTENT_LENGTH")) ? cp : "0" );
	    if ( cl && (contentf = cgi_content_file()) ) {
	        /*
		 * We have POST content.
		 */
	        for(x = 0; cl && (!feof(contentf) && x < MAX_ENTRIES); x++) {
		    entries[x].val = fmakeword(contentf, '&', &cl);
		    plustospace(entries[x].val);
		    unescape_url(entries[x].val);
		    entries[x].name = makeword(entries[x].val,'=');
		    if (append_equal_sign)
		        strcat(entries[x].name, "=");
		    m++;
	        }
		if ( *Fprefix == '\0' ) {
		    /*
		     * Default CERN-style symbols wanted.
		     */
                    do_dcl_form_env(m);
		    count = (2 * m);
		} else {
		    /*
		     * OSU CGI_SYMBOLS-style symbols wanted.
		     */
		    do_cgi_form_env(m);
		    count = 0;
		}
	    }
	} else if ( 0==strcasecomp( METHOD, "GET" ) &&
		    (cp=cgi_info("QUERY_STRING")) != NULL && *cp != '\0' &&
		    strchr( cp, '=') != NULL ) {
            /*
	     * It's a Form with METHOD="GET" and we have content.
	     */
            for(x=0; cp[0] != '\0' && x < MAX_ENTRIES; x++) {
	        len = strlen(cp) + 1;
	        if (cp1=strchr(cp, '&'))
	            len -= strlen(cp1);
	        entries[x].val = (char *) malloc(sizeof(char) * len);
                getword(entries[x].val, cp, '&');
                plustospace(entries[x].val);
                unescape_url(entries[x].val);
                entries[x].name = makeword(entries[x].val,'=');
		if (append_equal_sign)
	            strcat(entries[x].name, "=");
	        m++;
	    }
	    if ( *Fprefix == '\0' ) {
		/*
		 * Default CERN-style symbols wanted.
		 */
                do_dcl_form_env(m);
		count = (2 * m);
	    } else {
		/*
		 * OSU CGI_SYMBOLS-style symbols wanted.
		 */
		do_cgi_form_env(m);
		count = 0;
	    }
        } else if ( *Fprefix != '\0' ) {
            /*
             * Output foo_FIELDS_COUNT and foo_FLD_COUNT symbols
	     * with zero values.
             */
            sprintf( symname, "%sFIELDS_COUNT", Fprefix );
	    symbol.dsc$w_length = strlen( symname );
	    strcpy(KeyCount, "0");
	    value.dsc$a_pointer = KeyCount;
	    value.dsc$w_length = 1;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
	        "Error defining %s symbol.  status: %d\n", symname, status );

            sprintf( symname, "%sFLD_COUNT", Fprefix );
	    symbol.dsc$w_length = strlen( symname );
	    strcpy(KeyCount, "0");
	    value.dsc$a_pointer = KeyCount;
	    value.dsc$w_length = 1;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
	        "Error defining %s symbol.  status: %d\n", symname, status );
        }
    }

    /*
     * Check for an ISINDEX query.
     */
    if ( (cp=cgi_info( "QUERY_STRING" )) != NULL && *cp != '\0' &&
	 strchr( cp, '=' ) == NULL ) {
	/*
	 * Check for a + separated set of terms.
	 */
	char *query = cp;
	while ( (cp=strchr(query, '+')) != NULL ) {
	    *(cp++) = '\0';
	    unescape_url(query);
	    sprintf( symname, "%sKEY_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = query;
	    value.dsc$w_length = strlen (query);
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	    query = cp;
	}
	/*
	 * Do the first term if its the only, or the last term.
	 */
	if ( *query != '\0' ) {
	    unescape_url(query);
	    sprintf( symname, "%sKEY_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = query;
	    value.dsc$w_length = strlen (query);
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	}
    }

    /*
     * Set the KEY count.
     */
    sprintf( symname, "%sKEY_COUNT", prefix );
    symbol.dsc$w_length = strlen( symname );
    sprintf(KeyCount, "%d", count);
    value.dsc$a_pointer = KeyCount;
    value.dsc$w_length = strlen ( KeyCount );
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );

    /*
     * Add any supplementary function calls here.
     */

    /*
     * Return control to the DCL command file.
     */
    return (1);
} /* main */


static void getword(char *word, char *line, char stop) {
    int x = 0,y;

    for(x=0; ((line[x] != '\0') && (line[x] != stop)); x++)
        word[x] = line[x];

    word[x] = '\0';
    if(line[x]) ++x;
    y=0;

    while(line[y++] = line[x++]);
    return;
}


static char *makeword(char *line, char stop) {
    int x = 0,y;
    char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));

    for(x=0;((line[x]) && (line[x] != stop));x++)
        word[x] = line[x];

    word[x] = '\0';
    if(line[x]) ++x;
    y=0;

    while(line[y++] = line[x++]);
    return word;
}


static char *fmakeword(FILE *f, char stop, int *cl) {
    int wsize;
    char *word;
    int ll;

    wsize = 96;
    ll=0;
    word = (char *) malloc(sizeof(char) * (wsize + 1));

    while(1) {
        word[ll] = (char)fgetc(f);
        if(ll==wsize) {
            word[ll+1] = '\0';
            wsize+=1024;
            word = (char *)realloc(word,sizeof(char)*(wsize+1));
        }
        --(*cl);
        if((word[ll] == stop) || (feof(f)) || (!(*cl))) {
            if(word[ll] != stop) ll++;
            word[ll] = '\0';
            return word;
        }
        ++ll;
    }
}


static char x2c(char *what) {
    register char digit;

    digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
    digit *= 16;
    digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
    return(digit);
}


static void unescape_url(char *url) {
    register int x,y;

    for(x=0,y=0;url[y];++x,++y) {
        if((url[x] = url[y]) == '%') {
            url[x] = x2c(&url[y+1]);
            y+=2;
	    if(url[x] == '\r') {
	        if(url[y] == '%' && x2c(&url[y+1]) == '\n')
		    /* Ignore the CR in CRLFs */
		    x--;
		else
		    /* Convert lone CR to LF */
		    url[x] = '\n';
	    }
        }
    }
    url[x] = '\0';
}


static void plustospace(char *str) {
    register int x;

    for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
}


static int strcasecomp(char *a, char *b)
{
	char *p = a;
	char *q = b;
	for(p=a, q=b; *p && *q; p++, q++) {
	    int diff = tolower(*p) - tolower(*q);
	    if (diff) return diff;
	}
	if (*p) return 1;	/* p was longer than q */
	if (*q) return -1;	/* p was shorter than q */
	return 0;		/* Exact match */
}


static int strncasecomp(char *a, char *b, int n)
{
	char *p = a;
	char *q = b;
	
	for(p=a, q=b;; p++, q++) {
	    int diff;
	    if (p == a+n) return 0;	/*   Match up to n characters */
	    if (!(*p && *q)) return *p - *q;
	    diff = tolower(*p) - tolower(*q);
	    if (diff) return diff;
	}
}

static void do_dcl_form_env(int m)
{
    int i, count, status, length, table, LIB$SET_SYMBOL();
    $DESCRIPTOR(symbol,"");
    $DESCRIPTOR(value,"");
    char symname[256];
    register int x;
    symbol.dsc$a_pointer = symname;

    /*
     * Define local symbols to be used by calling script.
     */
    table = LIB$K_CLI_LOCAL_SYM;
    for ( count = x = 0; x < m; x++ ) {
	/*
	 * Set key for name.
	 */
	sprintf( symname, "%sKEY_%d", prefix, ++count );
	symbol.dsc$w_length = strlen( symname );
	value.dsc$a_pointer = entries[x].name;
	value.dsc$w_length = strlen ( entries[x].name );
	if ( value.dsc$w_length > 255 )
	    value.dsc$w_length = 255;
	status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	if ( (status&1) == 0 ) fprintf(stderr,
	    "Error defining %s symbol.  status: %d\n", symname, status );
	/*
	 * Set key(s) for value.
	 */
	if ( strchr( entries[x].val, '\n' ) == NULL ) {
	    /*
	     * Value is a simple string.
	     */
	    sprintf( symname, "%sKEY_%d", prefix, ++count );
	    symbol.dsc$w_length = strlen( symname );
	    value.dsc$a_pointer = entries[x].val;
	    value.dsc$w_length = strlen ( entries[x].val );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	} else {
	    /*
	     * Value is a multi-line TEXTAREA.
	     */
	    int line = 0;
	    char *newline;
	    char *cp = entries[x].val;
	    ++count;
	    while ( (newline=strchr( cp, '\n' )) != NULL ) {
	        /*
		 * Get all the lines preceding newlines.
		 */
	        *newline = '\0';
		sprintf( symname, "%sKEY_%d_%d", prefix, count, ++line );
		symbol.dsc$w_length = strlen( symname );
		value.dsc$a_pointer = cp;
		value.dsc$w_length = strlen ( cp );
		if ( value.dsc$w_length > 255 )
		    value.dsc$w_length = 255;
		status = LIB$SET_SYMBOL ( &symbol, &value, &table );
		if ( (status&1) == 0 ) fprintf(stderr,
		    "Error defining %s symbol.  status: %d\n",
		    		    symname, status );
		cp = (newline + 1);
	    }
	    if ( *cp != '\0' ) {
	        /*
		 * Get the last line if there wasn't a terminal newline.
		 */ 
		sprintf( symname, "%sKEY_%d_%d", prefix, count, ++line );
		symbol.dsc$w_length = strlen( symname );
		value.dsc$a_pointer = cp;
		value.dsc$w_length = strlen ( cp );
		if ( value.dsc$w_length > 255 )
		    value.dsc$w_length = 255;
		status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	        if ( (status&1) == 0 ) fprintf(stderr,
		    "Error defining %s symbol.  status: %d\n",
		    		    symname, status );
	    }
	    /*
	     * Set the line count for this key.
	     */
	    sprintf( symname, "%sKEY_%d_COUNT", prefix, count);
	    symbol.dsc$w_length = strlen( symname );
	    sprintf(KeyCount, "%d", line);
	    value.dsc$a_pointer = KeyCount;
	    value.dsc$w_length = strlen ( KeyCount );
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) fprintf(stderr,
		"Error defining %s symbol.  status: %d\n", symname, status );
	}
    }
    return;
}

static void do_cgi_form_env (int m)
{
    int i, j, FLDCount, FIELDSCount, status, length, table, LIB$SET_SYMBOL();
    $DESCRIPTOR(symbol,"");
    $DESCRIPTOR(value,"");
    char symname[256], sym_list[256], temp[256];
    char *cp;
    register int x;
    symbol.dsc$a_pointer = symname;

    /*
     * Initilize our comma-separated list of names and counters.
     */
    for (i = 0; i < 256; i++)
        sym_list[i] = '\0';
    length = 0;
    FLDCount = 0;
    FIELDSCount = 0;

    /*
     * Define local symbols to be used by calling script.
     */
    table = LIB$K_CLI_LOCAL_SYM;
    /*
     *  Set the foo_FLD_name symbol values.
     *
     *  Note that with this design, multi-line TEXTAREA values are
     *    almost certain to be trunctated.
     */
    sprintf( symname, "%sFLD_", Fprefix );
    symname[255] = '\0';
    for ( x = 0; x < m; x++ ) {
	strncpy( (char *)&symname[Fprefix_len],
			 entries[x].name, (255 - Fprefix_len) );

	/*
	 * Force field names uppercase and convert any dashes to underscores.
	 */
	for ( i = Fprefix_len; symname[i] != '\0'; i++ ) {
	    symname[i] = toupper( symname[i] );
	    if (symname[i] == '-')
	        symname[i] =  '_';
	}
	symbol.dsc$w_length = strlen( symname );

        /*
	 * Check if we already have the name, and if not, set the
	 * new name=value pair, otherwise, append the value to the
	 * existing one as a comma-separated list.
	 */
	i = 0;
	while ( i < x && strcmp( entries[i].name, entries[x].name ) )
	    i++;
	if ( i >= x ) {
	    /*
	     * Set the new pair;
	     */
	    value.dsc$a_pointer = entries[x].val;
	    value.dsc$w_length = strlen ( entries[x].val );
	    if ( value.dsc$w_length > 255 )
	        value.dsc$w_length = 255;
	    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
	    if ( (status&1) == 0 ) {
	        fprintf( stderr,
			 "Error defining %s symbol.  status: %d\n",
			 symname, status );
	    } else {
	        FLDCount++;

	        /*
		 * Create or extend a comma-separated list
		 * of form field names.
		 *
		 * Note that this list is likely to be
		 * trunctated for a large form.
		 */
		j = strlen( entries[x].name );
		if ( (length + j + (sym_list[0] ? 2 : 1)) < 256 ) {
		    if ( sym_list[0] ) {
		        strcat( sym_list, "," );
			length++;
		    }
		    strcat( sym_list, entries[x].name );
		    length += j;
		    FIELDSCount++;
		}
	    }
	} else {
	    /*
	     * Append the current value to the previous value
	     * as a comma separated list.
	     */
	    cp = getenv( symname );
	    j = strlen( entries[x].val ) + (cp ? strlen( cp ) : 256) + 2;
	    if ( j < 256 ) {
	        strcpy( temp, cp );
		strcat( temp, "," );
		strcat( temp, entries[x].val );
		value.dsc$a_pointer = temp;
		value.dsc$w_length = strlen ( temp );
		status = LIB$SET_SYMBOL ( &symbol, &value, &table );
		if ( (status&1) == 0 ) {
		    fprintf( stderr,
		    	     "Error redefining %s symbol.  status: %d\n",
			     symname, status );
		}
	    } else {
	        fprintf( stderr,
	      		 "Error extending %s symbol.  status: %d\n",
			 symname, status );
	    }
	}
    }

    /*
     *  Set a foo_FLD_COUNT symbol with the number of
     *    foo_FLD_name=value symbols that were set,
     *	  where value could be a comma-separated list.
     */
    sprintf( symname, "%sFLD_COUNT", Fprefix );
    symbol.dsc$w_length = strlen( symname );
    sprintf(KeyCount, "%d", FLDCount);
    value.dsc$a_pointer = KeyCount;
    value.dsc$w_length = strlen ( KeyCount );
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );

    /*
     * Output the list of unique names as the foo_FIELDS symbol.
     */
    sprintf( symname, "%sFIELDS", Fprefix );
    symbol.dsc$w_length = strlen ( symname );
    value.dsc$w_length = strlen( sym_list );
    value.dsc$a_pointer = sym_list;
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );

    /*
     * Output a foo_FIELDS_COUNT symbol with
     * the number of (comma-separated) names in the list
     * (might be less than foo_FLD_COUNT).
     */
    sprintf( symname, "%sFIELDS_COUNT", Fprefix );
    symbol.dsc$w_length = strlen( symname );
    sprintf(KeyCount, "%d", FIELDSCount);
    value.dsc$a_pointer = KeyCount;
    value.dsc$w_length = strlen ( KeyCount );
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
    if ( (status&1) == 0 ) fprintf(stderr,
	"Error defining %s symbol.  status: %d\n", symname, status );

    return;
}