adacgi-1.6/0040755000175000017500000000000007535217144010714 5ustar pjbpjbadacgi-1.6/COPYING0100644000175000017500000000064107535217157011751 0ustar pjbpjbThe different components in this distribution have different licenses. See cgi.html for information on licenses. The main AdaCGI library is covered by the LGPL (see lesser.txt) with some modifications (see cgi.ads). The demonstration programs and documentation are covered by the GPL (see gpl.txt). See http://www.gnu.org/copyleft for more information (and copies of these licenses, in case you don't have them). adacgi-1.6/README0100644000175000017500000000325207535217157011577 0ustar pjbpjb This directory contains AdaCGI, an Ada 95 interface to the Common Gateway Interface (CGI). To see its current status, go to the AdaCGI website at: http://www.dwheeler.com/adacgi The following files are included in the AdaCGI distribution: cgi.html - Documentation for AdaCGI. (Older versions of this package included a duplicate file named cgi-doc.htm; now just consult cgi.html). cgi.ads - The Ada 95 package specification (declaration) for the main CGI Ada package. cgi.adb - The corresponding Ada 95 package body. minimal.adb - A minimal demonstration of how to use CGI. demo.adb - A larger demonstration of how to use CGI. search.adb - Search replies with all lines that match a given pattern in a given file. Only files listed in a special srchlist file may be searched. makefile - The makefile to compile the demo programs using the GNAT Ada 95 compiler. ustrings.ads - A package that simplifies the use of Ada's Unbounded_String. It is required by the search demonstration program. ustrings.adb - Its package body. test_get.adb - Source for a short test program of package Ustrings. README - This file. COPYING - Information about copying and licensing. There are a few other demo files and related material. The entire distribution is contained in a single file named "cgi.zip", a zip-formatted file, and in "cgi.tar.gz", a tarball. There's also an RPM packaging of it. Previously the package was available at: http://wuarchive.wustl.edu/languages/ada/swcomps/cgi/cgi.html --- David A. Wheeler dwheeler@dwheeler.com adacgi-1.6/adacgi.spec0100644000175000017500000003674307535217157013016 0ustar pjbpjb# Copyright (C) 1999, 2000 # by Juergen Pfeifer # Ada for Linux Team (ALT) # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, distribute with modifications, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR # THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name(s) of the above copyright # holders shall not be used in advertising or otherwise to promote the # sale, use or other dealings in this Software without prior written # authorization. # # --------------------------------------------------------------------------- # Author: Juergen Pfeifer # --------------------------------------------------------------------------- # GNU Ada RPM Packaging for David Wheelers CGI package # # This specification file is generated using a m4 based macrosystem. # Please don't change it directly but get instead the macro system # and change the input files of this system. # --------------------------------------------------------------------------- # %define PKG_TARGET_OS Linux %define TARGET_OS linux %define TARGET_ARCH i386 %define COMPAT_TARGET_ARCH i386 i486 i586 i686 %define DEF_USER bin %define DEF_GROUP bin %define CFG_PREFIX /usr # %define AUTHOR_NAME Juergen Pfeifer %define AUTHOR_MAIL juergen.pfeifer@gmx.net # %define GNAT_BASE_VERSION 3.12 %define GNAT_PKG_VERSION 3.12p %define GNAT_PKG_RELEASE 10 %define GCC_VERSION 2.8.1 %define GDB_VERSION 4.17 %define GLIBC_VERSION 2.1 %define GNAT_VERSION 3.12p %define BASE_VERSION gcc-%{GCC_VERSION} # %define BASE_NAME gnat %define GNAT_PKG_NAME gnat %define GNATRT_PKG_NAME gnat-3.12p-runtime %define GNATRT_PKG_VERSION 1 # %define ADA_ROOT /lib/ada %define ADA_BASE %{CFG_PREFIX}%{ADA_ROOT} %define SHARE_BASE /share/ada %define ADA_SHARE %{CFG_PREFIX}%{SHARE_BASE} # %define HTML_BASE %{SHARE_BASE}/html %define ADA_HTML %{CFG_PREFIX}%{HTML_BASE} # %define GNAT_SO_MAJOR 1 %define GNAT_SO_MINOR %{GNAT_PKG_RELEASE} # %define RPM_C_FLAGS -O3 -m486 %define RPM_ADA_FLAGS -gnatpn # %define THREADLIBS -lpthread # %define DOC_BASE %{CFG_PREFIX}/doc # %define GNAT_ALIAS %{BASE_NAME} %define GNAT_NAME %{GNAT_ALIAS}-%{GNAT_VERSION} %define GNAT_SO %{GNAT_NAME} # %define GNARL_ALIAS gnarl %define GNARL_NAME %{GNARL_ALIAS}-%{GNAT_VERSION} %define GNARL_SO %{GNARL_NAME} # %define AINC_NAME adainclude %define AINC_DIR %{ADA_BASE}/%{AINC_NAME} # %define ALIB_NAME adalib %define ALIB_DIR %{ADA_BASE}/%{ALIB_NAME} # %define ETC_NAME etc %define ETC_DIR %{ADA_BASE}/%{ETC_NAME} %define EMACS_DIR %{ADA_ROOT}/%{ETC_NAME}/adamode %define ADAMODE_DIR %{CFG_PREFIX}%{EMACS_DIR} %define INFO_NAME %{ADA_ROOT}/info %define INFO_DIR %{CFG_PREFIX}%{INFO_NAME} # %define ASIS_ALIAS asis %define ASIS_NAME %{ASIS_ALIAS}-%{GNAT_VERSION} %define ASIS_SO %{ASIS_NAME} %define ASIS_DIR %{ADA_BASE}/%{ASIS_NAME} # %define GLADE_ALIAS garlic %define GLADE_NAME garlic-%{GNAT_VERSION} %define GLADE_SO garlic-%{GNAT_VERSION} %define GLADE_DIR %{ADA_BASE}/%{GLADE_NAME} # %define FLORIST_ALIAS florist %define FLORIST_NAME %{FLORIST_ALIAS}-%{GNAT_VERSION} %define FLORIST_SO %{FLORIST_NAME} # %define GNAT_GCC gnatgcc # %define PKG_NAME adacgi %define PKG_VERSION 1.6 %define PKG_RELEASE 1 # # If there is a runtime package, it has this name %define PKGRT_NAME adacgi-runtime # # Name of development package in the old scheme %define OLD_DEVPKG_NAME adacgi-devel-3.12p %define OLD_RTNAME adacgi-3.12p # # --------------------------------------------------------------------------- # We restrict the use of this package script at the moment to Intel and # Linux. For sure there are details (compiler options, shared library # building) that must be fixed for other architectures and OSes. # ExclusiveArch: %{COMPAT_TARGET_ARCH} ExclusiveOS: %{PKG_TARGET_OS} Vendor: Ada for Linux Team (ALT) Packager: Juergen Pfeifer Distribution: ALT (Ada for Linux Team) Version: %{PKG_VERSION} Release: %{PKG_RELEASE} Name: %{PKG_NAME} BuildRoot: %{_builddir}/%{PKG_NAME}_glibc%{GLIBC_VERSION}-%{version}-root Autoreq: No Autoreqprov: No # --------------------------------------------------------------------------- # # This are the official sources Source0: http://www.dwheeler.com/adacgi/latest/adacgi-%{version}.tar.gz # # --------------------------------------------------------------------------- Copyright: GPL (modified for runtime) URL: http://www.dwheeler.com Summary: Ada95 CGI Programming Interface Summary(de): Ada95 Interface fu%r CGI Programmierung Group: Libraries Requires: %{GNAT_PKG_NAME} = %{GNAT_PKG_VERSION} Provides: %{name} Obsoletes: %{name} Conflicts: %{name}-%{GNAT_VERSION} Prefix: %{CFG_PREFIX} # I don't have this icon: # Icon: adasmall.gif # %description This is David A. Wheeler's package for implementing web programs in Ada95. This is an Ada95 binding to CGI (the Common Gateway Interface), a common interface between web servers and specialized web server applications. You only need to install this package if you're compiling Ada95 programs which use this binding. %description -l de Dies ist David A. Wheeler's Paket fu%r die Implementierung von Web Programmen in Ada95. Es ist ein Ada95 Binding fu%r CGI (das Common Gateway Interface), eine allgemeine Schnittstelle zwischen Web-Servern und Web-Server Anwendungen. Sie brauchen dieses Paket nur zu installieren wenn Sie Ada95 Programme schreiben wollen, die dieses Binding benutzen. # #----------------------------------------------------------------------------- %prep #============================================================================= # %setup # #----------------------------------------------------------------------------- %build #============================================================================= # # Get the name of the Operating System in lower case OS=%{TARGET_OS} # PATH=/usr/bin:/bin:/sbin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin if [ "${GNAT_ROOT}" != "" ]; then PATH="${GNAT_ROOT}/bin:${PATH}" fi export PATH # %define ALT_BUILD_DOC $RPM_BUILD_ROOT/doc %define ALT_BUILD_HTML $RPM_BUILD_ROOT%{ADA_HTML} # # Create the required directory structure for the binary package rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{CFG_PREFIX}/info mkdir -p $RPM_BUILD_ROOT%{CFG_PREFIX}/bin mkdir -p $RPM_BUILD_ROOT%{CFG_PREFIX}/lib mkdir -p $RPM_BUILD_ROOT%{CFG_PREFIX}/doc mkdir -p $RPM_BUILD_ROOT%{AINC_DIR} mkdir -p $RPM_BUILD_ROOT%{ALIB_DIR} mkdir -p $RPM_BUILD_ROOT%{GLADE_DIR} mkdir -p $RPM_BUILD_ROOT%{ASIS_DIR} mkdir -p $RPM_BUILD_ROOT%{ETC_DIR} mkdir -p $RPM_BUILD_ROOT%{INFO_DIR} mkdir -p $RPM_BUILD_ROOT%{ADA_SHARE} mkdir -p %{ALT_BUILD_DOC} mkdir -p %{ALT_BUILD_HTML} # mkdir -p %{ALT_BUILD_DOC}/sample mkdir -p %{ALT_BUILD_HTML}/adacgi # %{GNAT_GCC} -c %{RPM_C_FLAGS} %{RPM_ADA_FLAGS} cgi.adb # #----------------------------------------------------------------------------- %install #============================================================================= OS=%{TARGET_OS} # # cp -pf cgi.ad? $RPM_BUILD_ROOT%{AINC_DIR} cp -pf cgi.ali $RPM_BUILD_ROOT%{ALIB_DIR} cp -pf cgi.o $RPM_BUILD_ROOT%{ALIB_DIR} rm -f cgi.ad? # cp -pf README %{ALT_BUILD_DOC}/ cp -pf COPYING %{ALT_BUILD_DOC}/ cp -pf *.txt %{ALT_BUILD_DOC}/ cp -pf cgi.html %{ALT_BUILD_DOC}/ cp -pf cgi.html %{ALT_BUILD_HTML}/cgi-doc.html cp -pf *.ad? %{ALT_BUILD_DOC}/sample cp -pf makefile %{ALT_BUILD_DOC}/sample cp -pf screen.html %{ALT_BUILD_DOC}/sample rm -f %{ALT_BUILD_DOC}/sample/cgi.ad? # pushd $RPM_BUILD_ROOT%{AINC_DIR} ${GNAT_ROOT:-/usr}/bin/gnathtml -I../%{ALIB_NAME} \ -o%{ALT_BUILD_HTML}/adacgi *.ad[bs] popd # if [ -d ${RPM_BUILD_ROOT}%{AINC_DIR} ]; then find ${RPM_BUILD_ROOT}%{AINC_DIR} -type f -name '*.ad?' -exec chmod 0444 {} \; fi if [ -d ${RPM_BUILD_ROOT}%{ALIB_DIR} ]; then find ${RPM_BUILD_ROOT}%{ALIB_DIR} -type f -name '*.ali' -exec chmod 0444 {} \; find ${RPM_BUILD_ROOT}%{ALIB_DIR} -type f -name '*.o' -exec chmod 0444 {} \; find ${RPM_BUILD_ROOT}%{ALIB_DIR} -type f -name '*.a' -exec chmod 0444 {} \; fi if [ -d ${RPM_BUILD_ROOT}%{CFG_PREFIX}/lib ]; then find ${RPM_BUILD_ROOT}%{CFG_PREFIX}/lib -type f -name '*.so*' -exec chmod 0755 {} \; fi if [ -d ${RPM_BUILD_ROOT}/doc ]; then find ${RPM_BUILD_ROOT}/doc -type f -exec chmod 0444 {} \; find ${RPM_BUILD_ROOT}/doc -type d -exec chmod 0755 {} \; fi # --------------------------------------------------------------------------- %pre if [ -f /etc/profile.d/%{BASE_NAME}-rts.sh ]; then source /etc/profile.d/%{BASE_NAME}-rts.sh if [ ! -z ${GNAT_ROOT} ]; then if [ "${GNAT_ROOT}" != "${RPM_INSTALL_PREFIX}" ]; then echo "%{BASE_NAME} was installed with --prefix=${GNAT_ROOT}" >&2 echo "You must use the same prefix with this package." >&2 exit 1 fi else if [ "${RPM_INSTALL_PREFIX}" != "%{CFG_PREFIX}" ]; then echo "%{BASE_NAME} was installed without the --prefix option." >&2 echo "You must do this also with this package." >&2 exit 1 fi fi fi # --------------------------------------------------------------------------- %post etc_prof="/etc/profile.d" ETC_DIR="${RPM_INSTALL_PREFIX}%{ADA_ROOT}/%{ETC_NAME}" # htmldir=${RPM_INSTALL_PREFIX}/share/ada/html pkgfile=${htmldir}/packages html_insert() { mkdir -p ${htmldir} 2>/dev/null if [ -f $pkgfile ]; then awk -F, '{printf "%s,\n",$1;}' < $pkgfile | grep -q "$1," if [ $? -eq 0 ]; then sed -e "/^$1,/d" < $pkgfile >${pkgfile}.tmp mv -f ${pkgfile}.tmp ${pkgfile} fi fi echo "$1,$2,$3" >> $pkgfile } html_remove() { sed -e "/^$1,/d" < ${pkgfile} > ${pkgfile}.tmp mv -f ${pkgfile}.tmp ${pkgfile} } html_generate() { insmarker="" indexfile=${htmldir}/index.html touch ${pkgfile}.in if [ -f ${pkgfile} ]; then awk -F, '{printf "
  • %s
  • \n",$2,$1,$3;}' < ${pkgfile} > ${pkgfile}.in fi if [ -f ${indexfile}.in ]; then cat > ${pkgfile}.sed < ${indexfile} rm -f ${pkgfile}.sed fi rm -f ${pkgfile}.in } html_insert "adacgi" "cgi-doc.html" "CGI Binding Documentation" html_insert "adacgi2" "adacgi/index.htm" "CGI Binding Packages" html_generate # --------------------------------------------------------------------------- %postun etc_prof="/etc/profile.d" ETC_DIR="${RPM_INSTALL_PREFIX}%{ADA_ROOT}/%{ETC_NAME}" # htmldir=${RPM_INSTALL_PREFIX}/share/ada/html pkgfile=${htmldir}/packages html_insert() { mkdir -p ${htmldir} 2>/dev/null if [ -f $pkgfile ]; then awk -F, '{printf "%s,\n",$1;}' < $pkgfile | grep -q "$1," if [ $? -eq 0 ]; then sed -e "/^$1,/d" < $pkgfile >${pkgfile}.tmp mv -f ${pkgfile}.tmp ${pkgfile} fi fi echo "$1,$2,$3" >> $pkgfile } html_remove() { sed -e "/^$1,/d" < ${pkgfile} > ${pkgfile}.tmp mv -f ${pkgfile}.tmp ${pkgfile} } html_generate() { insmarker="" indexfile=${htmldir}/index.html touch ${pkgfile}.in if [ -f ${pkgfile} ]; then awk -F, '{printf "
  • %s
  • \n",$2,$1,$3;}' < ${pkgfile} > ${pkgfile}.in fi if [ -f ${indexfile}.in ]; then cat > ${pkgfile}.sed < ${indexfile} rm -f ${pkgfile}.sed fi rm -f ${pkgfile}.in } html_remove adacgi html_remove adacgi2 html_generate # --------------------------------------------------------------------------- %files %defattr(-,%{DEF_USER},%{DEF_GROUP}) %doc %{ALT_BUILD_DOC}/* %dir %{CFG_PREFIX} %dir %{ADA_BASE} %dir %{AINC_DIR} %dir %{ALIB_DIR} %dir %{ADA_HTML} %dir %{ADA_HTML}/adacgi %{AINC_DIR}/* %{ALIB_DIR}/* %{ADA_HTML}/*.html %{ADA_HTML}/adacgi/* # # --------------------------------------------------------------------------- %clean rm -rf $RPM_BUILD_ROOT # --------------------------------------------------------------------------- rm -rf $RPM_BUILD_DIR/adacgi # %changelog * Wed Nov 1 2000 David A. Wheeler - Released version 1.6. * Tue Mar 14 2000 Juergen Pfeifer - Published as Release 1 of Version 1.5 * Wed Mar 01 2000 Juergen Pfeifer - Fixed documentation generation in spec file * Sun Feb 27 2000 Juergen Pfeifer - Published as Release 6 * Wed Feb 23 2000 Juergen Pfeifer - Grand package renaming * Mon Jan 03 2000 Juergen Pfeifer - Published as Release 5 * Wed Dec 29 1999 Juergen Pfeifer - Inlined HTML generation into the installation scripts to eliminate installation order dependencies. * Mon Nov 15 1999 Juergen Pfeifer - Published as Release 4 * Sun Nov 07 1999 Juergen Pfeifer - Added gnathtml generated package docu - Integrate AdaCGI HTML page into overall HTML docu. * Sun Oct 31 1999 Juergen Pfeifer - Fixed build architecture handling - Published as Release 3 * Fri Oct 29 1999 Juergen Pfeifer - Published as Release 2 (3.12p based) * Tue Sep 14 1999 David A. Wheeler - Updated to adacgi 1.4: + merged in Juergen Pfeifer's patch, + added cookie support + Expanded documentation + License change to be LGPL-like * Wed Mar 31 1999 Juergen Pfeifer - Changed description - Published as Release 1 * Wed Mar 10 1999 Juergen Pfeifer - Created adacgi-1.6/cgi.adb0100644000175000017500000006260307535217157012136 0ustar pjbpjbwith Ada.Strings.Maps, Ada.Characters.Handling, Interfaces.C.Strings, Text_IO; use Ada.Strings.Maps, Ada.Characters.Handling, Interfaces.C.Strings, Text_IO; with Ada.Strings.Maps.Constants; use Ada.Strings.Maps.Constants; package body CGI is -- This package is an Ada 95 interface to the "Common Gateway Interface" (CGI). -- This package makes it easier to create Ada programs that can be -- invoked by HTTP servers using CGI. -- Developed by David A. Wheeler, dwheeler@dwheeler.com, (C) 1995-2000. -- See the specification file for the license. -- The following are key types and constants. type Key_Value_Pair is record Key, Value : Unbounded_String; end record; type Key_Value_Sequence is array(Positive range <>) of Key_Value_Pair; type Access_Key_Value_Sequence is access Key_Value_Sequence; Cookie_Data: Access_Key_Value_Sequence; Ampersands : constant Character_Set := To_Set('&'); Equals : constant Character_Set := To_Set('='); Plus_To_Space : constant Character_Mapping := To_Mapping("+", " "); Semicolon : constant Character_Set := To_Set(';'); Unescaped_URL : constant Character_Set := Alphanumeric_Set or To_Set("-_.!~*'()"); -- The following are data internal to this package. Parsing_Errors_Occurred : Boolean := True; Is_Index_Request_Made : Boolean := False; -- Isindex request made? CGI_Data : Access_Key_Value_Sequence; -- Initially nil. Actual_CGI_Method : CGI_Method_Type := Get; -- The following are private "Helper" subprograms. function Value_Without_Exception(S : chars_ptr) return String is pragma Inline(Value_Without_Exception); -- Translate S from a C-style char* into an Ada String. -- If S is Null_Ptr, return "", don't raise an exception. begin if S = Null_Ptr then return ""; else return Value(S); end if; end Value_Without_Exception; function Image(N : Natural) return String is -- Convert Positive N to a string representation. This is just like -- Ada 'Image, but it doesn't put a space in front of it. Result : String := Natural'Image(N); begin return Result( 2 .. Result'Length); end Image; function Field_End(Data: Unbounded_String; Field_Separator: Character; Starting_At : Positive := 1) return Natural is -- Return the end-of-field position in Data after "Starting_Index", -- assuming that fields are separated by the Field_Separator. -- If there's no Field_Separator, return the end of the Data. begin for I in Starting_At .. Length(Data) loop if Element(Data, I) = Field_Separator then return I-1; end if; end loop; return Length(Data); end Field_End; function Hex_Value(H : in String) return Natural is -- Given hex string, return its Value as a Natural. Value : Natural := 0; begin for P in H'Range loop Value := Value * 16; if H(P) in '0' .. '9' then Value := Value + Character'Pos(H(P)) - Character'Pos('0'); elsif H(P) in 'A' .. 'F' then Value := Value + Character'Pos(H(P)) - Character'Pos('A') + 10; elsif H(P) in 'a' .. 'f' then Value := Value + Character'Pos(H(P)) - Character'Pos('a') + 10; else raise Constraint_Error; end if; end loop; return Value; end Hex_Value; procedure URL_Decode(Data : in out Unbounded_String; Translate_Plus : Boolean := True) is I : Positive := 1; Last_Possible_Position : Integer := Length(Data) - 2; begin -- For URL/URI encoding, see IETF RFC 2396. while I <= Last_Possible_Position loop if Element(Data, I) = '%' and then Is_Hexadecimal_Digit(Element(Data, I+1)) and then Is_Hexadecimal_Digit(Element(Data, I+2)) then Replace_Element(Data, I, Character'Val(Hex_Value(Slice(Data, I+1, I+2)))); Delete(Data, I+1, I+2); Last_Possible_Position := Last_Possible_Position - 2; end if; I := I + 1; end loop; if Translate_Plus then Translate(Data, Mapping => Plus_To_Space); end if; end URL_Decode; function URL_Decode(Data : in Unbounded_String; Translate_Plus : Boolean := True) return Unbounded_String is Destination : Unbounded_String := Data; begin URL_Decode(Destination); return Destination; end URL_Decode; function To_Hex_Char(Number : Natural ) return Character is begin -- Assumes ASCII (or at least continuity in 0..9 and A..F). if Number < 10 then return Character'Val(Number + Character'Pos('0')); else return Character'Val(Number + Character'Pos('A') - 10); end if; end To_Hex_Char; procedure URL_Encode(Data : in out Unbounded_String; Translate_Plus : Boolean := False) is I : Positive := 1; Current_Character : Character; Replacer : String := "%xx"; -- The String we replace with. Last_Position : Natural := Length(Data); begin -- For URL/URI encoding, see IETF RFC 2396. while I <= Last_Position loop Current_Character := Element(Data, I); if Translate_Plus and Current_Character = '+' then Replace_Element(Data, I, ' '); elsif not Is_In(Current_Character, Unescaped_URL) then -- Character I isn't safe, replace it: Replacer(2) := To_Hex_Char(Character'Pos(Current_Character) / 16); Replacer(3) := To_Hex_Char(Character'Pos(Current_Character) mod 16); Replace_Slice(Data, I, I, Replacer); Last_Position := Last_Position + 2; end if; I := I + 1; end loop; end URL_Encode; function URL_Encode(Data : in Unbounded_String; Translate_Plus : Boolean := False) return Unbounded_String is Destination : Unbounded_String := Data; begin URL_Encode(Destination); return Destination; end URL_Encode; procedure HTML_Encode(Data : in out Unbounded_String) is I : Positive := 1; Current_Length : Natural := Length(Data); Current_Character : Character; begin while I <= Current_Length loop Current_Character := Element(Data, I); -- Note: some old documents recommend translating double quote ("), -- but some browsers don't handle its replacement (") correctly -- and there's no need to encode double quote anyway. -- This encoder doesn't encode control characters, etc; since they're -- unambiguous there's no need to. if Current_Character = '&' then Replace_Slice(Data, I, I, "&"); Current_Length := Current_Length + 4; elsif Current_Character = '<' then Replace_Slice(Data, I, I, "<"); Current_Length := Current_Length + 3; elsif Current_Character = '>' then Replace_Slice(Data, I, I, ">"); Current_Length := Current_Length + 3; elsif Current_Character = '"' then -- This is problematic, because some very old browsers don't handle -- " correctly. However, we HAVE to do this, because otherwise -- attribute values will incorrectly terminate in odd places. -- It _is_ in the standard, and current versions of Netscape Navigator, -- Microsoft Internet Explorer, and lynx all handle this correctly. Replace_Slice(Data, I, I, """); Current_Length := Current_Length + 5; end if; I := I + 1; end loop; end HTML_Encode; function HTML_Encode(Data : in Unbounded_String) return Unbounded_String is Destination : Unbounded_String := Data; begin HTML_Encode(Destination); return Destination; end HTML_Encode; function HTML_Encode(Data : in String) return String is Destination : Unbounded_String := To_Unbounded_String(Data); begin HTML_Encode(Destination); return To_String(Destination); end HTML_Encode; -- Don't have an HTML_Encode with "in out String", since -- HTML_Encode needs to be able to change the length of the result. -- Perhaps someday I'll do "HTML_Decode". Patches welcome. -- As far as I can tell, HTML_Decode is a lot less needed. -- The following are public subprograms. function Get_Environment(Variable : String) return String is -- Return the value of the given environment variable. -- If there's no such environment variable, return an empty string. function getenv(Variable : chars_ptr) return chars_ptr; pragma Import(C, getenv); -- getenv is a standard C library function; see K&R 2, 1988, page 253. -- it returns a pointer to the first character; do NOT free its results. Variable_In_C_Format : chars_ptr := New_String(Variable); Result_Ptr : chars_ptr := getenv(Variable_In_C_Format); Result : String := Value_Without_Exception(Result_Ptr); begin Free(Variable_In_C_Format); return Result; end Get_Environment; function Parsing_Errors return Boolean is begin return Parsing_Errors_Occurred; end Parsing_Errors; function Argument_Count return Natural is begin if CGI_Data = null then return 0; else return CGI_Data.all'Length; end if; end Argument_Count; function Input_Received return Boolean is -- True if Input Received. begin return Argument_Count /= 0; -- Input received if nonzero data entries. end Input_Received; function CGI_Method return CGI_Method_Type is -- Return Method used to send data. begin return Actual_CGI_Method; end CGI_Method; function Is_Index return Boolean is begin return Is_Index_Request_Made; end Is_Index; function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String is My_Index : Positive := 1; begin for I in 1 .. Argument_Count loop if CGI_Data.all(I).Key = Key then if Index = My_Index then return CGI_Data.all(I).Value; else My_Index := My_Index + 1; end if; end if; end loop; -- Didn't find the Key. if Required then raise Constraint_Error; else return To_Unbounded_String(""); end if; end Value; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return String is begin return To_String(Value(To_Unbounded_String(Key), Index, Required)); end Value; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String is begin return Value(To_Unbounded_String(Key), Index, Required); end Value; function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return String is begin return To_String(Value(Key, Index, Required)); end Value; function Key_Exists(Key : in Unbounded_String; Index : in Positive := 1) return Boolean is My_Index : Positive := 1; begin for I in 1 .. Argument_Count loop if CGI_Data.all(I).Key = Key then if Index = My_Index then return True; else My_Index := My_Index + 1; end if; end if; end loop; return False; end Key_Exists; function Key_Exists(Key : in String; Index : in Positive := 1) return Boolean is begin return Key_Exists(To_Unbounded_String(Key), Index); end Key_Exists; function Key_Count(Key : in Unbounded_String) return Natural is Count : Natural := 0; begin for I in 1 .. Argument_Count loop if CGI_Data.all(I).Key = Key then Count := Count + 1; end if; end loop; return Count; end Key_Count; function Key_Count(Key : in String) return Natural is begin return Key_Count(To_Unbounded_String(Key)); end Key_Count; function Key_Value_Exists(Key : in Unbounded_String; Value : in Unbounded_String) return Boolean is My_Index : Positive := 1; begin for I in 1 .. Argument_Count loop if CGI_Data.all(I).Key = Key and then CGI_Data.all(I).Value = Value then return True; end if; end loop; return False; end Key_Value_Exists; function Key_Value_Exists(Key : in String; Value : in String) return Boolean is begin return Key_Value_Exists(To_Unbounded_String(Key), To_Unbounded_String(Value)); end Key_Value_Exists; function Key(Position : in Positive) return Unbounded_String is begin return CGI_Data.all(Position).Key; end Key; function Key(Position : in Positive) return String is begin return To_String(Key(Position)); end Key; function Value(Position : in Positive) return Unbounded_String is begin return CGI_Data.all(Position).Value; end Value; function Value(Position : in Positive) return String is begin return To_String(Value(Position)); end Value; procedure Iterate_Key (Key : in String) is My_Index : Positive := 1; begin for I in 1 .. Argument_Count loop if CGI_Data.all(I).Key = Key then Evaluate(CGI_Data.all(I).Value); end if; end loop; end Iterate_Key; procedure Iterate_CGI is My_Index : Positive := 1; begin for I in 1 .. Argument_Count loop Evaluate(CGI_Data.all(I).Key, CGI_Data.all(I).Value); end loop; end Iterate_CGI; function My_URL return String is -- Returns the URL of this script. begin return "http://" & Get_Environment("SERVER_NAME") & Get_Environment("SCRIPT_NAME"); end My_URL; procedure Put_CGI_Header(Header : in String := "Content-type: text/html") is -- Put Header to Current_Output, followed by two carriage returns. -- Default is to return a generated HTML document. begin Put_Line(Header); New_Line; end Put_CGI_Header; procedure Put_HTML_Head(Title : in String; Mail_To : in String := "") is begin Put_Line("" & Title & ""); if Mail_To /= "" then Put_Line(""); end if; Put_Line(""); end Put_HTML_Head; procedure Put_HTML_Heading(Title : in String; Level : in Positive) is -- Put an HTML heading, such as

    Title

    begin Put_Line("" & Title & ""); end Put_HTML_Heading; procedure Put_HTML_Tail is begin Put_Line(""); end Put_HTML_Tail; procedure Put_Error_Message(Message : in String) is -- Put to Current_Output an error message. begin Put_HTML_Head("Fatal Error Encountered by Script " & My_URL); Put_HTML_Heading("Fatal Error: " & Message, 1); Put_HTML_Tail; New_Line; Flush; end Put_Error_Message; procedure Put_Variables is -- Put to Current_Output all of the data as an HTML-formatted String. begin Put_Line("
    ");
     for I in 1 .. Argument_Count loop
       Put("");
       Put(To_String(HTML_Encode(CGI_Data.all(I).Key)));
       Put(": ");
       Put(To_String(HTML_Encode(CGI_Data.all(I).Value)));
       Put_Line("");
     end loop;
     Put_Line("
    "); end Put_Variables; -- Helper routine - function Next_CRLF (S : in String; N : in Natural) return Natural -- Return the location within the string of the next CRLF sequence -- beginning with the Nth character within the string S; -- return 0 if the next CRLF sequence is not in the string is I : Natural := N; begin while I < S'LAST loop if S(I) = ASCII.CR and then S(I+1) = ASCII.LF then return I; else I := I + 1; end if; end loop; return 0; end; function Line_Count (Value : in String) return Natural -- Count the number of lines inside the given string. -- returns 0 if Key_Value is the empty/null string, -- i.e., if its length is zero; otherwise, returns -- the number of "lines" in Key_Value, effectively -- returning the number of CRLF sequences + 1; -- for example, both "AB/CDEF//GHI" and "AB/CDEF//" -- (where / is CRLF) return Line_Count of 4. is Number_of_Lines : Natural := 0; I : Natural := Value'FIRST; begin if Value'LENGTH = 0 then return 0; else loop I := Next_CRLF (Value, I+1); exit when I = 0; Number_of_Lines := Number_of_Lines + 1; end loop; -- Always count the line (either non-null or null) after -- the last CRLF as a line Number_of_Lines := Number_of_Lines + 1; return Number_of_Lines; end if; end; function Line (Value : in String; Position : in Positive) return String -- Return the given line position value. -- that is separated by the n-1 and the nth CRLF sequence -- or if there is no nth CRLF sequence, then returns the line -- delimited by the n-1 CRLF and the end of the string is Next : Natural := 1; Line_Number : Natural := 0; Start_of_Line, End_of_Line : Natural; begin End_of_Line := Next_CRLF (Value, 1); if End_of_Line = 0 then -- no CRLF sequence on the "line" if Position > 1 then -- raise an exception if requesting > 1 raise Constraint_Error; else -- otherwise, requesting first line -- return original string, even if null string return Value; end if; else -- There's at least one CRLF on the "line" for I in 1..Position loop Start_of_Line := Next; End_of_Line := Next_CRLF (Value, Next); -- normally, the line is Start_of_Line .. End_of_Line-1 -- if no more CRLFs on line, it's Start_of_Line .. 'LAST exit when End_of_Line = 0; Line_Number := Line_Number + 1; -- skip past the 2 chars, CRLF, to start next search Next := End_of_Line + 2; end loop; -- if we fall out of loop normally, End_of_Line is non-zero if End_of_Line > 0 then -- and Position had better be equal to Line_Number if Position = Line_Number then return Value (Start_of_Line .. End_of_Line-1); else raise Constraint_Error; end if; else -- we exit the loop prematurely because there's not -- enough CRLFs in the line, -- thus Line_Number is one less than Position if Position = Line_Number+1 then return Value (Start_of_Line .. Value'LAST); else raise Constraint_Error; end if; end if; end if; end Line; function Line_Count_of_Value (Key : String) return Natural is begin if Key_Exists (Key) then return Line_Count (Value(Key)); else return 0; end if; end Line_Count_of_Value; function Value_of_Line (Key : String; Position : Positive) return String is begin if Key_Exists (Key) then return Line (Value(Key), Position); else return ""; end if; end Value_of_Line; -- Initialization routines, including some private procedures only -- used during initialization. procedure Set_CGI_Position(Key_Number : in Positive; Datum : in Unbounded_String) is Last : Natural := Field_End(Datum, '='); -- Given a Key number and a datum of the form key=value -- assign the CGI_Data(Key_Number) the values of key and value. begin CGI_Data.all(Key_Number).Key := To_Unbounded_String(Slice(Datum, 1, Last)); CGI_Data.all(Key_Number).Value := To_Unbounded_String(Slice(Datum, Last+2, Length(Datum))); -- Don't need to translate '+' to ' ', that was done earlier. URL_Decode(CGI_Data.all(Key_Number).Key, False); URL_Decode(CGI_Data.all(Key_Number).Value, False); end Set_CGI_Position; procedure Set_CGI_Data(Raw_Data : in Unbounded_String) is -- Set CGI_Data using Raw_Data. Key_Number : Positive := 1; Character_Position : Positive := 1; Last : Natural; begin while Character_Position <= Length(Raw_Data) loop Last := Field_End(Raw_Data, '&', Character_Position); Set_CGI_Position(Key_Number, To_Unbounded_String( Slice(Raw_Data, Character_Position, Last))); Character_Position := Last + 2; -- Skip over field separator. Key_Number := Key_Number + 1; end loop; end Set_CGI_Data; procedure Set_Cookie_Position(Key_Number : in Positive; Datum : in Unbounded_String) is Last : Natural := Field_End(Datum, '='); -- Parse through the cookie raw data and put in the cookie data array -- Given a Key number and a datum of the form key=value -- assign the Cookie_Data(Key_Number) the values of key and value. begin Cookie_Data.all(Key_Number).Key := To_Unbounded_String(Slice(Datum, 1, Last)); Cookie_Data.all(Key_Number).Value := To_Unbounded_String(Slice(Datum, Last+2, Length(Datum))); -- Version 1.4 automatically URL_decoded cookies. However, the cookie -- spec does not require this, so for accuracy we won't do that and -- instead will expose the URL_Decode subprogram to do it. -- URL_Decode(Cookie_Data.all(Key_Number).Key, False); -- URL_Decode(Cookie_Data.all(Key_Number).Value, False); end Set_Cookie_Position; procedure Set_Cookie_Data(Raw_Data : in Unbounded_String) is Key_Number : Positive := 1; Character_Position : Positive := 1; Last : Natural; -- Parse through the cookie raw data and put in the cookie data array begin while Character_Position <= Length(Raw_Data) loop Last := Field_End(Raw_Data, ';', Character_Position); Set_Cookie_Position(Key_Number, To_Unbounded_String(Slice(Raw_Data, Character_Position, Last))); Character_Position := Last + 2; -- Skip over field separator. Key_Number := Key_Number + 1; end loop; end Set_Cookie_Data; function Cookie_Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String is My_Index : Positive := 1; -- Read the cookie from the browser request, -- returns the data or a null pointer if no cookie data begin if Cookie_Data /= null then for I in 1 .. Cookie_Data'Last loop if Cookie_Data.all(I).Key = Key then if Index = My_Index then return Cookie_Data.all(I).Value; else My_Index := My_Index + 1; end if; end if; end loop; end if; -- Didn't find the Key. if Required then raise Constraint_Error; else return To_Unbounded_String(""); end if; end Cookie_Value; function Cookie_Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return String is begin return To_String(Cookie_Value(To_Unbounded_String(Key), Index, Required)); end Cookie_Value; function Cookie_Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String is begin return Cookie_Value(To_Unbounded_String(Key), Index, Required); end Cookie_Value; function Cookie_Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return String is begin return To_String(Value(Key, Index, Required)); end Cookie_Value; function Cookie_Value(Position : in Positive) return Unbounded_String is begin return Cookie_Data.all(Position).Value; end Cookie_Value; function Cookie_Value(Position : in Positive) return String is begin return To_String(Value(Position)); end Cookie_Value; function Cookie_Count return Natural is begin if Cookie_Data = null then return 0; else return Cookie_Data'Last; end if; end Cookie_Count; procedure Read_Cookie is Temp_Ptr : Access_Key_Value_Sequence; Raw_Data: Unbounded_String; Number_of_Cookies : Natural; begin -- read_cookie Raw_Data := To_Unbounded_String(Get_Environment("HTTP_COOKIE")); if Raw_Data /= "" then if Element(Raw_Data, Length(Raw_Data)) = ';' then -- If there's an invalid extra trailing ";", delete it. Delete(Raw_Data, Length(Raw_Data), Length(Raw_Data)); end if; Number_of_Cookies :=Ada.Strings.Unbounded.Count(Raw_Data, Semicolon)+1; Cookie_Data := new Key_Value_Sequence(1 .. Number_of_Cookies); Set_Cookie_Data(Raw_Data); else Cookie_Data:= null; end if; end Read_Cookie; procedure Set_Cookie(Key : String; Value : String; Expires : String := ""; Path : String := Get_Environment("PATH_INFO"); Domain: String := Get_Environment("SERVER_NAME"); Secure: Boolean := False ) is -- Sends a cookie to the browser. -- Do this before sending the header for the HTML. begin Put("Set-Cookie: "); Put(Key & "=" & Value & ";"); if Expires /= "" then Put("expires=" & Expires & ";"); end if; if Path /= "" then Put("path=" & Path & ";"); end if; if Domain /= "" then Put("domain=" & Domain & ";"); end if; if Secure then put_line("secure"); else new_line; end if; end Set_Cookie; procedure Initialize is Raw_Data : Unbounded_String; -- Initially an empty string (LRM A.4.5(73)) Request_Method_Text : String := To_Upper(Get_Environment("REQUEST_METHOD")); -- Initialize this package, most importantly the CGI_Data variable. begin if Request_Method_Text = "GET" then Actual_CGI_Method := Get; Raw_Data := To_Unbounded_String(Get_Environment("QUERY_STRING")); elsif Request_Method_Text = "POST" then Actual_CGI_Method := Post; declare Raw_Data_String : String(1 .. Integer'Value(Get_Environment("CONTENT_LENGTH"))); begin Get(Raw_Data_String); Raw_Data := To_Unbounded_String(Raw_Data_String); end; else Actual_CGI_Method := Unknown; end if; Translate(Raw_Data, Mapping => Plus_To_Space); -- Convert "+"s to spaces. if Length(Raw_Data) > 0 then if Index(Raw_Data, Equals) = 0 then -- No "=" found, so this is an "Isindex" request. Is_Index_Request_Made := True; Raw_Data := "isindex=" & Raw_Data; end if; CGI_Data := new Key_Value_Sequence(1 .. Ada.Strings.Unbounded.Count(Raw_Data, Ampersands)+1); Set_CGI_Data(Raw_Data); Parsing_Errors_Occurred := False; end if; end Initialize; -- This library automatically parses CGI and cookie input on program start. -- This is a trade-off, limiting flexibility very slightly -- (in the weird case where you don't want this auto-initialization) -- but it eliminates a common error (forgetting to initialize things). -- If you really don't want auto-initialization, just remove the calls -- here and make the calls visible in the spec. Don't forget to call them! begin Initialize; Read_Cookie; end CGI; adacgi-1.6/cgi.ads0100644000175000017500000003203207535217157012150 0ustar pjbpjbwith Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package CGI is -- This package is an Ada 95 interface to the "Common Gateway Interface" (CGI). -- This package makes it easier to create Ada programs that can be -- invoked by World-Wide-Web HTTP servers using the standard CGI interface. -- CGI is rarely referred to by its full name, so the package name is short. -- General information on CGI is at "http://hoohoo.ncsa.uiuc.edu/cgi/" -- and "http://w3.org/CGI". -- Developed by (C) David A. Wheeler (dwheeler@dwheeler.com) June 1995-2000. -- This is version 1.5. -- For more information, see adacgi's home page at -- http://www.dwheeler.com/adacgi -- The worldwide name of the entire set of components is "adacgi", -- while the name of this particular Ada package is "CGI". -- LICENSE PREAMBLE: -- AdaCGI is an open source (free software) library. -- AdaCGI is released using the LGPL license along with an exception and -- clarification. You can use this library to develop proprietary programs; -- if you don't make changes to this library, there is no problem and you -- can use it as you wish. -- -- If you _DO_ make changes to this library and use the result, then those -- changes must be made available to users for further use and distribution. -- In short, you are not allowed to make changes to the library and make -- the resulting library proprietary. If you use the modified library -- for a server on the Internet, this means everyone on the Internet must -- be able to get the modified version of the library. -- -- Naturally, you can also make open source programs through this license, -- and making open source programs using this library is strongly -- encouraged (but not required). -- LICENSE: -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License (LGPL) as published by the Free Software Foundation; either -- version 2.1 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 -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser 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. -- -- As a special exception, if other files simply instantiate generics from -- this unit, or you simply link this unit with other files to produce an -- executable, this unit does not by itself cause the resulting -- executable to be covered by the GNU Lesser General Public License. This -- exception does not however invalidate any other reasons why the -- executable file might be covered by the GNU Lesser General Public License. -- -- As a clarification, when this library is used in a server serving -- a client (such as a user browser invoking a server program), -- for purposes of this license the client is executing -- the program, even when this execution occurs remotely. -- After all, the client sends the program input, causes the program to -- execute, and receives program output. -- As a consequence, if you make any modifications to this library, -- you MUST make those modifications available to all users of clients -- under the terms of this license. As described in the LGPL, those -- clients then have certain rights to redistribute the library. -- This library was inspired by a perl binding by Steven E. Brenner at -- "http://www.bio.cam.ac.uk/web/form.html" -- and another perl binding by L. Stein at -- "http://www-genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html" -- A different method for interfacing binding Ada with CGI is to use the -- "Un-CGI" interface at "http://www.hyperion.com/~koreth/uncgi.html". -- This package automatically loads information from CGI on program start-up. -- It loads information sent from "Get" or "Post" methods and automatically -- splits the data into a set of variables that can be accessed by position or -- by name. An "Isindex" request is translated into a request with a single -- key named "isindex" with its Value as the query value. -- This package provides two data access methods: -- 1) As an associative array; simply provide the key name and the -- value associated with that key will be returned. -- 2) As a sequence of key-value pairs, indexed from 1 to Argument_Count. -- This is similar to Ada library Ada.Command_Line. -- The main access routines support both String and Unbounded_String. -- See the documentation file for more information and sample programs. function Parsing_Errors return Boolean; -- True if Error on Parse. function Input_Received return Boolean; -- True if Input Received. function Is_Index return Boolean; -- True if an Isindex request made. -- An "Isindex" request is turned into a Key of "isindex" at position 1, -- with Value(1) as the actual query. -- Report the CGI Method; where possible, don't depend on this. type CGI_Method_Type is (Get, Post, Unknown); function CGI_Method return CGI_Method_Type; -- Access data as an associative array - given a key, return its value. -- The Key value is case-sensitive. -- If a key is required but not present, raise Constraint_Error; -- otherwise a missing key's value is considered to be "". -- These routines find the Index'th value of that key (normally the first one). function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return String; function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return String; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; -- Was a given key provided? function Key_Exists(Key : in String; Index : in Positive := 1) return Boolean; function Key_Exists(Key : in Unbounded_String; Index : in Positive := 1) return Boolean; -- How many of a given key were provided? function Key_Count(Key : in String) return Natural; function Key_Count(Key : in Unbounded_String) return Natural; -- Access data as an ordered list (it was sent as Key=Value); -- Keys and Values may be retrieved from Position (1 .. Argument_Count). -- Constraint_Error will be raised if Position<1 or Position>Argument_Count function Argument_Count return Natural; -- 0 means no data sent. function Key(Position : in Positive) return Unbounded_String; function Key(Position : in Positive) return String; function Value(Position : in Positive) return Unbounded_String; function Value(Position : in Positive) return String; -- The following are helpful subprograms to simplify use of CGI. function Key_Value_Exists(Key : in Unbounded_String; Value : in Unbounded_String) return Boolean; function Key_Value_Exists(Key : in String; Value : in String) return Boolean; -- Returns True if a given Key has exactly Value as one of its values. -- Iterators: through all CGI values of a given key, or all CGI values. generic with procedure Evaluate (Value : in Unbounded_String); procedure Iterate_Key (Key : in String); generic with procedure Evaluate (Key : in Unbounded_String; Value : in Unbounded_String); procedure Iterate_CGI; -- Useful output routines: procedure Put_CGI_Header(Header : in String := "Content-type: text/html"); -- Put CGI Header to Current_Output, followed by two carriage returns. -- This header determines what the program's reply type is. -- Default is to return a generated HTML document. -- Warning: Make calls to Set_Cookie before calling this procedure! procedure Put_HTML_Head(Title : in String; Mail_To : in String := ""); -- Puts to Current_Output an HTML header with title "Title". This is: -- _Title_ -- -- -- If Mail_To is omitted, the "made" reverse link is omitted. procedure Put_HTML_Heading(Title : in String; Level : in Positive); -- Put an HTML heading at the given level with the given text. -- If level=1, this puts:

    Title

    . procedure Put_HTML_Tail; -- This is called at the end of an HTML document. It puts to Current_Output: -- procedure Put_Error_Message(Message : in String); -- Put to Current_Output an error message. -- This Puts an HTML_Head, an HTML_Heading, and an HTML_Tail. -- Call "Put_CGI_Header" before calling this. procedure Put_Variables; -- Put to Current_Output all of the CGI variables as an HTML-formatted String. -- Miscellaneous Routines: function My_URL return String; -- Returns the URL of this script. function Get_Environment(Variable : in String) return String; -- Return the given environment variable's value. -- Returns "" if the variable does not exist. -- Multi-Line data support: function Line_Count (Value : in String) return Natural; -- Given a value that may have multiple lines, count the lines. -- Returns 0 if Value is the empty/null string (i.e., length=0) function Line_Count_of_Value (Key : String) return Natural; -- Given a Key which has a Value that may have multiple lines, -- count the lines. Returns 0 if Key's Value is the empty/null -- string (i.e., length=0) or if there's no such Key. -- This is the same as Line_Count(Value(Key)). function Line (Value : in String; Position : in Positive) return String; -- Given a value that may have multiple lines, return the given line. -- If there's no such line, raise Constraint_Error. function Value_of_Line (Key : String; Position : Positive) return String; -- Given a Key which has a Value that may have multiple lines, -- return the given line. If there's no such line, raise Constraint_Error. -- If there's no such Key, return the null string. -- This is the same as Line(Value(Key), Position). -- Encoding and Decoding functions: procedure URL_Decode(Data : in out Unbounded_String; Translate_Plus : Boolean := True); -- In the given string, convert pattern %HH into alphanumeric characters, -- where HH is a hex number. Since this encoding only permits values -- from %00 to %FF, there's no need to handle 16-bit characters. -- If "Translate_Plus" is True, translate '+' to ' '. function URL_Decode(Data : in Unbounded_String; Translate_Plus : Boolean := True) return Unbounded_String; -- Returns the decoded value (instead of tranlating in-place) procedure URL_Encode(Data : in out Unbounded_String; Translate_Plus : Boolean := False); -- Given a string, encode to %HH all characters not URL-safe; -- if "Translate_Plus" is True, translate '+' to ' '. function URL_Encode(Data : in Unbounded_String; Translate_Plus : Boolean := False) return Unbounded_String; -- Same as procedure, but returns a new Unbounded_String. procedure HTML_Encode(Data : in out Unbounded_String); -- Given string, perform HTML encoding, so the text can be included -- in an HTML file. This means '&' becomes '&', '<' becomes '<', -- '>' becomes '>', and '"' becomes '"'. -- All other characters are untouched. -- ALL VARIABLE DATA sent from the application should be filtered through -- HTML_Encode unless it's already in HTML format or you know that -- it can't have these special characters. -- Even if the data appears to have come from the user, it should be filtered; -- the user may be unknowingly clicking though a malicious link. function HTML_Encode(Data : in Unbounded_String) return Unbounded_String; function HTML_Encode(Data : in String) return String; -- Same as procedure, but returns a new value. -- Cookie handling subprograms -- (Note that cookies are automatically read when the program starts): procedure Set_Cookie(Key : String; Value : String; Expires : String := ""; Path: String := Get_Environment("PATH_INFO"); Domain: String := Get_Environment("SERVER_NAME"); Secure: Boolean := False ); -- Sets a cookie value; call this BEFORE calling Put_CGI_Header. -- If you don't want to send values for Expires, Path, or Domain, -- just make them "". function Cookie_Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; function Cookie_Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return String; function Cookie_Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; function Cookie_Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return String; function Cookie_Value(Position : in Positive) return Unbounded_String; function Cookie_Value(Position : in Positive) return String; function Cookie_Count return Natural; -- Returns the number of cookies (0 if none) end CGI; adacgi-1.6/cgi.html0100644000175000017500000014725707535217157012365 0ustar pjbpjb AdaCGI: An Ada 95 Binding to CGI

    AdaCGI: An Ada 95 Binding to CGI

    AdaCGI (formerly called "Package CGI") is an Ada 95 interface to the "Common Gateway Interface" (CGI). AdaCGI makes it easier to create Ada programs that can be invoked by World-Wide-Web (WWW) HTTP servers using the standard CGI interface. Using it, you can create Ada programs that perform queries or other processing by request from a WWW user. Such programs are often called ``web applications'' or simply ``web apps.'' If you don't already know the advantages and disadvantages of using CGI and Ada, you might want to look at the later section titled Advantages and Disadvantages: CGI, Ada, AdaCGI.

    The website for current versions of AdaCGI is http://www.dwheeler.com/adacgi.

    This Ada package provides two data access approaches for CGI-related data:

    1. As an associative array; simply provide the key name (as a string) and the value associated with that key will be returned. Since CGI keys can duplicate, you can even ask for ``the Nth value of this key.''
    2. As a sequence of key-value pairs, indexed from 1 to Argument_Count. This access approach is similar to the Ada library Ada.Command_Line.

    The main access routines support both Ada 95 types String and Unbounded_String.


    The AdaCGI package is available in various formats, including zip, tarball (tar.gz), and RPM foramts. Again, go to the AdaCGI website to get the latest version in a variety of formats.


    This documentation assumes that you are already familiar with HTML. To use this package you'll need to learn a little about Ada 95; the Lovelace Ada 95 tutorial provides one good way to do so. It would help if you understood the Common Gateway Interface (CGI), though hopefully for straightforward web applications you won't need to.

    Below are the following sections; the ``license'' and ``advantages'' sections will hopefully help you determine if this library is right for you, the ``installation'' and ``trying out'' sections will help you get started, and the rest (including the example) will hopefully give you enough information to be able to use it effectively:

    1. AdaCGI License.
    2. Installing AdaCGI.
    3. Trying out a sample program.
    4. Details on the Ada 95 Binding to CGI.
    5. A Minimal Example.
    6. Cookies
    7. Going Further.
    8. Contents of the AdaCGI Distribution.
    9. Limitations.
    10. Security.
    11. Advantages and Disadvantages: CGI, Ada, AdaCGI.
    12. Testimonials
    13. Related Information Sources.
    14. Version Information.


    AdaCGI License

    AdaCGI is copyright (C) 1995-2000 David A. Wheeler (dwheeler@dwheeler.com, or alternatively dwheeler@ida.org and wheeler@ida.org). AdaCGI is an open source library; the actual library is released using the LGPL license as modified by a special exception and a clarification (see the CGI specification for the actual license). You can use this library in proprietary programs but any changes to the library must stay as open source. No payment is required, but please provide credit if you use this package. The demonstration programs and this documentation are covered by the GPL.

    The special exception made to the LGPL in the AdaCGI library license is the same as that used by many Ada libraries, including the GNAT (gcc-based) Ada compiler library and GtkAda. This exception eliminates the requirement to create special object files to permit re-linking new libraries. While this requirement is desirable, it's onerous to do using today's heavily optimizing compilers and hard to do with generics, so this exception is common in Ada open source programs.

    The clarification states that any user who uses the server remotely still has the right to acquire the source of this library as used by the serving program. The clarification was added because, as an interface to the web, the issue of "who is executing this program" could be a source of confusion. If you allow users to run your program, then you can't make the library proprietary from them.


    Installing AdaCGI

    If you use an RPM-based Linux system (e.g., Red Hat Linux), just get and install the RPM file as usual. For example, on a Linux i386-derived system (including Pentiums), you can get the precompiled file and just run:
     rpm -Uvh adacgi-*.i386.rpm
    

    The RPM installs the source files in the directory /usr/lib/ada/adainclude, the compiled files in /usr/lib/ada/adalib, top-level documentation in /usr/doc/adacgi-*, and the sample programs in /usr/doc/adacgi-*/sample (this is different than older RPMs, which for example used ``gnat'' instead of ``ada''). Detailed HTML format documentation is integrated into the standard Ada documentation tree; the curious might want to know that this tree begins at /usr/share/ada/html/adacgi. The precompiled library depends on the Ada GNAT runtime library; you can get you can get these and other files from the Ada for Linux website. Note that a renaming of the GNAT RPMs has taken place, starting at GNAT version 3.12p release 9; this AdaCGI RPM requires at least this version.

    At the time of this writing I don't have a Debian (.deb) format for Debian-based systems (such as Debian and Corel), sorry. You can use the Unix-like instructions (below) to install it. It's been reported to me that ``alien'' translates adacgi into a Debian package fairly well by doing:

      alien --to-deb adacgi-*.i386.rpm
    
    This isn't perfect, for example, /usr/share/doc is now used instead of /usr/doc. However, it's been reported to work. Even better, please provide me with such a packaging!

    Warning: If you've installed older versions of AdaCGI in 'zip' or 'tar.gz' format, please note that the packaging conventions have changed slightly. This version of AdaCGI automatically unpacks itself into a subdirectory with the name of the version as part of the directory name, following standard distribution-making conventions. Older versions of AdaCGI unpacked themselves into the current directory, which while convenient for some was inconvenient for others and was not what most distributions do.

    On a Unix-like system where you're not using the RPM format, get the tarball, create and move into a new directory, and install as usual. If you use the GNU tools (e.g., essentially any Linux system):

      tar xvfz adacgi-*.tar
    
    Otherwise, if you're using a Unix-like system, the commands should work fine (you may need to install a version of ``gunzip'' first):
      gunzip adacgi-*.tar.gz
      tar xvf adacgi-*.tar
    
    On a Microsoft-based platform, get the zip file, create and move into a new directory, and install as usual, using a command like this (you might have ``unzip'' instead of ``pkunzip''):
      pkunzip adacgi-*.zip
    

    If you want to use the demonstration programs, then you need to compile them. If you're using the RPM version, first copy the demonstration programs to some other directory:

     mkdir adacgisample
     cp /usr/doc/adacgi*/sample/* adacgisample
     cd adacgisample
    
    For other formats, just move into the directory with adacgi. Then, for any format, type "make" to build the programs. This assumes that you have a suitable Ada compiler installed, of course; the files use the GNAT naming convention and assume that the compiler can be invoked using ``gnatmake''; adjust for your local situation.

    The files cgi.ads and cgi.adb are the actual library; the other files are documentation and example programs. At this time only the RPM files automatically install themselves in a library directory; on other systems you'll need to compile the library into a shared area or simply include the library as part of your server's source code directory. The last "make" only compiles the sample programs.

    If during compilations you get messages like "getenv not found", you probably need to add the C library to the list of searched libraries. On most systems, that's automatic, but it isn't for ObjectAda. Anthony A. Lowe sent in this tip for ObjectAda users:

    Basically the key to making this work in ObjectAda is to add the Win32 library to the search path (in Project-Settings-Search). Once it is there, it links fine.

    Trying out a sample program

    To actually use this library, you need to write a program (this is, after all, only a library!), test the program, and then install it so it will be invoked by your web server. Included are some sample programs so you can try things out and see how the library works.

    Impatient to do something? Well, compile the demonstration programs as described above, and then run the "minimal" program by typing:

      ./minimal
    

    The output will look like this:

    Content-type: text/html
    
    <HTML><HEAD><TITLE>Minimal Form Demonstration</TITLE>
    </HEAD><BODY>
    <FORM METHOD=POST>What's your Name?<INPUT NAME="username">
    <INPUT TYPE="submit"></FORM>
    </BODY></HTML>
    
    The first line means that the program is returning an HTML file (the common case). The second (blank) line means that there is no more meta-information about the data to be returned to the user (such as cookies to be set). The rest of the lines are a tiny HTML file, which in this case presents a trivial form.

    Notice that no web server is required here; we can just invoke the program directly. That's really handy in debugging, because sometimes when you're interacting with a buggy server program it's hard to determing why things are failing unless you can see EXACTLY what is being sent back.

    So, how can we send data to this script? The answer is by setting the REQUEST_METHOD and QUERY_STRING environment variables. Setting the REQUEST_METHOD variable to GET causes the library to get its data from the QUERY_STRING variable. This QUERY_STRING environment variable is of the form "fieldname=value"; if there's more than one field, the entries should be separated by ampersands (&). If you want the values "=", "&", " ", or "%" in the value, write them as "%3D", "%26", "%20", and "%25" respectively using the standard URL escaping mechanism (i.e., characters are replaced with % followed by 2 hexadecimal digits). On Unix-compatible systems running an sh-compatible shell (including Linux running bash), just do the following:

      REQUEST_METHOD="GET"
      export REQUEST_METHOD
      QUERY_STRING="name=David%20Wheeler&email=dwheeler@dwheeler.com"
      export QUERY_STRING
    

    Now, when you re-run ./minimal, you'll see that the program instead simply lists all of the fields that you've sent and their data.

    So, how could you get this running through a web server? Well, you'll need to copy this program into an area that the web server accepts for executables. By implication, that means that your web server will have to be configured to run programs in certain directories and that you have permission to write to such a directory. On a typical Linux system running the Apache web server, such a directory is probably called "/home/httpd/cgi-bin", and is writable by root, so on such a configuration you'd do this to make the server "minimal" available to all:

      su
      cp minimal /home/httpd/cgi-bin
    

    Assuming that your web server will run programs and you've installed your server in an appropriate place, now you need to try it out. Start up a web browser and open up:

      http://localhost/cgi-bin/minimal
    
    replacing "localhost" with the name of the machine the web server is at if it's not your local machine. You should see a request to enter your name, a text box for entry, and a submit button. You can provide preset values to it by opening the URL using a format like:
      http://localhost/cgi-bin/minimal?name=David%20Wheeler&email=dwheeler@dwheeler.com
    

    You can also see the screenshot showing the demo.adb program in action.

    You can also try out the more useful "search.adb" sample program, which lets the user specify a file to search and a string; the search program then lists every line in that file containing the string. Search requires a list of files that can be searched, called the "srchlist"; copy the demo file 'srchlist' to some useful location (I suggest /home/httpd/srchlist) and edit the srchlist file to be useful to you. The srchlist format is:

       <FILENAME>,<EXTERNAL NAME>
    
    where <FILENAME> is the local filename, and <EXTERNAL NAME> is the name that the user will see. The comma is the separator; that means that filenames can't have commas in them, sorry. Note that this is both a convenience and a security measure; users only see an easy-to-read external name, and only files that are specifically listed as searchable can be searched. You'll then need to set up reasonable files to search; I've included /usr/dict/words as a sample entry because many systems have such a file.

    If you aren't going to place "srchlist" at /home/httpd/srchlist, then edit the program "search.adb" to change Search_List_Filename to some other value. Then compile "search.adb" (with GNAT, a "gnatmake search" will do nicely). Copy the resuling "search" executable to where the web server can use it (usually that would be /home/httpd/cgi-bin). Now send your browser to http://localhost/cgi-bin/search, and you should see a form that lets you search.


    Details on Ada 95 Binding to CGI

    Now, let's talk about how to write your own programs using this library.

    To use package CGI, "with CGI" in your Ada program. Package CGI will automatically load the CGI information when your Ada program begins executing. CGI handles both "GET" and "POST" forms of CGI data automatically. The form information from a GET or POST form is loaded into a sequence of variables; each variable has a Key and a Value. Package CGI transforms "Isindex" queries into a form with a single key (named "isindex"), and the key's value is the query value.

    Once the main Ada program starts, it can make various calls to the CGI subprograms to get information or to send information back out.

    A typical program using package CGI would first call "CGI.Put_CGI_Header", which tells the calling HTTP server what kind of information will be returned. Usually the CGI header is a reply saying "I will reply a generated HTML document", so that is the default of Put_CGI_Header, but you could reply something else (for example, a Location: header to automatically redirect someone to a different URL; see the CGI specification for information about references which allow you to redirect browsers elsewhere).

    Most CGI programs handle various types of forms, and most should automatically reply with a blank form if the user hasn't provided a filled-in form. Thus, your program will probably call CGI.Input_Received, which returns True if input has been received (and otherwise it returns False). You should reply with a blank form if CGI.Input_Received is False.

    You can then use various routines to query what data values were sent. You can query either by the name of a variable (what is the value of 'name'?) or by position (what was the first variable's key name and value sent?):

    • To query by variable name, use the "Value" function with the variable name as its parameter. Normally if the variable wasn't sent you'll just get an empty string back, but you can call Value with Required=>True to cause the exception Constraint_Error to be raised if the variable was not sent. To determine if given a key was sent, you can also use Key_Exists, which will return True if the given key was sent (and False otherwise). A given key can have more than one value; you can use the "Index" parameter to return the Nth value of a given key (the default is to return the first value). Function Key_Count will return how many values there are for a given key.
    • To query by position, use the "Value" function with a Positive to get that value and the "Key" function to get the variable name. For example, Value(1) is the value of the first variable and Key(1) is the name of the first variable. The number of values sent is stored in CGI.Argument_Count.

    There are also a number of useful output functions:

    • Procedure Put_Variables is useful while debugging; it will cause all form values sent to be printed (in HTML format) to the Current_Output.
    • Procedure Put_HTML_Head will put out an HTML header. It is given a title and an optional Mail_To email address.
    • Procedure Put_HTML_Heading will put out an HTML heading (such as <H1 ...> Title </H1>).
    • Procedure HTML_Encode will encode characters special to HTML so that they'll pass through unharmed. When generating HTML, always pass variable data through HTML_Encode if it isn't already HTML formatted. If you don't do this, data with the characters &, <, >, and " may become garbled (since these characters have special meaning in HTML).
    • Procedure Put_HTML_Tail will put out an HTML tail, (</BODY></HTML>).
    • Procedure Put_Error_Message will put an error message (including an HTML_Head, an HTML_Heading, and an HTML_Tail). Call "Put_CGI_Header" before calling this.

    Function Get_Environment simply calls the underlying operating system and requests the value of the given operating system variable; this may be useful for acquiring less-often-used CGI values. If the variable does not exist, function Get_Environment replies with a null string ("").


    Minimal Example

    Here is a minimal example. Procedure "Minimal" always replies with an HTML document. If input is received, the document is simply a list of the variable values. If no input is received, procedure Minimal replies with a simple fill-in form:

    with CGI, Text_IO; use CGI, Text_IO;
    
    procedure Minimal is
    -- Demonstrate CGI interface.
    
    -- To run this program directly (without an HTTP server), set the
    -- environment variable REQUEST_METHOD to "GET" and the variable
    -- QUERY_STRING to either "" or "x=a&y=b".
    
    begin
      -- First, declare that we'll regurn a generated HTML document:
      Put_CGI_Header;
      -- Now send the top of a typical HTML document, which is
      --    <HTML><HEAD><TITLE>title</TITLE></HEAD><BODY>
      Put_HTML_Head("Minimal Form Demonstration");
      if CGI.Input_Received then  -- Check if input was received.
        Put_Variables;  -- Input received; show all variable values.
      else
        -- No input received; reply with a simple HTML form.
        Put_Line("<FORM METHOD=POST>What's your Name?<INPUT NAME=""name"">" &
                 "<INPUT TYPE=""submit""></FORM>");
      end if;
      Put_HTML_Tail;  -- End the HTML document, sending </BODY></HTML>
    end Minimal;
    
    Procedure Minimal is stored in file minimal.adb. More sophisticated sample programs are demo.adb and search.adb.


    Cookies

    Cookies are supported by this package. A "cookie" is simply a value sent by a web server to a web browser; from then on, the web browser will respond with that value when reconnecting with that server. You should be aware that cookies can be used to reduce user anonymity, so some users intentionally disable cookies (see the references below for more about cookie controversies). Also, cookie data is intended to be small; a web user might not store more than 20 cookies per server, cookies larger than 4K, or 300 cookies total. If you need more, just store an ID with the cookie and store the rest of the data on the server.

    To set a cookie's value in a remote browser, call Set_Cookie with the appropriate parameters. Note that Set_Cookie must be called before Put_CGI_Header. The expires attribute specifies when the cookie will no longer be stored; the domain attribute determines which host names will cause the cookie to be sent (at least two domain levels); the path attribute specifies the subset of URLs in a domain where the cookie will be returned; and if the cookie is marked secure, the cookie will only be sent over encrypted channels (e.g., SSL, using https://).

    Cookie values are automatically loaded by this package on initialization. You can retrieve their values by calling Cookie_Value. You can retrieve cookies by their key value or by simple index. Just like CGI form fields, a key can occur multiple times. Information other than the key and value (such as expiration time, domain, path, and secure setting) is not available through AdaCGI, because this information is not sent in the underlying protocol from the user to the web server.

    You can send cookie values to your program without using a web server by setting the environment variable HTTP_COOKIE. This has the format "key=value", separated by a semicolon, using URL escapes. The distribution includes a sample program, cookie_test, that prints the "first" cookie and the first value of the cookie named "problem". Here's how to try it out on a Unix-like machine using an sh-like command shell (e.g., a typical Linux system):

      HTTP_COOKIE="first_cookie=first_value;problem=my%20problem"
      export HTTP_COOKIE
      ./test_cookie
    


    Going Further

    Many CGI applications display a number of forms, data, and so on. For larger applications, I suggest drawing a sort of ``state diagram'' showing the different displays as the nodes and showing the expected transitions between displayes. For each display, identify what information is needed for it; make sure that all the ways to reach that display will provide that information. In many cases I find it useful to have some CGI variable indicate the form desired (say ``command''). Remember that HTTP is essentially stateless; if you need some data later, you'll need to send it back to the user to store, or at least store some sort of identifier so that you can determine which user's data to use. Also, users can hop directly into any point by bookmarking things or just writing their own URLs, so don't depend on users only going through an ``expected path.''


    Contents of AdaCGI Distribution

    File adacgi.zip is the distribution collection of AdaCGI. It contains the following files:

    cgi.html      - Documentation for AdaCGI.
    cgi-doc.htm   - A duplicate of cgi.html (see README for an explanation).
    cgi.ads       - The Ada 95 package specification for the AdaCGI library.
    cgi.adb       - The Ada 95 package body for the AdaCGI library.
    minimal.adb   - A minimal demonstration of how to use the library.
    demo.adb      - A larger demonstration of how to use the library.
    search.adb    - A larger demo that searches a set of files.
    test_cookie   - A demo for getting cookie values.
    test_send.adb - A demo for setting cookie values.
    makefile      - The makefile to compile demo and minimal using GNAT.
    README        - A short list of the files.
    

    Note: all of the text files are stored in Unix text file format. MS-DOS users will need to convert them to MS-DOS text file format (some MS-DOS text editors will do this automatically).


    Limitations

    This package has the following known limitations:

    1. Doesn't support an object-oriented or ADT interface. You might want to look at the Perl5 CGI library CGI.pm. Clearly, there's a lower-level ``indexed multikey'' type that both cookies and CGI data could be based on; the current design is due to the growth over time to support specific requests. Some future version may overhaul the whole interface; the real problem is figuring how to better handle string types (see below).
    2. It only interfaces using the standard CGI interface. It doesn't support FastCGI or other interfaces.
    3. It doesn't support generation of forms with widgets automatically set to existing values. This is easily solved by creating a higher-level package that uses this package as an interface. That way, users can access capabilities more directly or not, their choice.
    4. It automatically initializes by reading in the CGI input; in a few odd cases this is limiting (though it also eliminates a common error).
    5. The way it handles String and Unbounded_String is at times awkward; perhaps requiring users to use the "+" convention or explicit type changes would be better.
    6. The current packaging could use some improvement for ease-of-use. In particular, the current zip and tarball packaging puts all the files in the current directory; they should create a subdirectory (note that you must fix the RPM spec file to do the same). A Debian package would be nice too.


    Security

    As with all CGI programs, there are security ramifications. In general, ALWAYS check any values sent to you, and be conservative: identify the list of acceptable values, and reject anything that doesn't meet that list. Thus for strings, identify the legal characters and maximum length you'll accept, and reject anything that doesn't meet those requirements. Don't do the reverse and identify ``characters you'll prohibit,'' because you'll probably forget an important case. You may need to escape shell characters. For numbers, identify minimum and maximum values. Be very cautious about filenames; beware of filenames with ".." or "/" in them (it's best not to accept them at all, if you can).

    Since the user may not be the actual source for some variables and/or data, when generating HTML always send variable data through HTML_Encode first. That way, the presence of the special reserved characters "&", "<", ">", or """ won't cause problems for the user's browser.

    It's worth noting that Ada (and AdaCGI) can easily handle the "NIL" character (ASCII 0, represented as %00 in URLs). However, many system functions called by an Ada program assume that NIL is the end of a string, so calling system functions with such values may cause surprises. This isn't really unique to Ada; Perl can also handle NIL and has the same issues.

    If you don't already know them, examine the extant literature on the subject of CGI security. Useful resources about CGI security include Gundavaram's Perl CGI FAQ (particularly the security information), Kim's CGI book, Phillips' safe CGI material, Stein's WWW Security FAQ, and Webber's web security tips. You might find my document "Secure Programming for Linux HOWTO" useful; I include a number of CGI-relevant tips. You could also search altavista for "CGI" and "security": http://www.altavista.com/cgi-bin/query?q=%2BCGI+%2Bsecurity.


    Advantages and Disadvantages: CGI, Ada, AdaCGI

    No tool is perfect, or appropriate for all circumstances. Here are some advantages and disadvantages of CGI and Ada for web applications; look at these and other information to determine if they're a good match for your application.

    CGI is the standard interface between a web server and a web application, in the same way that HTTP is the standard interface between a web client (browser) and a web server. When using CGI there are 3 active components: the web client, the web server, and the web application (you're writing the web application). The client sends a request to the web server, the web server starts up the web application, the web server sends the request data to the web application using the CGI interface, the web application replies with data using the CGI interface, and the web server sends that data on to the web client. The web application then exits; the next client request will start a separate copy of the web application. If there are simultaneously clients making requests, then the web application will be executed more than once simultaneously (each web application serves exactly one request).

    First, let's cover alternatives to CGI for interfacing to the web, listing their advantages and disadvantages compared to CGI:

    1. FastCGI: This is an alternative interface that, instead of stopping and restarting an application on each request, keeps the web application alive and sets up a permanent communication path between web server and web application.
      • Advantages: FastCGI has better performance than CGI on start-up (since start-up time is eliminated). This ``better performance'' isn't as big a strength as you might think:
        • Modern systems can strart new processes rather quickly, so optimizing for process start-up isn't as helpful.
        • Interpreters and just-in-time compilers do have an additional start-up time, but again, this is not as helpful as you'd think. Most such systems can cache previous analyses, eliminating a lot of this time.
        • Fully compiled languages (such as typical C, C++, and Ada implementations) essentially eliminate start-up costs imposed by a language interpreter. They don't need to start-up their interpreter, they just have a tiny run-time-library startup overhead.
        Another advantage of FastCGI is that inter-application locking is potentially eliminated.
      • Disadvantages: FastCGI requires more work to develop the application (because you must correctly reset all state), the result is likely to be less robust (because the application must survive many requests), and when using FastCGI is slightly more difficult to take advantage of potential concurrency (because you have to explicitly multi-thread your server).
    2. Server-specific (proprietary) APIs
      • Advantages: These APIs can potentially provide even better performance by eliminating startup and inter-process communication costs.
      • Disadvantages: These APIs lock you into a particular web server, and your application is likely to be even less robust (because an error may take down the entire web server).
    3. Specially-implemented HTTP server. This is lots of work.
    4. Separate protocol. This is lots of work, and now you need to distribute a client.
    5. Web application servers. These are intended for ``big jobs'' - large-scale dynamic web systems with a vast number of pages driven by many databases and programs. For smaller jobs, they're often too much. If you need something like this, take a look at Zope.
    6. HTML-embedded scripting language. For smaller jobs, or jobs where you have mostly static information with small snippets of dynamic information being inserted into it, a hypertext preprocessor is useful. This enables you to stick commands into an HTML document, and have the web server run those commands. A common one is PHP. If you've used Microsoft's proprietary ASP language, you can switch to PHP using asp2php. You can use the hypertext processor commands to run an Ada program.

    For lots of people, CGI is the way to go to implement web applications. So, assuming that you've evaluated your options and decided to use CGI, let's move on.

    The next question is, why use Ada? Well, here are some advantages of using Ada for web applications:

    1. Excellent Run-Time Performance: Ada is typically compiled to machine code, so its performance is generally much better than interpreters. Ada typically runs at the same speed as C and C++; sometimes faster (since it has more information) and sometimes slower (since by default it performs lots of safety checking not built into C/C++). Thus, it's typically much faster than Perl, and faster than Java if Ada is not compiled to a typical Java Virtual Machine (JVM). Note that CGI is itself a low performance interface, so this is primarily relevant only for compute-bound processes (such as graphics generation, mathematical processes such as some cryptography applications, etc.).
    2. Excellent compile-time checking: Ada is well-known for its tight compile-time checks, which tries to eliminate many errors before the first execution. The theory here is that it's cheaper to let a machine find problems than make a human find them.
    3. Highly readable: Ada is designed to be easy to read; this is especially obvious when comparing it to Perl, but many C and C++ programs belong in an obfuscated code contest. Inscrutable code and clear code can be written in any language, but it's less work to make things clear in Ada.
    4. Increased security over C/C++: Ada by default does bounds checking on all arrays (and has the information necessary to do this quickly); C and C++ have to simulate this or use special libraries which are easily bypassed.
    5. Prefer Ada: you may prefer Ada for other reasons. Ada's the only widely-used language that combines the ability to compile to machine code, platform-independent threading, enumerations, generics, buffer overflow protection, and object-orientation in a single internationally-standardized language. Java omits enumerations, generics, and compilation to machine code (some JVMs try to get close, but there's a limiting necessary overhead); C++ omits platform-independent threading and buffer overflow protection. C lacks the C++ capabilities, and it also lacks object-orientation and generics. Whether or not having all of these capabilities simultaneously available is important depends on your application, of course.
    6. Have existing Ada applications. If you have an existing Ada application, and you want to move it to becoming a web application, using AdaCGI is a natural approach.

    Sounds like you should always use Ada, right? Nonsense - no engineering decision is ever that simple. Here are some weaknesses of Ada for building web applications:

    1. Wordiness. Ada is wordy, which is especially inconvenient for short scripts. As programs get large, I find this isn't as big a disadvantage; the wordiness is for readability and modularity, which is more important for larger programs. You may disagree.
    2. Less convenient string handling. Ada originally came with type String, which stays at a fixed length once initialized and is inconvenient for many situations. The Ada type Unbounded_String automatically handles resizing, etc., but it is used essentially always through functions and procedures. The lack of syntactic sugar for Unbounded_String makes simple operations especially wordy and can obscure what's happening. This is a problem for web scripts, because string handling often takes up a great deal of the program.
    3. No built-in regular expression system. You could use GNAT's regular expression library, which is portable to other Ada compilers, but it's not as rich as Perl's library (for example) nor can Ada compilers optimize it the way Perl can optimize regular expressions.
    4. No built-in garbage collector necessarily built in. Ada doesn't guarantee that a garbage collector will be available, and in fact most Ada implementations don't include one. For CGI, this is almost never an issue, since the CGI program will exit after servicing one request anyway (and clean up then).
    5. Fewer web-centric libraries and/or need to reuse code in another language. If there's an existing library in another language that you need, that might be an excellent reason to use that language instead. You could use external language bindings; C and Fortran bindings in particular are built into the specification of Ada. If you have to interface to a lot of such modules, though, you might be much better off using that other language instead.
    6. Compilation time delays deployment. Scripts can simply be edited and used, while for Ada a compilation step is required before use. Since compilations are quite fast nowadays, this is not a real disadvantage.
    7. Complications from installing a dynamically linked library or static code. Since Ada is usually implemented as a compiled language, it generally requires a dynamically linked library to run. That means you'll have to get that library installed (or made available to your scripts). Alternatively, you could just generate statically linked programs, but that makes the individual programs larger. If you control the web server, this is a non-issue, but it might be minor issue if you really want the run-time library installed in the ``global'' location of your system.

    At one time, Ada compilers were extremely costly ($20,000 or more), which was a serious disadvantage. Nowadays, there's an open-source no-cost high-quality implementation (GNAT) and several other inexpensive implementations, so that's no longer a relevant disadvantage.

    As always, base your decision based on the engineering trade-off.

    Finally, even if you're using CGI and Ada, you needn't use this library. See the resource section for un-CGI and WebAda CGI. However, neither of those support cookies. For specific weaknesses, WebAda CGI has buggy encoders, and un-CGI is both slower than AdaCGI and introduces data ambiguity when handling data with multiple keys. In short, I believe that if you're using Ada and CGI, AdaCGI is the library you want to use. If it isn't, please let me know why so that it can be that way again :-).


    Testimonials

    I can't thank you enough for your great creation! I have been extensively using the CGI package (version 1.5) in the last couple of weeks and have totally fallen in love with it! It is simple and does everything one could ask for! So thank you, I don't know how I could put together my project without it!

    -- Alex Gertsen (AlexGertsen@libertybay.com)


    Related Information Sources

    1. The current website for AdaCGI is http://www.dwheeler.com/adacgi.
    2. Old versions of this Ada binding to CGI are available via the Public Ada Library (PAL). The PAL card catalog provides a nice general way to find Ada components (this binding is categorized as a "software component").
    3. CGI information at the W3C.
    4. "Adding Cookies to your site" by Paul Bonner; an introduction to cookies including notes on privacy issues.
    5. Netscape's original specification on cookies.
    6. Cookie Central.
    7. General information on CGI is available from the NSCA.
    8. Package CGI is inspired by the perl CGI interface by Steven E. Brenner (S.E.Brenner@bioc.cam.ac.uk).
    9. Another source of inspiration was the perl CGI interface by L. Stein.
    10. Doug Smith uses a different interface from Ada to CGI in his WebAda program, based on an old version of AdaCGI that he modified in a different way; you can see the webada source for more information or more specifically see the CGI interface of WebAda. This CGI interface has a few small features that AdaCGI doesn't, such as key removal, generic iterators, and encoders (though last I looked, the HTML encoders didn't handle ampersand correctly). However, AdaCGI has other significant features, such as Cookie support, and has a raft of documentation. I also think AdaCGI's easier to use; WebAda CGI splits into so many child packages that it's more work to use. Hopefully, these two interfaces will merge in the future.
    11. Dale Stanbrough's CGI programming in Ada site has related information. (Ada Home calls this site ``Ada CGI'', which can be confusing). However, Dale's package does something different -- it doesn't create an interface with CGI, it creates a programmatic interface for generating HTML. Dale's package itself is called ``HTML'', and can easily be used in conjunction with AdaCGI (as his example does).
    12. A different method for interfacing binding Ada with CGI is to use the "Un-CGI" interface.
    13. Many Ada resources are available through the Ada Home, including an on-line Ada 95 reference manual and a free on-line Ada 95 tutorial, Lovelace.
    14. Ada Power is another useful Ada site.
    15. The Ada for Linux team has useful Linux-specific information.
    16. GNAT, a no-cost Ada 95 compiler, is available through New York University (NYU).
    17. You can download an `unzip' program from the Info-ZIP archives, which has software to unzip files as well as create zip files (including both a free implementation and the shareware pkzip/pkunzip programs). The Info-ZIP archive index lists what files are available., An alternate (mirror) site for these zip format utilities is wuarchive.wustl.edu.


    Version Information

    This is version 1.6.

    • Fixed an error in Hex_Value found and fixed by Pascal Obry. The internal function Hex_Value had a line reading ``1.. H'Length'', which should have been ``H'Range'' instead. This could cause URL decoding to fail.
    • Fixed a minor problem in cgi.adb that prevented ObjectAda from compiling the library. I had pragma Inline after the end of the function declaration; by moving it to right after the "is", ObjectAda became happy. Thanks to Lionel Draghi for reporting the problem (and the fix).
    • Added testimonial.
    • Added note that ``alien'' does a reasonable job converting this RPM to Debian format.

    For version 1.5:

    • All AdaCGI library routines have been modified so that any generated HTML is also valid XML. In particular, all tags are now lower case. This also caused a minor reformatting of Put_Variables so that its results would be valid XML and HTML (the <br> command doesn't easily work with both HTML and XML across all platforms at this time). This does not mean that somehow a program magically generates both valid XML and valid HTML if they just use this package; it just means that it's possible. See the specifications at the W3C for the requirements you have to meet if you wish to do this. Also, note that Put_HTML_Head does not autoamtically generate the official header to indicate that the following text is HTML (and which version) or XML (and which version); you may wish to Put_Line such a header. A future version of Put_HTML_Head may do this.
    • Added Cookie_Count, so you can find out how many cookies are available.
    • Changed the behavior of cookie results: cookie values are no longer automatically URL-decoded (CGI values continue to be automatically decoded by the package). This means that, if you depended on adacgi version 1.4 behavior, your program will need to insert calls to URL_Decode after requests for the cookie's value. The reason for this backwards-incompatible change is that I found that the cookie specification does not require URL encoding of cookies. While in some cases URL encoding is desirable, automatically decoding cookies could produce wrong results when interoperating with other scripts. The main issue is that, if you don't encode them in some way, semicolons in particular cannot be in cookies. You might consider encoding in the same way as CGI values are encoded, that is, URL encoding. However, these are merely suggestions; the actual interface permits as much freedom as the underlying protocol supports, aiding interoperability.
    • An HTML encoding subprogram (HTML_Encode) is now available, which is very useful when generating an HTML document. This subprogram takes a string and translates "&" to "&amp;", "<" to "&lt;", ">" to "&gt;", and the double-quote character to "&quot;". All other characters (including control characters) are untouched. It is HIGHLY recommended that all variable data being sent in HTML go through this filter; if you don't, data that has these special characters may cause the browser to become confused and display data incorrectly. I haven't developed an "HTML decoding" subprogram as part of AdaCGI; a future version of AdaCGI may add this. Such a subprogram would have to handle the many more HTML escapes, however, and it's not clear how to represent some of them (e.g., "&nbsp;" can be represented in Unicode but can only be represented in the Character type using other encodings like UTF-8).
    • URL encoding and decoding subprograms are now available. The "URL" encoding is useful when dealing with CGI headers, generating follow-on URLs, processing cookie values, and other purposes. The subprogram URL_Encode walks through a string and, for each character that isn't URL-safe, replaces it with "%" and a 2-digit hexadecimal number. The URL-safe characters are English letters, digits, and the URL-safe symbols ("_", ".", "!", "~", "*", "'", "(", ")"). Thus "%" becomes "%25" and "&" becomes "%26". Some systems translate space into "+", while others translate to "%20"; the encoder lets you choose. URL decoding reverses the process (and handles both "+" and "%20" as space). All CGI values are internally sent in this format, but it's sometimes useful to use these programs directly. If you're dealing with International character sets, I recommend that you use UTF-8 encoding first, then use URL encoding if you're using URL encoding. These functions were inspired by Doug Smith's version of AdaCGI in his WebAda program (though it turns out his functions had many errors; hopefully these are correct!).
    • Added Key_Value_Exists, a quick way to tell if a Key has been given a specific Value (as one of its values).
    • The documentation was modified, adding more information on how to create secure CGI programs. In particular, links to the variety of CGI security information were added. Too many people create insecure CGI programs, even though techniques for avoiding most of their errors are widely known. I hope that linking to this information will make it easier for people to learn how to make secure CGI programs.
    • Improved the "search.adb" example so it's easier to understand. In particular, I made Generate_Blank_Form a separate procedure and I added more explanatory comments. I also modified it so that it's more likely to be useful ``out of the box.'' In particular, the default search file location is now /home/httpd/srchlist (a reasonable location on many systems). The search file list provided (and can be easily installed there) includes the English word dictionary file available on many Unix-like systems; this way, many users of Unix-like systems can easily play with the demo. Windows users, don't dispair; the program can be easily configured for your systems too.
    • Hyperlink fixes: fixed the broken link to Un-CGI, added another link for WebAda CGI, added a reference to Dale Stanbrough's package.
    • Made Put_Error_Mesage flush itself, so that errors would be more likely to reach the people who needed to see them.

    Version 1.4 was released 21-Oct-1999. I changed the library license to the LGPL with minor additions as described in cgi.ads. I don't mind proprietary products using this library, but if they make improvements to this component and "release" its use to users I want EVERY user to be able to get the improvements. I also changed the documentation license to be a straight GPL license. All the demo programs are (C) 1995-1999 David A. Wheeler, licensed under the GPL license. The name of the packaged collection of files was changed to "AdaCGI", to clearly differentiate it from non-Ada CGI interfaces (the actual Ada package is still named "CGI", for backwards compatibility; after all, there's no ambiguity when calling from Ada :-) ). The program "minimal.adb" was changed to be more aesthetically pleasing (in particular, the submit button comes AFTER the data request). This version includes a patch by Juergen Pfeifer (Juergen.Pfeifer@t-online.de) that fixed an ambiguity in search.adb; it also makes use of his RPM packaging. I also added a patch by Bob Holcomb (bob_holcomb@hotmail.com) to directly support cookies, and modified his patch to eliminate a bug involving semicolons in cookie values. I added a major documentation section on how to start using the program (the "trying out" section).

    Version 1.3 fixes a nasty bug in the low-level "getenv" routine, which kept this program from working on OS/2 and some other systems.

    Version 1.2 added routines which get a Value and then get a Line or Line_Count all at once, developed by Clyde Roby (roby@ida.org). The Ustrings package (used by the search demo) has had two minor changes: Put_Line to a designated file now works correctly (instead of putting to the current output), and Get_Line can read in a line up to the maximum length of an Unbounded_String.

    Major additions in version 1.1 are:

    • Added Index parameter to Value(Key) so multi-valued keys could be handled. Also added Key_Count, which returns the number of values for a given key.
    • Added routines (Line and Line_Count) to help handle multi-line text values.

    Version 1.0 was released June 1995.

    This documentation is (C) 1995-1999 David A. Wheeler. This documentation is free; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

    This documentation 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 General Public License for more details.

    You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    David A. Wheeler (dwheeler@dwheeler.com / dwheeler@ida.org)
    adacgi-1.6/demo.adb0100644000175000017500000000356307535217157012320 0ustar pjbpjbwith CGI, Text_IO; use CGI, Text_IO; procedure Demo is -- Demonstrate CGI interface. See the examples at -- http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html -- To run this program directly (without an HTTP server), set the -- environment variable REQUEST_METHOD to "GET" and the variable -- QUERY_STRING to either "" or "name=David&topping=anchovies&callfirst=no". begin Put_CGI_Header; if CGI.Input_Received then Put_HTML_Head("Form Result of Demo Ada 95 Binding to CGI"); Put_HTML_Heading("Form Result of Demo", 1); Put_Line("

    Your name is " & HTML_Encode(Value("name")) & ""); Put_Line("

    The keys and values sent were:

    "); Put_Variables; else Put_HTML_Head("Demonstration of Ada 95 Binding to CGI"); Put_HTML_Heading("AdaCGI Demonstration Form", 1); Put_Line("

    This form demonstrates an Ada 95 binding to CGI.

    "); Put_Line("

    "); Put_Line("What is your name: "); Put_Line("

    What topping would you like on your pizza?

      "); Put_Line("
    1. Pepperoni."); Put_Line("
    2. Sausage."); Put_Line("
    3. Anchovies."); Put_Line("
    "); Put_Line("Would you like us to call ahead?"); Put_Line("
    "); Put_Line("
    Yes."); Put_Line("
    " & "No."); Put_Line("
    "); Put_Line("

    "); Put_Line("

    "); end if; Put_HTML_Tail; end Demo; adacgi-1.6/exclude0100644000175000017500000000003107535217157012263 0ustar pjbpjbadacgi.zip adacgi.tar.gz adacgi-1.6/gpl.txt0100644000175000017500000004312707535217157012247 0ustar pjbpjb GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. adacgi-1.6/lesser.txt0100644000175000017500000006347407535217157012771 0ustar pjbpjb GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! adacgi-1.6/makefile0100644000175000017500000000516507535217157012424 0ustar pjbpjb# This makefile automates generates the CGI demo programs and # compressed files. VERSION=1.6 # By default, compile all of the demo programs: all: demo minimal search test_cookie test_send test_encode demo: FORCE gnatmake demo.adb minimal: FORCE gnatmake minimal.adb search: FORCE gnatmake search.adb test_cookie: FORCE gnatmake test_cookie.adb test_send: FORCE gnatmake test_send.adb test_encode: FORCE gnatmake test_encode.adb # "FORCE" just forces the depending rule to always be run. # In particular, we always want to invoke gnatmake, which then checks to see if # anything needs recompiling. FORCE: clean: /bin/rm -f demo getdemo minimal search test_get test_cookie \ test_encode test_send *.o *.ali *.BAK # "make distribute" makes the files for re-distribution. # Note that the "distribute" rule explicitly requires GNU tar, since # GNU tar has the "--name-prefix" option. See the "Software Release Practice # HOWTO" at http://www.linuxdoc.org if you need to eliminate GNU dependencies. # Switch to this (need to anyway for zip files): # @ls $(SRC) | sed s:^:foobar-$(VERS)/: >MANIFEST # @(cd ..; ln -s foobar foobar-$(VERS)) # (cd ..; tar -czvf foobar/foobar-$(VERS).tar.gz `cat foobar/MANIFEST`) # @(cd ..; rm foobar-$(VERS)) distribute: clean # weblint -e bad-link -e upper-case -e mailto-link -x netscape *.html echo "Note: only distributing filenames matching [a-zA-Z]*" chmod ugo+r [a-zA-Z]* chmod g-w [a-zA-Z]* rm -f adacgi-*.zip adacgi-*.tar.gz *.BAK *.rpm # tar --name-prefix='adacgi-$(VERSION)/' -cvf - [a-zA-Z]* > adacgi.tar cd ..; \ tar -cvf - adacgi-$(VERSION)/[a-zA-Z]* > adacgi-$(VERSION).tar ; \ gzip --best adacgi-$(VERSION).tar cd ..; zip -9 adacgi-$(VERSION).zip adacgi-$(VERSION)/[a-zA-Z]* mv ../adacgi-$(VERSION).tar.gz . mv ../adacgi-$(VERSION).zip . chmod ugo+r *.zip *.tar.gz chmod g-w *.zip *.tar.gz # uuencode cgi.tar.gz cgi.tar.gz > cgi.tar.gz.uu # uuencode cgi.zip cgi.zip > cgi.zip.uu # more readme *.html *.htm *.ads *.adb makefile > cgi.email echo "If all has gone well, run 'make RPM' as root." RPM: cp adacgi-$(VERSION).tar.gz /usr/src/redhat/SOURCES cp adacgi.spec /usr/src/redhat/SPECS cd /usr/src/redhat/SPECS; rpm -ba adacgi.spec cp /usr/src/redhat/RPMS/i386/adacgi-*.i386.rpm /usr/src/redhat/SRPMS/adacgi-*.src.rpm . chown --reference=. *.rpm chmod g-w * # i386 version goes into /usr/src/redhat/RPMS/i386/adacgi-1.4-1.i386.rpm # Source RPM in SRPMS. # /usr/doc/adacgi-1.4 (and its sample subdirectory) # /usr/lib/gnat/adainclude gets the files cgi.ad{b,s} (source) # /usr/lib/gnat/adalib/cgi.o is the resulting binary adacgi-1.6/minimal.adb0100644000175000017500000000147107535217157013016 0ustar pjbpjb with CGI, Text_IO; use CGI, Text_IO; procedure Minimal is -- Demonstrate CGI interface. -- To run this program directly (without an HTTP server), set the -- environment variable REQUEST_METHOD to "GET" and the variable -- QUERY_STRING to either "" or "x=a&y=b". begin Put_CGI_Header; -- We will reply with a generated HTML document. Put_HTML_Head("Minimal Form Demonstration"); -- Start generating HTML. if CGI.Input_Received then -- Check if input was received. Put_Variables; -- Input received; show all variable values. else -- No input received; reply with a simple HTML form. Put_Line("
    What's your Name?" & "
    "); end if; Put_HTML_Tail; -- End the HTML document, sending end Minimal; adacgi-1.6/pal.txt0100644000175000017500000000664107535217157012241 0ustar pjbpjbThe SID for the Ada binding to CGI follows. I'd appreciate it if you would make the file cgi.html "visible" outside of the ZIP formatted file so that people can link directly to it. I plan to create many links from many non-Ada places directly to the HTML file in the PAL. --- David wheeler@ida.org ========================================================= %UNIT NAME CGI (Common Gateway Interface) %VERSION 1.0 %REVIEW CODE NR %INET ADDRESS Author's email address is wheeler@ida.org %AUTHOR David A. Wheeler IDA 1801 N. Beauregard St. Alexandria, VA 22311-1772 (703) 845-6662 %RIGHTS Approved for Public Release; Distribution Unlimited %COPYRIGHT (C) 1995 David A. Wheeler %DATE CREATED June 1995. %DATE RELEASED June 1995. %DATE LAST UPDATED June 1995. %LOCATION PAL %ENVIRONMENT Requires an Ada 95 compiler; is known to work with GNAT. The files are Unix-formatted text files. The programs run under Unix. %LIMITATIONS The CGI interface requires an operating system to support environment variables. %=CLASSIFICATION %CATEGORY LEVEL 1 %CATEGORY LEVEL 2 %CATEGORY LEVEL 3 %CATEGORY LEVEL 4 %KEYWORD CGI, Common Gateway Interface, World Wide Web, WWW, HTTP, Hypertext Transfer Protocol, binding, Ada 95. %INDEX %TAXONOMY %DEPENDENCIES None. %SEE ALSO CGI is defined at http://hoohoo.ncsa.uiuc.edu/cgi/ See the documentation file, cgi.html or cgi-doc.htm %SHORT DESCRIPTION Ada 95 binding to CGI (Common Gateway Interface). %=FILE LISTING %FILE SPECS %DIRECTORY DISPLAY %=ABSTRACT Package CGI is an Ada 95 interface to the Common Gateway Interface (CGI). This package makes it easier to create Ada programs that can be invoked by World-Wide-Web (WWW) HTTP servers using the standard CGI interface. Using it, you can create Ada programs that perform queries or other processing by request from a WWW user. This package is copyright (C) 1995 David A. Wheeler (wheeler@ida.org). You are free to use it in anything you wish without restriction or payment, but please provide credit if you use this package. This Ada package provides two data access approaches from the CGI: * As an associative array; simply provide the key name (as a string) and the value associated with that key will be returned. * As a sequence of key-value pairs, indexed from 1 to Argument_Count. This access approach is similar to the Ada library Ada.Command_Line. The main access routines support both Ada 95 types String and Unbounded_String. %=REVISION HISTORY Version 1.0, 26 June 1995. Initial release. %=RELEASE NOTICE This prologue must be included in all copies of this software. Restrictions on use or distribution: NONE However, users are requested to give credit if this package is used. %=DISCLAIMER This software and its documentation are provided "AS IS" and without any expressed or implied warranties whatsoever. No warranties as to performance, merchantability, or fitness for a particular purpose exist. The user is advised to test the software thoroughly before relying on it. The user must assume the entire risk and liability of using this software. In no event shall any person or organization of people be held responsible for any direct, indirect, consequential or inconsequential damages or lost profits. This software is not endorsed by the Institute for Defense Analyses (IDA) or the U.S. Department of Defense (DoD). adacgi-1.6/screen.html0100644000175000017500000000664407535217157013074 0ustar pjbpjbAdaCGI "Screenshot"

    AdaCGI "Screenshot"

    Many people like to see ``screenshots,'' but how do you show a screenshot of a CGI interface library? Well, here's my attempt. Below is a demonstration form, followed by the code that created it (the code is available in the file demo.adb). This basically demonstrates how the AdaCGI library can be used to create programs that work with the World Wide Web. The form is not active at this time, so selecting "submit" won't do anything useful. If you want to learn more, see the AdaCGI documentation.


    AdaCGI Demonstration Form

    This form demonstrates an Ada 95 binding to CGI.

    What is your name:

    What topping would you like on your pizza?

    1. Pepperoni.
    2. Sausage.
    3. Anchovies.
    Would you like us to call ahead?
    Yes.
    No.


    with CGI, Text_IO; use CGI, Text_IO;
    
    procedure Demo is
    -- Demonstrate CGI interface.   See the examples at 
    -- http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html
    
    -- To run this program directly (without an HTTP server), set the
    -- environment variable REQUEST_METHOD to "GET" and the variable
    -- QUERY_STRING to either "" or "name=David&topping=anchovies&callfirst=no".
    
    begin
      Put_CGI_Header;
    
      if CGI.Input_Received then
        Put_HTML_Head("Form Result of Demo Ada 95 Binding to CGI");
        Put_HTML_Heading("Form Result of Demo", 1);
        Put_Line("<P>Your name is <I>" & Value("name") & "</I>");
        Put_Line("<P>The keys and values sent were:<P>");
        Put_Variables;
      else
        Put_HTML_Head("Demonstration of Ada 95 Binding to CGI");
        Put_HTML_Heading("AdaCGI Demonstration Form", 1);
        Put_Line("<P>This form demonstrates an Ada 95 binding to CGI.<P>");
    
        Put_Line("<FORM METHOD=POST>");
    
        Put_Line("What is your name: <INPUT NAME=""name"" SIZE=40>");
    
        Put_Line("<P>What topping would you like on your pizza?<P><OL>");
        Put_Line("<LI><INPUT TYPE=""checkbox"" NAME=""topping"" " &
                 "VALUE=""pepperoni"" CHECKED>Pepperoni.");
        Put_Line("<LI><INPUT TYPE=""checkbox"" NAME=""topping"" " &
                 "VALUE=""sausage"">Sausage.");
        Put_Line("<LI><INPUT TYPE=""checkbox"" NAME=""topping"" " &
                 "VALUE=""anchovies"">Anchovies.");
        Put_Line("</OL>");
    
        Put_Line("Would you like us to call ahead?");
        Put_Line("<DL>");
        Put_Line("<DD> <INPUT TYPE=""radio"" NAME=""callfirst"" VALUE=""yes"" " &
                 "CHECKED> <I>Yes.</I>");
        Put_Line("<DD> <INPUT TYPE=""radio"" NAME=""callfirst"" VALUE=""no""> " &
                 "<I>No.</I>");
        Put_Line("</DL>");
    
    
        Put_Line("<P> <INPUT TYPE=""submit""> <INPUT TYPE=""reset""> ");
        Put_Line("</FORM>");
      end if;
    
      Put_HTML_Tail;
    end Demo;
    
    adacgi-1.6/search.adb0100644000175000017500000002310207535217157012630 0ustar pjbpjbwith CGI, Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded, Ada.Characters.Handling, Ada.Strings.Maps.Constants, Ustrings; use CGI, Text_IO, Ada.Integer_Text_IO, Ada.Strings.Unbounded, Ada.Characters.Handling, Ada.Strings.Maps.Constants, Ustrings; procedure Search is -- Search for a requested search string in a requested text file; -- the request and reply use the Common Gateway Interface (CGI) to -- an HTTP server, and then on to a user of a World Wide Web (WWW) browser. -- It's basically a web application version of "grep", with security features -- that let the server select which files a user can search. -- If a search string _and_ file name is sent, a search result is returned. -- Otherwise, the program will reply with a form to fill out. -- If some information (such as the file to search) is provided, -- the form is specialized returned to "remember" the previous values sent. -- This program can search many different files, but each file _MUST_ be -- listed in the file "srchlist". The format for the "srchlist" file -- is a list of lines with the following format: -- local_file_name,User_Name -- Here's an example of an entry in "srchlist": -- /public/addresses/phone,Phone List -- Srchlist lines beginning with "#" are comment lines and are ignored. -- To run this program directly (without an HTTP server), set the -- environment variable REQUEST_METHOD to "GET" and the variable -- QUERY_STRING to the query values, such as "" or -- "file=Phone%20List&query=David&casesensitive=no". -- Returning specialized forms takes a little extra effort since -- package CGI doesn't automatically do this; a higher-level interface -- than package CGI could simplify handling partially completed forms. -- Copyright (C) 1995-2000 David A. Wheeler -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program 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 General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- CHANGE THIS LINE TO WHEREVER YOUR SEARCH LIST FILE IS: Search_List_Filename : constant String := "/home/httpd/srchlist"; Search_List : File_Type; function User_Name(S : Unbounded_String) return Unbounded_String is X : Natural; begin X := Index(S, ","); return To_Unbounded_String(Slice(S, X+1, Length(S))); end User_Name; function Real_File_Name(S : Unbounded_String) return String is Line : Unbounded_String; begin while not End_Of_File(Search_List) loop Ustrings.Get_Line(Search_List, Line); if Element(Line, 1) /= '#' then if User_Name(Line) = S then return Slice(Line, 1, Index(Line, ",") - 1); end if; end if; end loop; return ""; end Real_File_Name; procedure Put_Matches(Filename : String; Pattern : String; Case_Sensitive : Boolean) is Found_Something : Boolean := False; Found_Here : Boolean := False; Line : Unbounded_String; Match_To : Unbounded_String; Search_File : File_Type; Clean_Pattern : String(1 .. Pattern'Length); -- Given Filename, pattern, and case sensitivity, put matches. -- This is currently implemented in a slow, inefficient way, but it's -- sufficient for the purpose for non-monstrous files. begin if not Case_Sensitive then Clean_Pattern := To_Lower(Pattern); else Clean_Pattern := Pattern; end if; if Filename = "" then Put_Line("

    Sorry, that's not a searchable file.

    "); return; end if; if Pattern = "" then Put_Line("

    Sorry, empty patterns are not permitted.

    "); return; end if; Open(Search_File, In_File, Filename); while not End_Of_File(Search_File) loop Get_Line(Search_File, Line); if not Case_Sensitive then Match_To := Translate(Line, Lower_Case_Map); Found_Here := (Index(Match_To, Clean_Pattern) /= 0); else Found_Here := (Index(Line, Clean_Pattern) /= 0); end if; if Found_Here then Put_Line(HTML_Encode(Line)); Found_Something := True; end if; end loop; if not Found_Something then Put_Line("No matches found"); end if; exception when Name_Error => Put_Line("File to search is not available"); end Put_Matches; procedure Process_Query is User_File_To_Search : constant String := CGI.Value("file"); -- Note that users can't pick the filename; instead, the user provides -- the "file" value, and the program controls the conversion to a filename. -- That way, users can't view arbitrary files. File_To_Search : constant String := Real_File_Name(U(User_File_To_Search)); Pattern : constant String := Value("query"); Case_Sensitive : Boolean := False; Case_Sensitivity : constant String := Value ("casesensitive"); begin Put_HTML_Head("Query Result"); Put_HTML_Heading("Query Result", 1); Put_Line(String'("

    The search for " & HTML_Encode(Value("query")))); Put_Line(String'(" in file " & HTML_Encode(Value("file")) & "")); if Case_Sensitivity = "yes" then Case_Sensitive := True; Put_Line(" in a case-sensitive manner"); end if; Put_Line("produced the following result:

    "); Put_Line("

    ");
        Flush;
        Put_Matches(File_To_Search, Pattern, Case_Sensitive);
        Put_Line("
    "); end Process_Query; procedure Put_Select_List is Line : Unbounded_String; First_Option : Boolean := True; Number_Of_Options : Natural := 0; begin -- Put a Selection list of legal filenames out. -- Count the number of options (non-comment lines). while not End_Of_File(Search_List) loop Get_Line(Search_List, Line); if Element(Line, 1) /= '#' then Number_Of_Options := Number_Of_Options + 1; end if; end loop; Reset(Search_List); Put("

    "); end Put_Select_List; function Open_Search_List return Boolean is begin Open(Search_List, In_File, Search_List_Filename); return True; exception when Name_Error => Put_Error_Message("Search List File is not available"); return False; when Others => Put_Error_Message("Search List File could not be opened"); return False; end Open_Search_List; procedure Generate_Blank_Form is Query_String : constant String := CGI.Value ("query"); File_Value : constant String := CGI.Value ("file"); begin Put_HTML_Head("Text Search Form"); Put_HTML_Heading("Text Search Form", 1); Put_Line("

    You may search for a text phrase"); Put_Line(" from any of the given files.

    "); Put_Line("

    "); Put_Line("What do you want to search for:

    "); Put("

    "); -- If file was set, save it in the form and note it as a fixed value. -- Otherwise, let the user pick the file to search. if Key_Exists("file") and File_Value /= "" then Put("")); Put("

    You will be searching file "); Put(String'(HTML_Encode(Value("file")))); Put_Line("

    "); else Put_Line("Where do you want to search?

    "); Put_Select_List; end if; -- If "casesensitive" set, save it in the form (invisibly). -- Otherwise, let the user choose. if Key_Exists("casesensitive") then Put(""); else Put_Line("Do you want this search to be case-sensitive?"); Put_Line("

    "); Put_Line("
    Yes."); Put_Line("
    No."); Put_Line("
    "); end if; Put_Line("

    "); Put_Line(" "); Put_Line("

    "); end Generate_Blank_Form; begin Put_CGI_Header; if not Open_Search_List then return; -- Can't open search list, don't go any further. end if; if Key_Exists("query") and Key_Exists("file") then Process_Query; else Generate_Blank_Form; end if; Put_HTML_Tail; Close(Search_List); end Search; adacgi-1.6/srchlist0100644000175000017500000000133707535217157012477 0ustar pjbpjb# This is a demonstration Search File list for search.adb. # You'll need to put this in a directory that can be accessed # by the "search" sample CGI program. # If you don't change "search.adb", this search file list # must be placed in "/home/httpd/srchlist". # # Obviously, comments in this file begin with '#' and end at the end-of-line. # # The format of this file is: # , # where is the local filename, and is the # name that the user will see. The comma is the separator; that means that # filenames can't have commas in them, sorry. # /usr/dict/words,English Word List /home/httpd/public/phone_list/my.phone.list,Phone List /home/httpd/public/addresses/acronyms,Acronyms adacgi-1.6/test_cookie.adb0100644000175000017500000000112107535217157013670 0ustar pjbpjb-- This is a short program to test getting cookie values. with Ada.Text_Io; use Ada.Text_Io; with Ada.Integer_Text_Io; use Ada.Integer_Text_IO; with CGI; use CGI; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; procedure Test_Cookie is Temp: Unbounded_String; begin Put("Number of cookies="); Put(Cookie_Count); New_Line; if Cookie_Count > 0 then Temp := Cookie_Value(1); Put("Value of first cookie: "); Put_Line(To_String(Temp)); end if; Temp := Cookie_Value("problem"); Put("Value of cookie ""problem"": "); Put(To_String(Temp)); end Test_Cookie; adacgi-1.6/test_encode.adb0100644000175000017500000000153207535217157013662 0ustar pjbpjb -- Test_Encode is a short program to permit interactively trying -- out the encodings. Setup the CGI input data, then type. with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Text_IO; use Text_IO; with Ustrings; use Ustrings; with CGI; use CGI; procedure Test_Encode is The_Line : Unbounded_String; begin Put_Line("Type in test text and press return."); Put_Line("Enter a blank line when finished."); loop Get_Line (The_Line); exit when Length(The_Line) = 0; Put (Integer'Image(Length(The_Line)) & ": "); Put_Line (The_Line); Put("HTML Encoding:"); Put_Line(HTML_Encode(The_Line)); Put("URL Encoding:"); Put_Line(URL_Encode(The_Line)); Put("URL Decoding:"); Put_Line(URL_Decode(The_Line)); end loop; end Test_Encode; adacgi-1.6/test_get.adb0100644000175000017500000000104507535217157013203 0ustar pjbpjb -- Test_Get is a short program that tests package Ustrings. with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Text_IO; use Text_IO; with Ustrings; use Ustrings; procedure Test_Get is The_Line : Unbounded_String; begin Put_Line("Type in test text and press return."); Put_Line("Enter a blank line when finished."); loop Get_Line (The_Line); exit when Length(The_Line) = 0; Put (Integer'Image(Length(The_Line)) & ": "); Put_Line (The_Line); end loop; end Test_Get; adacgi-1.6/test_send.adb0100644000175000017500000000043107535217157013353 0ustar pjbpjb-- Test sending a cookie. with Text_IO; use Text_IO; with CGI; use CGI; procedure Test_Send is begin Set_Cookie("test_key", "test_value"); Put_CGI_Header; Put_HTML_Head(Title=>"test send cookie"); Put_Line("

    This is just a test"); Put_HTML_Tail; end Test_Send; adacgi-1.6/ustrings.adb0100644000175000017500000000342007535217157013242 0ustar pjbpjbpackage body Ustrings is Input_Line_Buffer_Length : constant := 1024; -- If an input line is longer, Get_Line will recurse to read in the line. procedure Swap(Left, Right : in out Unbounded_String) is -- Implement Swap. This is the portable but slow approach. Temporary : Unbounded_String; begin Temporary := Left; Left := Right; Right := Temporary; end Swap; -- Implement Unbounded_String I/O by calling Text_IO String routines. -- Get_Line gets a line of text, limited only by the maximum number of -- characters in an Unbounded_String. It reads characters into a buffer -- and if that isn't enough, recurses to read the rest. procedure Get_Line (File : in File_Type; Item : out Unbounded_String) is function More_Input return Unbounded_String is Input : String (1 .. Input_Line_Buffer_Length); Last : Natural; begin Get_Line (File, Input, Last); if Last < Input'Last then return To_Unbounded_String (Input(1..Last)); else return To_Unbounded_String (Input(1..Last)) & More_Input; end if; end More_Input; begin Item := More_Input; end Get_Line; procedure Get_Line(Item : out Unbounded_String) is begin Get_Line(Current_Input, Item); end Get_Line; procedure Put(File : in File_Type; Item : in Unbounded_String) is begin Put(File, To_String(Item)); end Put; procedure Put(Item : in Unbounded_String) is begin Put(Current_Output, To_String(Item)); end Put; procedure Put_Line(File : in File_Type; Item : in Unbounded_String) is begin Put(File, Item); New_Line(File); end Put_Line; procedure Put_Line(Item : in Unbounded_String) is begin Put(Current_Output, Item); New_Line; end Put_Line; end Ustrings; adacgi-1.6/ustrings.ads0100644000175000017500000000367207535217157013274 0ustar pjbpjbwith Text_IO, Ada.Strings.Unbounded; use Text_IO, Ada.Strings.Unbounded; package Ustrings is -- This package provides a simpler way to work with type -- Unbounded_String, since this type will be used very often. -- Most users will want to ALSO with "Ada.Strings.Unbounded". -- Ideally this would be a child package of "Ada.Strings.Unbounded". -- -- This package provides the following simplifications: -- + Shortens the type name from "Unbounded_String" to "Ustring". -- + Creates shorter function names for To_Unbounded_String, i.e. -- To_Ustring(U) and U(S). "U" is not a very readable name, but -- it's such a common operation that a short name seems appropriate -- (this function is needed every time a String constant is used). -- It also creates S(U) as the reverse of U(S). -- + Adds other subprograms, currently just "Swap". -- + Other packages can use this package to provide other simplifications. -- Developed by David A. Wheeler; released to the public domain. subtype Ustring is Unbounded_String; function To_Ustring(Source : String) return Unbounded_String renames To_Unbounded_String; function U(Source : String) return Unbounded_String renames To_Unbounded_String; function S(Source : Unbounded_String) return String renames To_String; -- "Swap" is important for reuse in some other packages, so we'll define it. procedure Swap(Left, Right : in out Unbounded_String); -- I/O Routines. procedure Get_Line(File : in File_Type; Item : out Unbounded_String); procedure Get_Line(Item : out Unbounded_String); procedure Put(File : in File_Type; Item : in Unbounded_String); procedure Put(Item : in Unbounded_String); procedure Put_Line(File : in File_Type; Item : in Unbounded_String); procedure Put_Line(Item : in Unbounded_String); end Ustrings;