From: tlhouns@srv.PacBell.COM (Lee Hounshell)
Subject: VAR - a string class library (source)
Organization: Pacific * Bell
Date: Thu, 20 Aug 1992 01:26:12 GMT


This is "var", a C++ object library that is kinda like a "super-string" class.
The var class does a pretty good job of offering a data object that assumes
its "type" at run time, based on context of use.  Rarely will you need to
declare int's, or longs, or doubles or char[] or even string objects again!
"Var" does it all (or at least tries to).

	+ var will do base data types (eg: int, long, char *, float, string ...)
	+ var will do arithmetic
	+ var will do strings and operations on strings
	+ var will do sub-strings and operations on sub-strings
	+ var will intelligently "mix" operations between mixed types
	+ var will do formatted output using the stream library
	+ individual vars can be "staticly" typed, or they can assume
	  type at runtime, based on context.

To use this class, simply type make and a library file "libvar.a" will be
created.  This class has been used extensively here at Pacific Bell as a
base class in development of our own internal C++ class libraries. I've
even used "var" as the YYSTYPE type inside yacc/lex programs!!

If there is sufficient interest in "var" I may post a few other "base" C++
classes that I've developed.. such as an "associative array" class that uses
a "var" to index another "var."

If you like (or dislike) var, please drop me a line.
Mail bug reports and comments to:
tlhouns@srv.pacbell.com

enjoy.

-Lee



#-----------------------------------cut here----------------------------------

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by photon!tlhouns on Wed Aug 19 18:18:18 PDT 1992
# Contents:  README LEGAL_NOTICE var.3++ Makefile var.H var.C Misc.H Misc.C
#	demo.C
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'

This is "var", a C++ object library that is kinda like a "super-string" class.
The var class does a pretty good job of offering a data object that assumes
its "type" at run time, based on context of use.  Rarely will you need to
declare int's, or longs, or doubles or char[] or even string objects!
"Var" does it all (or at least tries to).

	+ var will do base data types (eg: int, long, char *, float, string ...)
	+ var will do arithmetic
	+ var will do strings and operations on strings
	+ var will do sub-strings and operations on sub-strings
	+ var will intelligently "mix" operations between mixed types
	+ var will do formatted output using the stream library
	+ individual vars can be "staticly" typed, or they can assume
	  type at runtime, based on context.

To use this class, simply type make and a library file "libvar.a" will be
created.  This class has been used extensively here at Pacific Bell as a
base class in development of our own internal C++ class libraries. I've
even used "var" as the YYSTYPE type inside yacc/lex programs!!

If there is sufficient interest in "var" I may post a few other "base" C++
classes that I've developed.. such as an "associative array" class that uses
a "var" to index another "var."

If you like (or dislike) var, please drop me a line.
Mail bug reports and comments to:
tlhouns@srv.pacbell.com

-Lee
@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - LEGAL_NOTICE
sed 's/^@//' > "LEGAL_NOTICE" <<'@//E*O*F LEGAL_NOTICE//'

        Any use of this source code must include, in the user documentation
        and internal comments to the code, and notices to the end user as
        follows:

	Copyright (c) 1992 Lee Hounshell
 
	LEE HOUNSHELL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF
        THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS"
        WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  LEE HOUNSHELL
	SEVERALLY AND INDIVIDUALLY, DISCLAIM ALL WARRANTIES WITH REGARD
	TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO
	EVENT SHALL LEE HOUNSHELL BE LIABLE FOR ANY SPECIAL, INDIRECT,
	INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
	RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
	OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
	OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.

	Permission to use, copy, modify, and distribute this software
	and its documentation for any purpose and without fee is hereby
	granted, provided that the above copyright notice appear in all
	copies and that both that copyright notice and this permission
	notice appear in supporting documentation, and that the name of
	Lee Hounshell not be used in advertising in publicity pertaining
	to distribution of the software without specific, written prior
	permission.

@//E*O*F LEGAL_NOTICE//
chmod u=rw,g=r,o=r LEGAL_NOTICE
 
echo x - var.3++
sed 's/^@//' > "var.3++" <<'@//E*O*F var.3++//'
@.po 6
@.TH VAR 3++ "1/92" "Version 1.0" "Variable Base Type String Class Library"

@.SH CLASS
VAR	\- Variable Base Type String Class Library
@.SH SYNOPSIS
@.B #include 	<var.H>
@.PP
@.nf
@.ta.5i 1.0i 4.0i
\fB
class var {

  public:
    // Constructors & Destructors
    var(void);					// constructor
    var(const varsize &);			// constructor
    var(const char *);				// constructor
    var(const char);				// constructor
    var(const short);				// constructor
    var(const unsigned short);			// constructor
    var(const int);				// constructor
    var(const unsigned int);			// constructor
    var(const long);				// constructor
    var(const unsigned long);			// constructor
    var(const double);				// constructor
    var(const var &);				// copy constructor
    ~var(void);					// destructor

    // Operators
    var & operator = (const char *);		// assignment
    var & operator = (const var &);		// assignment
    char & operator [] (const int);		// indexing
    subvar & operator () (int, int) const;	// substring
    subvar & operator () (const int) const;	// substring
    friend ostream & operator << (ostream &, const var &); // output
    friend istream & operator >> (istream &, var &); // input
    friend class subvar;			// substring

    // More Operators (used for arithmetic type extension)
    var & operator = (const char);		// assignment
    var & operator = (const short);		// assignment
    var & operator = (const unsigned short);	// assignment
    var & operator = (const int);		// assignment
    var & operator = (const unsigned int);	// assignment
    var & operator = (const long);		// assignment
    var & operator = (const unsigned long);	// assignment
    var & operator = (const double);		// assignment

    // Casting Operators
    operator char * (void) const;		// type conversion
    operator double (void) const;		// type conversion

    // Assignment Operators
    var & operator ++ (void);			// increment (pre-index only)
    var & operator -- (void);			// decrement (pre-index only)
    var operator ! (void) const;		// not

    var operator + (const var &) const;		// addition OR concatenation
    var operator - (const var &) const;		// subtraction
    var operator * (const var &) const;		// multiplication
    var operator / (const var &) const;		// division
    var operator % (const var &) const;		// remainder

    var & operator += (const var &);		// addition OR concatenation
    var & operator -= (const var &);		// subtraction
    var & operator *= (const var &);		// multiplication
    var & operator /= (const var &);		// division
    var & operator %= (const var &);		// remainder

    var & operator += (const char &);		// addition OR concatenation
    var & operator += (const char *);		// addition OR concatenation
    var & operator -= (const char *);		// subtraction
    var & operator *= (const char *);		// multiplication
    var & operator /= (const char *);		// division
    var & operator %= (const char *);		// remainder

    var & operator += (const double);		// addition OR concatenation
    var & operator -= (const double);		// subtraction
    var & operator *= (const double);		// multiplication
    var & operator /= (const double);		// division
    var & operator %= (const double);		// remainder

    friend var operator + (const char *, const var &); // addition OR concatenation
    friend var operator - (const char *, const var &); // subtraction
    friend var operator * (const char *, const var &); // multiplication
    friend var operator / (const char *, const var &); // division
    friend var operator % (const char *, const var &); // remainder
    friend var operator + (const var &, const char *); // addition OR concatenation
    friend var operator - (const var &, const char *); // subtraction
    friend var operator * (const var &, const char *); // multiplication
    friend var operator / (const var &, const char *); // division
    friend var operator % (const var &, const char *); // remainder

    friend var operator + (const var &, const double); // addition OR concatenation
    friend var operator - (const var &, const double); // subtraction
    friend var operator * (const var &, const double); // multiplication
    friend var operator / (const var &, const double); // division
    friend var operator % (const var &, const double); // remainder
    friend var operator + (const double, const var &); // addition OR concatenation
    friend var operator - (const double, const var &); // subtraction
    friend var operator * (const double, const var &); // multiplication
    friend var operator / (const double, const var &); // division
    friend var operator % (const double, const var &); // remainder

    // Equality Operators
    int operator == (const var &) const;	// equality
    int operator != (const var &) const;	// inequality
    int operator < (const var &) const;		// less than
    int operator > (const var &) const;		// greater than
    int operator <= (const var &) const;	// less than or equal
    int operator >= (const var &) const;	// greater than or equal

    friend int operator == (const var &, const char *); // equality
    friend int operator != (const var &, const char *); // inequality
    friend int operator < (const var &, const char *);  // less than
    friend int operator > (const var &, const char *);  // greater than
    friend int operator <= (const var &, const char *); // less than or equal
    friend int operator >= (const var &, const char *); // greater than or equal
    friend int operator == (const char *, const var &); // equality
    friend int operator != (const char *, const var &); // inequality
    friend int operator < (const char *, const var &);  // less than
    friend int operator > (const char *, const var &);  // greater than
    friend int operator <= (const char *, const var &); // less than or equal
    friend int operator >= (const char *, const var &); // greater than or equal

    friend int operator == (const var &, const double); // equality
    friend int operator != (const var &, const double); // inequality
    friend int operator < (const var &, const double);  // less than
    friend int operator > (const var &, const double);  // greater than
    friend int operator <= (const var &, const double); // less than or equal
    friend int operator >= (const var &, const double); // greater than or equal
    friend int operator == (const double, const var &); // equality
    friend int operator != (const double, const var &); // inequality
    friend int operator < (const double, const var &);  // less than
    friend int operator > (const double, const var &);  // greater than
    friend int operator <= (const double, const var &); // less than or equal
    friend int operator >= (const double, const var &); // greater than or equal

    // Custom Interface
    void null(int);				// "null" out string
    void changesize(int);			// change allocated memory
    int length(void) const;			// length of string
    const char * vartype(void) const;		// name of this var type
    void change_type(const char *);		// change var type
    int is_string(void) const;			// test var type
    int is_double(void) const;			// test var type
    int is_long(void) const;			// test var type
    int strchr(const char) const;		// strchr(char) index
    int strrchr(const char) const;		// strrchr(char) index
    var & concat(const var &);			// concatenation
    var & format(const char *);			// set output format
};
@.fi
\fP

@.SH DESCRIPTION
Class \fBvar\fP represents a \fBstring\fP object class that also provides all
the traditional functionality of the C base types: char, int, long, float, double, and char*.
\fBVar\fP, is in many ways a "super-string" class.
The var class does a pretty good job of offering a base data "container" object that can either
assume its "type" at run time, based on context or remain a "fixed" type, always.

@.SS var will do
@.TP 2
+
all the base data types (eg: short, int, long, char *, float, double ...)
@.TP 2
+
string types
@.TP 2
+
arithmetic
@.TP 2
+
strings and operations on strings
@.TP 2
+
sub-strings and operations on sub-strings
@.TP 2
+
intelligent "mixing" of operations between mixed types
@.TP 2
+
formatted output using the stream library

@.SH PUBLIC CONSTRUCTORS
@.SS var(void);
This constructor is used to declare an "untyped" var object.  Type is determined
at run-time, based on context of use.

@.SS var(const varsize &);
This constructor is used to declare an "string" var object, with preallocated memory.
The object's type can change at run-time, based on context.

@.SS var(const char *);
This constructor is used to declare a "string" object initialize from a "char *".
The object's type can change at run-time, based on context.

@.SS var(const char);
This constructor is used to declare an "numeric" var object, initialized from a char.
The object's type can change at run-time, based on context.

@.SS var(const short);
This constructor is used to declare an "numeric" var object, initialized from a short.
The object's type is fixed and will not change at run-time.

@.SS var(const unsigned short);
This constructor is used to declare an "numeric" var object, initialized from an unsigned short.
The object's type is fixed and will not change at run-time.

@.SS var(const int);
This constructor is used to declare an "numeric" var object, initialized from an int.
The object's type is fixed and will not change at run-time.

@.SS var(const unsigned int);
This constructor is used to declare an "numeric" var object, initialized from an unsigned int.
The object's type is fixed and will not change at run-time.

@.SS var(const long);
This constructor is used to declare an "numeric" var object, initialized from a long.
The object's type is fixed and will not change at run-time.

@.SS var(const unsigned long);
This constructor is used to declare an "numeric" var object, initialized from an unsigned long.
The object's type is fixed and will not change at run-time.

@.SS var(const double);
This constructor is used to declare an "numeric" var object, initialized from a double or float.
The object's type is fixed and will not change at run-time.

@.SS var(const var &);
This constructor is used to declare a var object, which is a copy of another var.
The object assumes the characteristics of the initializing object.

@.SS ~var(void);
The destructor returns all memory allocated by the object back to the OS.


@.SH PUBLIC OPERATORS
@.SS Arithmetic and Concatenation Operators
Most operators (+, -, /, *, %, +=, etc..) will operate as expected.
The "+" and "+=" operators will either do addition or concatenation, as appropriate.
if concatenation is required, then the \fB"var.concat(var)"\fP member function should
be used.

@.SS Relational Operators
These also operate as expected.  If "string" objects are compared, the comparison
will be as performed by \fBstrcmp(3)\fP.

@.SS The Indexing Operator []
You can index a character from inside a \fBvar\fP by using
the \fB"char & operator [] (const int);"\fP operator.
A reference to the character is returned, which can be assigned to.
Do not assign the NULL character using this operator.
Instead call the member function \fB"null(index)"\fP.

@.SS Sub-strings
Two operators are provide for substring operation.  The
first, \fB"subvar & operator () (int start, int length) const;"\fP
will extract a string starting at "start" for "length" characters.
The second, \fB"subvar & operator () (const int start) const;"\fP will
extract a string starting at "start" to the end of the string.

@.SS Type Casting
Only two type casts are required by \fBvar\fP. The first converts
the object into a "char *".  The second converts the object into a
double.  Implicit conversion between "char *" and "double" types
will be performed by your C++ compiler.

@.SS Formatted Input/Output
You can usr \fBvar\fP with the io stream library.  Object can be
both output and input using the ">>" and "<<" operators.
For formatted output, be sure to set the object's "format template"
prior to calling the ">>" operator.  (see \fB"var & format(const char *);"\fP)

@.SH PUBLIC MEMBER FUNCTIONS

@.SS Truncating a string 
The \fB"void null(int index);"\fP function will truncate a \fBvar\fP
object, starting from the specified index postion.

@.SS Memory Allocation
The \fB"void changesize(int newsize);"\fP can be used to increase
allocated memory for a var.  Memory can NOT be decreased.  Allocated
memory is returned to the heap when an object goes out of scope.

@.SS Determining Var's Length
The \fB"int length(void) const;"\fP function returns the "size" of a \fBvar\fP.

@.SS Determining Var's Type
The \fB"const char * vartype(void) const;"\fP function returns the "type" of a \fBvar\fP.
Possible types are: "VAR_STRING", "VAR_LONG" and "VAR_DOUBLE".

@.SS Explititly Changing a Var's Type
The \fB"void change_type(const char *newtype);"\fP function can be used
to set an exact type.  Valid values for "newtype" are "string", "short",
"unsigned short", "int", "unsigned int", "long", "unsigned long",
"float", and "double".

@.SS Testing a Var's Type
Three functions are provided that allow testing a \fBvar\fP type.
They are as follows: \fB"int is_string(void) const;"\fP,
\fB"int is_double(void) const;"\fP, and \fB"int is_long(void) const;"\fP

@.SS Searching for a Character
Two functions are provided that search a \fBvar\fP for a specified
character.  Both return an offset.  The first \fB"int strchr(const char) const;"\fP
searches forward.  The second, \fB"int strrchr(const char) const;"\fP
searches backward.

@.SS Concatenation
Concatenation can be forced, regardless of type with the \fB"var & concat(const var &);"\fP
function.

@.SS Setting the Output Format
The \fB"var & format(const char *fmt);"\fP function will allow you to specify an
output format.  This format will remain in effect until changed.  Printf()
style output formats can be introduced anywhere in the format statment.
Multiple formateed output directives can appear in the same "fmt".  Each
directive will receive a copy of the object.  Automatic type conversion will
occur.


@.SH AUTHOR
Lee Hounshell - 1/92

@.SH EXAMPLE
@.nf
#include	<stdlib.h>
#include	<stream.h>
#include	<var.H>

main ()
{
    var value;				// declare an "untyped" var
    value = "hello world";		// initialize it
    cout << value << endl;		// output "hello world"
    value = value(3, value.length() - 6); // substring example
    cout << value << endl;		// output "lo wo"
    value = 35;				// assignment of int
    value += 42.375;			// add 42.375 to present value
    cout << value << endl;		// output "77.375"
    cout << value.format("formatted output example %05d of value") << endl;
    cout << value.format("multiple outputs #1=%d, #2=%9.2f of value") << endl;
    value.null(2);			// truncate string
    value += " sunset strip";		// concatenate a string
    cout << value.format("%s") << endl;	// output "77 sunset strip"
    cout << value[3] << value[4] << value[5] << endl; // output "sun"
}
@.fi

@.SH SUPERCLASSES
none.

@.SH SUBCLASSES
none

@.SH BUGS
Assignment of an array of vars to another array of vars
must currently be done one elemnt at a time.

@//E*O*F var.3++//
chmod u=rw,g=r,o=r var.3++
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
############################################################################
#       make - compiles the C++ library (libvar.a) 
#       make clean - removes all .o files generated in these procedures
#       make clobber - removes all libraries, cleans up .o's
############################################################################


# from the two below, pick the operating system closest to yours:
INCDIRS = -I.

SYS	= SUN
CC	= CC
CFLAGS	= -O $(INCDIRS)
ARFLAGS	= rv


is_bsd	= test $(SYS) = SUN

all:	libvar.a

C++FILES = var.C Misc.C
INS_HFILES = var.H Misc.H
HFILES   =	$(INS_HFILES)

OBJECTS = ${C++FILES:.C=.o}

libvar.a:	$(OBJECTS)
		ar $(ARFLAGS) $@ $?
		if $(is_bsd) ; then ranlib $@; fi

$(OBJECTS):	$(HFILES)
	

clean:	
		rm -f *.o a.out core $(OBJECTS)
		cd demo; $(MAKE) clean

clobber:	clean
		rm -fr $(DOTAS)
		cd demo; $(MAKE) clobber

#####
#####
#.SUFFIXES: .o .C .C~ .c .c~
@.SUFFIXES: .o .C .C~
@.C~.C:
	-cd $(<D); $(GET) $(GFLAGS) $(<F)
@.C.c:
	$(CC) $(CFLAGS) -Fc $*.C > $*.c
@.C.o:
	$(CC) $(CFLAGS) -c $*.C
@.C~.o:
	-cd $(<D); $(GET) $(GFLAGS) $(<F)
	$(CC) $(CFLAGS) -c $*.C

@//E*O*F Makefile//
chmod u=rw,g=r,o=r Makefile
 
echo x - var.H
sed 's/^@//' > "var.H" <<'@//E*O*F var.H//'
//
// NAME:	var.H
//
// PURPOSE:	C++ Generic "Universal Variable" Class Library Header File
// AUTHOR:	Lee Hounshell
//

#ifndef VAR_H
#define VAR_H

#include	"string.h"

// -----------------------------------------------------------------------------
//
class varsize {
    // dummy class needed for var constructor of specific size that
    // doesn't conflict with the var integer type constructor
    public:
	// Constructors & Destructors
	varsize(int sz);				// constructor
	int size;					// size of var
};

class subvar;

// -----------------------------------------------------------------------------
//
class var {

    public:
	// Standard Interface
	const var & type(void) const;			// who am i

	// Constructors & Destructors
	var(void);					// constructor
	var(const varsize &);				// constructor
	var(const char *);				// constructor
	var(const char);				// constructor
	var(const short);				// constructor
	var(const unsigned short);			// constructor
	var(const int);					// constructor
	var(const unsigned int);			// constructor
	var(const long);				// constructor
	var(const unsigned long);			// constructor
	var(const double);				// constructor
	var(const var &);				// copy constructor
	~var(void);					// destructor

	// Operators
	var & operator = (const char *);		// assignment
        var & operator = (const var &);			// assignment
        char & operator [] (const int);			// indexing
        subvar & operator () (int, int) const;		// substring
        subvar & operator () (const int) const;		// substring
        friend ostream & operator << (ostream &, const var &); // output
        friend istream & operator >> (istream &, var &); // input
	friend class subvar;				// substring

	// More Operators (used for arithmetic type extension)
	var & operator = (const char);			// assignment
	var & operator = (const short);			// assignment
	var & operator = (const unsigned short);	// assignment
	var & operator = (const int);			// assignment
	var & operator = (const unsigned int);		// assignment
	var & operator = (const long);			// assignment
	var & operator = (const unsigned long);		// assignment
	var & operator = (const double);		// assignment

	// Casting Operators
	operator char * (void) const;			// type conversion
	operator double (void) const;			// type conversion

	// Assignment Operators
        var & operator ++ (void);			// increment (pre-index only)
        var & operator -- (void);			// decrement (pre-index only)
        var operator ! (void) const;			// not

        var operator + (const var &) const;		// addition OR concatenation
        var operator - (const var &) const;		// subtraction
        var operator * (const var &) const;		// multiplication
        var operator / (const var &) const;		// division
        var operator % (const var &) const;		// remainder

        var & operator += (const var &);		// addition OR concatenation
        var & operator -= (const var &);		// subtraction
        var & operator *= (const var &);		// multiplication
        var & operator /= (const var &);		// division
        var & operator %= (const var &);		// remainder

        var & operator += (const char &);		// addition OR concatenation
        var & operator += (const char *);		// addition OR concatenation
        var & operator -= (const char *);		// subtraction
        var & operator *= (const char *);		// multiplication
        var & operator /= (const char *);		// division
        var & operator %= (const char *);		// remainder

        var & operator += (const double);		// addition OR concatenation
        var & operator -= (const double);		// subtraction
        var & operator *= (const double);		// multiplication
        var & operator /= (const double);		// division
        var & operator %= (const double);		// remainder

	friend var operator + (const char *, const var &); // addition OR concatenation
	friend var operator - (const char *, const var &); // subtraction
	friend var operator * (const char *, const var &); // multiplication
	friend var operator / (const char *, const var &); // division
	friend var operator % (const char *, const var &); // remainder
	friend var operator + (const var &, const char *); // addition OR concatenation
	friend var operator - (const var &, const char *); // subtraction
	friend var operator * (const var &, const char *); // multiplication
	friend var operator / (const var &, const char *); // division
	friend var operator % (const var &, const char *); // remainder

	friend var operator + (const var &, const double); // addition OR concatenation
	friend var operator - (const var &, const double); // subtraction
	friend var operator * (const var &, const double); // multiplication
	friend var operator / (const var &, const double); // division
	friend var operator % (const var &, const double); // remainder
	friend var operator + (const double, const var &); // addition OR concatenation
	friend var operator - (const double, const var &); // subtraction
	friend var operator * (const double, const var &); // multiplication
	friend var operator / (const double, const var &); // division
	friend var operator % (const double, const var &); // remainder

	// Equality Operators
        int operator == (const var &) const;		// equality
        int operator != (const var &) const;		// inequality
        int operator < (const var &) const;		// less than
        int operator > (const var &) const;		// greater than
        int operator <= (const var &) const;		// less than or equal
        int operator >= (const var &) const;		// greater than or equal

	friend int operator == (const var &, const char *); // equality
	friend int operator != (const var &, const char *); // inequality
	friend int operator < (const var &, const char *);  // less than
	friend int operator > (const var &, const char *);  // greater than
	friend int operator <= (const var &, const char *); // less than or equal
	friend int operator >= (const var &, const char *); // greater than or equal
	friend int operator == (const char *, const var &); // equality
	friend int operator != (const char *, const var &); // inequality
	friend int operator < (const char *, const var &);  // less than
	friend int operator > (const char *, const var &);  // greater than
	friend int operator <= (const char *, const var &); // less than or equal
	friend int operator >= (const char *, const var &); // greater than or equal

	friend int operator == (const var &, const double); // equality
	friend int operator != (const var &, const double); // inequality
	friend int operator < (const var &, const double);  // less than
	friend int operator > (const var &, const double);  // greater than
	friend int operator <= (const var &, const double); // less than or equal
	friend int operator >= (const var &, const double); // greater than or equal
	friend int operator == (const double, const var &); // equality
	friend int operator != (const double, const var &); // inequality
	friend int operator < (const double, const var &);  // less than
	friend int operator > (const double, const var &);  // greater than
	friend int operator <= (const double, const var &); // less than or equal
	friend int operator >= (const double, const var &); // greater than or equal

	// Custom Interface
	void null(int);					// "null" out string
	void changesize(int);				// change allocated memory
	int length(void) const;				// length of string
	const char * vartype(void) const;		// name of this var type
	void change_type(const char *);			// change var type
	int is_string(void) const;			// test var type
	int is_double(void) const;			// test var type
	int is_long(void) const;			// test var type
	int strchr(const char) const;			// strchr(char) index
	int strrchr(const char) const;			// strrchr(char) index
	var & concat(const var &);			// concatenation
	var & format(const char *);			// set output format
	void print(ostream &) const;			// output
	void read(istream &);				// input

	static int save_me;				// cntrl object input
	static int save_it(const int save_flag = var::save_me); // input ctrl

    protected:

    private:
	int	numcheck(const char *) const;		// determine is_numeric value

	static	const var ctype;			// for type() function
	short	fixed;					// 1=fixed data type
	short	is_numeric;				// 0=string, 1=short/int/long, 2=float/double
	int	data_str_len;				// length of allocated "string"
	int	data_str_end;				// index to current "end" of string
	char	*data_str;				// for "string" data
	char	*format_str;				// the input/output format string

};


class subvar : public var {
    public:
        var & operator = (const var &);			// substring replacement
	var		*varptr;
	unsigned	offset;
	unsigned	length;
};

#endif

@//E*O*F var.H//
chmod u=rw,g=r,o=r var.H
 
echo x - var.C
sed 's/^@//' > "var.C" <<'@//E*O*F var.C//'
//
// NAME:	var.C
//
// PURPOSE:	C++ Generic "Universal Variable" library class
// AUTHOR:	Lee Hounshell
//

#include	<stddef.h>
#include	<stream.h>
#include	<stdlib.h>
#include	<ctype.h>
#include	<string.h>
#include	"var.H"
#include	"Misc.H"

const int	VAR_PAD_SIZE		= 128;
const int	VAR_DEF_SIZE		= 16;

const short	VAR_STRING		= 0;
const short	VAR_LONG		= 1;
const short	VAR_DOUBLE		= 2;

char *	DEFAULT_STRING_FORMAT		= "'%s'";
char *	DEFAULT_INT_FORMAT		= "%d";
char *	DEFAULT_UINT_FORMAT		= "%u";
char *	DEFAULT_LONG_FORMAT		= "%ld";
char *	DEFAULT_ULONG_FORMAT		= "%lu";
char *	DEFAULT_DOUBLE_FORMAT		= "%9.2f";

// -----------------------------------------------------------------------------

const var var::ctype	= "var";
int var::save_me			= 1;


const var & var::type(void) const
{
    return var::ctype;
}


varsize::varsize(int sz)
{
    size = sz;
}


var::var(void)
{
    fixed = 0;
    is_numeric = VAR_STRING;
    data_str_len = VAR_DEF_SIZE;
    data_str_end = 0;
    data_str = new char[data_str_len];
    data_str[0] = 0;
    format_str = DEFAULT_STRING_FORMAT;
}


var::var(const char *str)
{
    fixed = 1;
    is_numeric = VAR_STRING;
    data_str_end = strlen(str);
    data_str_len = data_str_end + VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, str);
    format_str = DEFAULT_STRING_FORMAT;
}


var::var(const varsize &vsz)
{
    fixed = 0;
    is_numeric = VAR_STRING;
    data_str_len = vsz.size + VAR_DEF_SIZE;
    data_str_end = 0;
    data_str = new char[data_str_len];
    data_str[0] = 0;
    format_str = DEFAULT_STRING_FORMAT;
}


var::var(const char ch)
{
    fixed = 0;
    is_numeric = VAR_STRING;
    data_str_len = VAR_DEF_SIZE;
    data_str_end = 1;
    data_str = new char[data_str_len];
    data_str[0] = ch;
    data_str[1] = 0;
    format_str = DEFAULT_STRING_FORMAT;
}


var::var(const short int_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, itoa(int_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_INT_FORMAT;
}


var::var(const unsigned short int_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, itoa(int_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_UINT_FORMAT;
}


var::var(const int int_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, itoa(int_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_INT_FORMAT;
}


var::var(const unsigned int int_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, itoa(int_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_UINT_FORMAT;
}


var::var(const long long_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, ltoa(long_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_LONG_FORMAT;
}


var::var(const unsigned long long_num)
{
    fixed = 1;
    is_numeric = VAR_LONG;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, ltoa(long_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_ULONG_FORMAT;
}


var::var(const double double_num)
{
    fixed = 1;
    is_numeric = VAR_DOUBLE;
    data_str_len = VAR_DEF_SIZE;
    data_str = new char[data_str_len];
    strcpy(data_str, dtoa(double_num));
    data_str_end = strlen(data_str);
    format_str = DEFAULT_DOUBLE_FORMAT;
}


var::var(const var &v)
{
    fixed = v.fixed;
    is_numeric = v.is_numeric;
    if (v.data_str && v.data_str_end) {
	data_str_len = v.data_str_end + VAR_DEF_SIZE;
	data_str_end = v.data_str_end;
	data_str = new char[data_str_len];
	strcpy(data_str, v.data_str);
    }
    else {
	data_str_len = VAR_DEF_SIZE;
	data_str_end = 0;
	data_str = new char[data_str_len];
	data_str[0] = 0;
    }
    format_str = DEFAULT_STRING_FORMAT;
}


var::~var(void)
{
    if (data_str) {
	delete data_str;
    }
    if (format_str
	&& format_str != DEFAULT_STRING_FORMAT
	&& format_str != DEFAULT_INT_FORMAT
	&& format_str != DEFAULT_UINT_FORMAT
	&& format_str != DEFAULT_LONG_FORMAT
	&& format_str != DEFAULT_ULONG_FORMAT
	&& format_str != DEFAULT_DOUBLE_FORMAT) {
	    delete format_str;
    }
}

// -----------------------------------------------------------------------------

var & var::operator = (const char *str)
{
    if (fixed && is_numeric) {
	if (is_numeric == VAR_DOUBLE) {
	    double d = atod((char *) str);
	    *this = d;
	}
	else {
	    long l = atol(str);
	    *this = l;
	}
    }
    else {
	int len = strlen(str) + 1;
	if (data_str_len < len) {
	    delete data_str;
	    data_str_len = len;
	    data_str = new char[data_str_len];
	}
	data_str_end = len - 1;
	strcpy(data_str, str);
	if (!fixed) {
	    int str_is_numeric = numcheck(data_str);
	    is_numeric = str_is_numeric;
	}
    }
    return *this;
}


var & var::operator = (const var &l)
{
    if (this != &l) {
	if (data_str_len <= l.data_str_end) {
	    delete data_str;
	    data_str_len = l.data_str_end + VAR_DEF_SIZE;
	    data_str = new char[data_str_len];
	}
	data_str_end = l.data_str_end;
	strncpy(data_str, l.data_str, l.data_str_end);
	data_str[data_str_end] = 0;
	if (!fixed) {
	    is_numeric = numcheck(data_str);
	}
	//
	// Note: the output "format" of a var variable is preserved
	//
    }
    return *this;
}


char & var::operator [] (const int index)
{
    static char error_ch;
    if (index < 0) {
	cerr << "ERROR: " << " - var[" << index << "] negative index used." << endl;
	error_ch = 0;
	return error_ch;
    }
    if (data_str_len <= index) {
	// this is technically a program error, but I'll be nice and extend the string's length
	data_str_len = index + VAR_PAD_SIZE;
	data_str_end = index + 1;
	char *buf = new char[data_str_len];
	sprintf(buf, "%-*.*s", data_str_end, data_str_end, data_str);
	delete data_str;
	data_str = buf;
	data_str[index] = 0;
	cerr << "WARNING: " << " - var index '" << index << "' beyond current string boundary." << endl;
    }
    while (data_str_end < index) {
	data_str[data_str_end++] = ' ';		// pad to index with spaces if necessary
    }
    if (data_str_end == index) {
	data_str[data_str_end] = 0;		// the end of a string is ALWAYS 0
	if ((data_str_end + 1) < data_str_len) {
	    data_str[++data_str_end] = 0;	// the new end of string is also 0
	}
    }
    return data_str[index];
}


// for substrings
subvar & var::operator () (const int offset) const
{
    return operator () (offset, -1);
}


// for substrings
subvar & var::operator () (int offset, int length) const
{
    static subvar _esi_subvar;
    if (length < 0) {
	length = data_str_end - offset;
    }
    char *substr = new char[length + 1];
    strncpy(substr, data_str + offset, (int) length);
    substr[length] = 0;
    _esi_subvar.var::operator = (substr);
    _esi_subvar.varptr = (var *) this;
    _esi_subvar.offset = offset;
    _esi_subvar.length = length;
    delete substr;
    return _esi_subvar;
}


// for syntax: var(offset, length) = var
var & subvar::operator = (const var &substr)
{
    char *srcstr = varptr->data_str;
    char *repstr = substr.data_str;
    int replen = length;
    if (substr.data_str_end < length) {
	replen = substr.data_str_end;
    }
    int len = varptr->data_str_len;
    char *newstr = new char[len];
    strncpy(newstr, srcstr, offset);		// data from string being replaced up to "offset"
    if (replen) {
	strncpy(newstr + offset, repstr, replen);	// replacement string data
    }
    int newoffset = offset + replen;
    if (newoffset < varptr->data_str_end) {
	strcpy(newstr + newoffset, srcstr + offset + length);
    }
    else {
	newstr[newoffset] = 0;
    }
    if (varptr->data_str) {
	delete varptr->data_str;
    }
    varptr->data_str = newstr;
    varptr->data_str_len = len;
    varptr->data_str_end = strlen(newstr);
    if (!varptr->fixed) {
	varptr->is_numeric = numcheck(newstr);
    }
    return *varptr;
}

// -----------------------------------------------------------------------------

var & var::operator = (const char ch)
{
    char buf[2];
    buf[0] = ch;
    buf[1] = 0;
    *this = buf;
    return *this;
}


var & var::operator = (const short int_num)
{
    char *str = itoa(int_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_LONG;
    }
    return *this;
}


var & var::operator = (const unsigned short int_num)
{
    char *str = itoa(int_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    is_numeric = VAR_LONG;
    return *this;
}


var & var::operator = (const int int_num)
{
    char *str = itoa(int_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_LONG;
    }
    return *this;
}


var & var::operator = (const unsigned int int_num)
{
    char *str = itoa(int_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_LONG;
    }
    return *this;
}


var & var::operator = (const long long_num)
{
    char *str = ltoa(long_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_LONG;
    }
    return *this;
}


var & var::operator = (const unsigned long long_num)
{
    char *str = ltoa(long_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_LONG;
    }
    return *this;
}


var & var::operator = (const double dbl_num)
{
    char *str = dtoa(dbl_num);
    int len = strlen(str);
    if (data_str_len < len) {
	delete data_str;
	data_str_len = len + 1;
	data_str = new char[data_str_len];
    }
    data_str_end = len;
    strcpy(data_str, str);
    if (!fixed) {
	is_numeric = VAR_DOUBLE;
    }
    return *this;
}

// -----------------------------------------------------------------------------

var::operator char * (void) const
{
    return data_str;
}


var::operator double (void) const
{
    return atod(data_str);
}

// -----------------------------------------------------------------------------

var & var::operator ++ (void)		// increment (pre-index only)
{
    *this += 1;
    return *this;
}


var & var::operator -- (void)		// decrement (pre-index only)
{
    *this -= 1;
    return *this;
}


var var::operator ! (void) const	// not
{
    var not(1);
    if ((int) *this) {
	not = 0;
    }
    return not;
}

// -----------------------------------------------------------------------------

var var::operator + (const var & v) const	// addition OR concatenation
{
    var add;
    if (is_numeric && v.is_numeric) {
	// do math in the highest precision specified
	int n_type = (is_numeric > v.is_numeric) ? is_numeric : v.is_numeric;
	switch (n_type) {
	    case VAR_LONG:
		add = (long) *this + (long) v;
		break;
	    default:
		// should be VAR_DOUBLE
		add = (double) *this + (double) v;
		break;
	}
    }
    else {
	// concatenate strings
	delete add.data_str;
	add.data_str_len = data_str_end + v.data_str_end + VAR_PAD_SIZE;
	add.data_str_end = data_str_end + v.data_str_end;
	add.data_str = new char[add.data_str_len];
	strcpy(add.data_str, data_str);
	strcpy((add.data_str) + data_str_end, v.data_str);
	add.is_numeric = VAR_STRING;
    }
    return add;
}


var var::operator - (const var & v) const	// subtraction
{
    var sub;
    // do math in the highest precision specified
    int n_type = (is_numeric > v.is_numeric) ? is_numeric : v.is_numeric;
    switch (n_type) {
	case VAR_LONG:
	    sub = (long) *this - (long) v;
	    sub.is_numeric = VAR_LONG;
	    break;
	default:
	    // should be VAR_DOUBLE
	    sub = (double) *this - (double) v;
	    break;
    }
    return sub;
}


var var::operator * (const var & v) const	// multiplication
{
    var times;
    // do math in the highest precision specified
    int n_type = (is_numeric > v.is_numeric) ? is_numeric : v.is_numeric;
    switch (n_type) {
	case VAR_LONG:
	    times = (long) *this * (long) v;
	    break;
	default:
	    // should be VAR_DOUBLE
	    times = (double) *this * (double) v;
	    break;
    }
    return times;
}


var var::operator / (const var & v) const	// division
{
    var div;
    // do math in the highest precision specified
    int n_type = (is_numeric > v.is_numeric) ? is_numeric : v.is_numeric;
    switch (n_type) {
	case VAR_LONG:
	    div = (long) *this / (long) v;
	    break;
	default:
	    // should be VAR_DOUBLE
	    div = (double) *this / (double) v;
	    break;
    }
    return div;
}


var var::operator % (const var & v) const	// remainder
{
    var mod;
    // do math in the highest precision specified
    int n_type = (is_numeric > v.is_numeric) ? is_numeric : v.is_numeric;
    switch (n_type) {
	case VAR_LONG:
	    mod = (long) *this % (long) v;
	    break;
	default:
	    // should be VAR_DOUBLE
	    // really, I shouldn't allow this..
	    mod = (double) ((long) *this % (long) v);
	    break;
    }
    return mod;
}

// -----------------------------------------------------------------------------

var & var::operator += (const var & v)
{
    if ((is_numeric == VAR_STRING) || (v.is_numeric == VAR_STRING)) {
	concat(v);
    }
    else {
	*this = (*this) + v;
    }
    return *this;
}


var & var::operator -= (const var & v)
{
    *this = (*this) - v;
    return *this;
}


var & var::operator *= (const var & v)
{
    *this = (*this) * v;
    return *this;
}


var & var::operator /= (const var & v)
{
    *this = (*this) / v;
    return *this;
}


var & var::operator %= (const var & v)
{
    *this = (*this) % v;
    return *this;
}

// -----------------------------------------------------------------------------

var & var::operator += (const char & ch)
{
    var foo = ch;
    *this += foo;
    return *this;
}

var & var::operator += (const char * v)
{
    var foo = v;
    *this += foo;
    return *this;
}


var & var::operator -= (const char * v)
{
    var foo = v;
    *this -= foo;
    return *this;
}


var & var::operator *= (const char * v)
{
    var foo = v;
    *this *= foo;
    return *this;
}


var & var::operator /= (const char * v)
{
    var foo = v;
    *this /= foo;
    return *this;
}


var & var::operator %= (const char * v)
{
    var foo = v;
    *this %= foo;
    return *this;
}

// -----------------------------------------------------------------------------

var & var::operator += (const double v)
{
    var foo = v;
    *this += foo;
    return *this;
}


var & var::operator -= (const double v)
{
    var foo = v;
    *this -= foo;
    return *this;
}


var & var::operator *= (const double v)
{
    var foo = v;
    *this *= foo;
    return *this;
}


var & var::operator /= (const double v)
{
    var foo = v;
    *this /= foo;
    return *this;
}


var & var::operator %= (const double v)
{
    var foo = v;
    *this %= foo;
    return *this;
}

// -----------------------------------------------------------------------------

var operator + (const char * s, const var & v)
{
    var foo = s;
    return foo + v;
}


var operator - (const char * s, const var & v)
{
    var foo = s;
    return foo - v;
}


var operator * (const char * s, const var & v)
{
    var foo = s;
    return foo * v;
}


var operator / (const char * s, const var & v)
{
    var foo = s;
    return foo / v;
}


var operator % (const char * s, const var & v)
{
    var foo = s;
    return foo % v;
}


var operator + (const var & v, const char * s)
{
    var foo = s;
    return v + foo;
}


var operator - (const var & v, const char * s)
{
    var foo = s;
    return v - foo;
}


var operator * (const var & v, const char * s)
{
    var foo = s;
    return v * foo;
}


var operator / (const var & v, const char * s)
{
    var foo = s;
    return v / foo;
}


var operator % (const var & v, const char * s)
{
    var foo = s;
    return v % foo;
}

// -----------------------------------------------------------------------------

var operator + (const var & v, const double d)
{
    var foo = d;
    return v + foo;
}


var operator - (const var & v, const double d)
{
    var foo = d;
    return v - foo;
}


var operator * (const var & v, const double d)
{
    var foo = d;
    return v * foo;
}


var operator / (const var & v, const double d)
{
    var foo = d;
    return v / foo;
}


var operator % (const var & v, const double d)
{
    var foo = d;
    return v % foo;
}


var operator + (const double d, const var & v)
{
    var foo = d;
    return foo + v;
}


var operator - (const double d, const var & v)
{
    var foo = d;
    return foo - v;
}


var operator * (const double d, const var & v)
{
    var foo = d;
    return foo * v;
}


var operator / (const double d, const var & v)
{
    var foo = d;
    return foo / v;
}


var operator % (const double d, const var & v)
{
    var foo = d;
    return foo % v;
}

// -----------------------------------------------------------------------------

int var::operator == (const var & t) const		// equality
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) == (long) t;
	}
	return (double) (*this) == (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return !strcmp(data_str, t.data_str);
	}
	else {
	    return data_str_end == t.data_str_end;
	}
    }
}


int var::operator != (const var & t) const		// inequality
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) != (long) t;
	}
	return (double) (*this) != (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return strcmp(data_str, t.data_str);
	}
	else {
	    return data_str_end != t.data_str_end;
	}
    }
}


int var::operator < (const var & t) const		// less than
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) < (long) t;
	}
	return (double) (*this) < (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return (strcmp(data_str, t.data_str) < 0);
	}
	else {
	    return data_str_end < t.data_str_end;
	}
    }
}


int var::operator > (const var & t) const		// greater than
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) > (long) t;
	}
	return (double) (*this) > (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return (strcmp(data_str, t.data_str) > 0);
	}
	else {
	    return data_str_end > t.data_str_end;
	}
    }
}


int var::operator <= (const var & t) const		// less than or equal
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) <= (long) t;
	}
	return (double) (*this) <= (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return (strcmp(data_str, t.data_str) <= 0);
	}
	else {
	    return data_str_end <= t.data_str_end;
	}
    }
}


int var::operator >= (const var & t) const		// greater than or equal
{
    if (is_numeric && t.is_numeric) {
	if (is_numeric == VAR_LONG && t.is_numeric == VAR_LONG) {
	    return (long) (*this) >= (long) t;
	}
	return (double) (*this) >= (double) t;
    }
    else {
	if (data_str_end && t.data_str_end) {
	    return (strcmp(data_str, t.data_str) >= 0);
	}
	else {
	    return data_str_end >= t.data_str_end;
	}
    }
}

// -----------------------------------------------------------------------------

int operator == (const var & t, const char * s)
{
    var foo = s;
    return t == foo;
}


int operator != (const var & t, const char * s)
{
    var foo = s;
    return t != foo;
}


int operator < (const var & t, const char * s)
{
    var foo = s;
    return t < foo;
}


int operator > (const var & t, const char * s)
{
    var foo = s;
    return t > foo;
}


int operator <= (const var & t, const char * s)
{
    var foo = s;
    return t <= foo;
}


int operator >= (const var & t, const char * s)
{
    var foo = s;
    return t >= foo;
}


int operator == (const char * s, const var & t)
{
    var foo = s;
    return foo == t;
}


int operator != (const char * s, const var & t)
{
    var foo = s;
    return foo != t;
}


int operator < (const char * s, const var & t)
{
    var foo = s;
    return foo < t;
}


int operator > (const char * s, const var & t)
{
    var foo = s;
    return foo > t;
}


int operator <= (const char * s, const var & t)
{
    var foo = s;
    return foo <= t;
}


int operator >= (const char * s, const var & t)
{
    var foo = s;
    return foo >= t;
}

// -----------------------------------------------------------------------------

int operator == (const var & t, const double d)
{
    return (double) t == d;
}


int operator != (const var & t, const double d)
{
    return (double) t != d;
}


int operator < (const var & t, const double d)
{
    return (double) t < d;
}


int operator > (const var & t, const double d)
{
    return (double) t > d;
}


int operator <= (const var & t, const double d)
{
    return (double) t <= d;
}


int operator >= (const var & t, const double d)
{
    return (double) t >= d;
}


int operator == (const double d, const var & t)
{
    return d == (double) t;
}


int operator != (const double d, const var & t)
{
    return d != (double) t;
}


int operator < (const double d, const var & t)
{
    return d < (double) t;
}


int operator > (const double d, const var & t)
{
    return d > (double) t;
}


int operator <= (const double d, const var & t)
{
    return d <= (double) t;
}


int operator >= (const double d, const var & t)
{
    return d >= (double) t;
}

// -----------------------------------------------------------------------------

void var::null(int index)
{
    if (index >= data_str_len) {
	cerr << "WARNING: " << " - var::null(" << index << ") - the index out of range." << endl;
	(*this)[index] = 0;
	data_str_end = index;
    }
    else {
	data_str[index] = 0;
	data_str_end = index;
    }
}


void var::changesize(int newsize)
{
    if (newsize > data_str_len) {
	char *buf = new char[newsize];
	if (data_str) {
	    strncpy(buf, data_str, data_str_end);
	    buf[data_str_end] = 0;
	    delete data_str;
	}
	else {
	    *buf = 0;
	    data_str_end = 0;
	}
	data_str_len = newsize;
	data_str = buf;
    }
}


int var::length(void) const
{
    return data_str_end;
}


const char * var::vartype(void) const
{
    switch (is_numeric) {
	case VAR_STRING:
	    return "VAR_STRING";
	case VAR_LONG:
	    return "VAR_LONG";
	case VAR_DOUBLE:
	    return "VAR_DOUBLE";
    }
    return "var type unknown";
}


void var::change_type(const char *ntype)
{
    if (ntype == NULL) {
	return;
    }
    int index = strlen(ntype);
    if (!index) {
	return;
    }
    char *new_type = new char[index + 1];
    if (ntype[0] == '(' && ntype[index - 1] == ')') {
	strcpy(new_type, &ntype[1]);
	index = strlen(new_type) - 1;
	if (index <= 0) {
	    delete new_type;
	    return;
	}
	new_type[index] = 0;			// drop parens
    }
    else {
	strcpy(new_type, ntype);
    }
    if (new_type[index - 1] == ' ') {
	new_type[index - 1] = 0;
    }
    fixed = 1;
    if (!strcmp(new_type, "var")) {
	is_numeric = numcheck((const char *) *this);
    }
    else if (!strcmp(new_type, "string")) {
	is_numeric = VAR_STRING;
    }
    else if (!strcmp(new_type, "short")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "unsigned short")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "int")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "unsigned int")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "long")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "unsigned long")) {
	is_numeric = VAR_LONG;
    }
    else if (!strcmp(new_type, "float")) {
	is_numeric = VAR_DOUBLE;
    }
    else if (!strcmp(new_type, "double")) {
	is_numeric = VAR_DOUBLE;
    }
    else {
	cerr << "WARNING: " << " - change_type(" << new_type << ") - unrecognized type name." << endl;
    }
    delete new_type;
}


int var::is_string(void) const
{
    return is_numeric == VAR_STRING;
}


int var::is_double(void) const
{
    return is_numeric == VAR_DOUBLE;
}


int var::is_long(void) const
{
    return is_numeric == VAR_LONG;
}


int var::strchr(const char ch) const
{
    for (int i = 0; i < data_str_end; ++i) {
	if (data_str[i] == ch) {
	    return i;
	}
    }
    return -1;
}


int var::strrchr(const char ch) const
{
    for (int i = data_str_end - 1; i >= 0; --i) {
	if (data_str[i] == ch) {
	    return i;
	}
    }
    return -1;
}


var & var::concat(const var & str)
{
    // concatenate strings
    int new_data_str_end = data_str_end + str.data_str_end;
    if (new_data_str_end >= data_str_len) {
	var add;
	add.data_str_len = data_str_len + str.data_str_len + VAR_PAD_SIZE;
	add.data_str_end = new_data_str_end;
	add.data_str = new char[add.data_str_len];
	strcpy(add.data_str, data_str);
	strcpy((add.data_str) + data_str_end, str.data_str);
	*this = add;
    }
    else {
	strcpy(data_str + data_str_end, str.data_str);
	data_str_end += str.data_str_end;
    }
    return *this;
}


var & var::format(const char * fmt)
{
    if (format_str
	&& format_str != DEFAULT_STRING_FORMAT
	&& format_str != DEFAULT_INT_FORMAT
	&& format_str != DEFAULT_UINT_FORMAT
	&& format_str != DEFAULT_LONG_FORMAT
	&& format_str != DEFAULT_ULONG_FORMAT
	&& format_str != DEFAULT_DOUBLE_FORMAT) {
	    delete format_str;
    }
    if (fmt) {
	format_str = new char[strlen(fmt) + 1];
	strcpy(format_str, fmt);
    }
    else {
	format_str = NULL;
    }
    return *this;
}


int var::numcheck(const char * str) const
{
    if (!str || !*str) {
	return VAR_STRING;		// assume a string
    }
    char *ptr = (char *) str;
    int nc = VAR_LONG;			// assume a signed long
    int decimal_yet = 0;
    if (*ptr == '.' && *(ptr + 1)) {
	nc = VAR_DOUBLE;		// floating point number
	decimal_yet = 1;
	++ptr;
    }
    else if (*ptr == '-' && *(ptr + 1)) {
	// skip optional sign char
	++ptr;
    }
    while (*ptr) {
	if (*ptr == '.' && !decimal_yet) {
	    decimal_yet = 1;
	    nc = VAR_DOUBLE;		// assume a double
	}
	else if (!isdigit(*ptr)) {
	    return VAR_STRING;		// nope.. got a string
	}
	++ptr;
    }
    return nc;
}

// -----------------------------------------------------------------------------

int var::save_it(const int save_flag)
{
    int s = var::save_me;
    var::save_me = save_flag;
    return s;
}

// -----------------------------------------------------------------------------

ostream & operator << (ostream &out, const var &d)
{
    d.print(out);
    return out;
}


void var::print(ostream &out) const
{
    // NOTE: the "read()" function requires a newline to appear after the last quote.
    // I assume that this newline was appropriately output by the var class user.
    if (!format_str || (format_str && *format_str == 0)) {
	out << "var OBJECT: {"
	    << Inc << "fixed        = " << fixed
	    << Tab << "is_numeric   = " << is_numeric
	    << Tab << "data_str_len = " << data_str_len
	    << Tab << "data_str_end = " << data_str_end
	    << Tab << "data_str     = '" << data_str << "'"
	    << Tab << "format_str   = '" << format_str << "'"
	    << Dec << "}" << endl;
    }
    else {
	// we need to use the specified format string for output
	int len = length() + 1;
	char *outbuf = new char[2048];
	char *fptr = format_str;
	while (*fptr) {
	    if (*fptr != '%' && *fptr != '\\') {
		out << *fptr;
		++fptr;
	    }
	    else if (*fptr == '\\') {
		switch (*(fptr + 1)) {
		    case 'n':
			cout << '\n';
			break;
		    case 't':
			cout << '\t';
			break;
		    case 'v':
			cout << '\v';
			break;
		    case 'b':
			cout << '\b';
			break;
		    case 'r':
			cout << '\r';
			break;
		    case 'f':
			cout << '\f';
			break;
		    case 'a':
			cout << '\007';
			break;
		    case '\\':
			cout << '\\';
			break;
		    case '?':
			cout << '\?';
			break;
		    case '\'':
			cout << '\'';
			break;
		    case '\"':
			cout << '\"';
			break;
		    default:
			cout << *(fptr + 1);
		}
		fptr += 2;
	    }
	    else {
		// Hmmm.. we need to do some special formatting
		// first extract this printf-style format string
		char smallfmtstr[128];
		char *smptr = smallfmtstr;
		*smptr = 0;
		if (*(fptr + 1) == '%') {
		    strcpy(outbuf, "%");
		    fptr += 2;
		}
		else {
		    while (*fptr) {
			*smptr = *fptr++;
			*(smptr + 1) = 0;
			// integer
			if (*smptr == 'd') {
			    sprintf(outbuf, smallfmtstr, (int) *this);
			    break;
			}
			// unsigned integer
			if (*smptr == 'o' || *smptr == 'u' || *smptr == 'x' || *smptr == 'X') {
			    sprintf(outbuf, smallfmtstr, (unsigned int) *this);
			    break;
			}
			// float or double
			if (*smptr == 'f' || *smptr == 'e' || *smptr == 'E' || *smptr == 'g' || *smptr == 'G') {
			    sprintf(outbuf, smallfmtstr, (double) *this);
			    break;
			}
			// character
			if (*smptr == 'c') {
			    if (!strcmp(vartype(), "VAR_STRING")) {
				const char *tmp = (const char *) (*this);
				sprintf(outbuf, smallfmtstr, tmp[0]);
			    }
			    else {
				sprintf(outbuf, smallfmtstr, (char) ((int) *this));
			    }
			    break;
			}
			// string
			if (*smptr == 's') {
			    sprintf(outbuf, smallfmtstr, (const char *) *this);
			    break;
			}
			++smptr;
		    }
		}
		out << outbuf;
	    }
	}
	out << flush;
	delete outbuf;
    }
}


istream & operator >> (istream &in, var &d)
{
    d.read(in);
    return in;
}


void var::read(istream &in)
{
    // input the same format as was created by the output operator
    char buf1[4096];
    char buf2[4096];
    if (!format_str || (format_str && *format_str == 0)) {
	look_for(in, '{');
	look_for(in, '=');
	in >> fixed;
	look_for(in, '=');
	in >> is_numeric;
	look_for(in, '=');
	in >> data_str_len;
	look_for(in, '=');
	in >> data_str_end;
	look_for(in, '=');
	scan_string(in, buf1, sizeof(buf1));
	look_for(in, '=');
	scan_string(in, buf2, sizeof(buf2));
	look_for(in, '}');
	*this = buf1;
	format(buf2);
    }
    else {
	// LEE: need to add input/output formatting capabilities
    }
}

@//E*O*F var.C//
chmod u=rw,g=r,o=r var.C
 
echo x - Misc.H
sed 's/^@//' > "Misc.H" <<'@//E*O*F Misc.H//'
// 
// NAME:	MISC.H
//
// PURPOSE:	generalized functions for C++ class library routines
// AUTHOR:	Lee Hounshell
//

#ifndef MISC_H
#define MISC_H

#include <stream.h>

    char *itoa(const int foo);
    char *uitoa(const unsigned int foo);

#ifdef HP
    char *ltoa(long foo);
    char *ultoa(unsigned long foo);
#else
    char *ltoa(const long foo);
    char *ultoa(const unsigned long foo);
#endif

    char *dtoa(const double foo);
    double atod(char * foo);
    char *ltoTime(const long date24);
    istream & look_for(istream &in, char c);
    void scan_string(istream &in, char *ptr, int size);
    ostream & Tab(ostream &out);
    ostream & Inc(ostream &out);
    ostream & Dec(ostream &out);

#endif

@//E*O*F Misc.H//
chmod u=rw,g=r,o=r Misc.H
 
echo x - Misc.C
sed 's/^@//' > "Misc.C" <<'@//E*O*F Misc.C//'
// 
// NAME:	MISC.C
//
// PURPOSE:	generalized functions for C++ class library routines
// AUTHOR:	Lee Hounshell
//

#include <stdlib.h>
#include <stream.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include "Misc.H"


// =============================================================================
// stuff thet jes' be here 'cause i wuz be 2 lazy 2 done drop it sumplace else, Mazza!
// =============================================================================


// -----------------------------------------------------------------------------
// convert an integer into an ascii string.  return a pointer to that string.
//
char *itoa(const int foo)
{
    static char int_buf[28];
    sprintf(int_buf, "%d", foo);
    return int_buf;
}


// convert an unsigned integer into an ascii string.  return a pointer to that string.
//
char *uitoa(const unsigned int foo)
{
    static char int_buf[28];
    sprintf(int_buf, "%u", foo);
    return int_buf;
}


// convert a long into an ascii string.  return a pointer to that string.
//
#ifdef HP
char *ltoa(long foo)
#else
char *ltoa(const long foo)
#endif
{
    static char long_buf[28];
    sprintf(long_buf, "%ld", foo);
    return long_buf;
}


// convert an unsigned long into an ascii string.  return a pointer to that string.
//
#ifdef HP
char *ultoa(unsigned long foo)
#else
char *ultoa(const unsigned long foo)
#endif
{
    static char long_buf[28];
    sprintf(long_buf, "%lu", foo);
    return long_buf;
}


// convert a double into an ascii string.  return a pointer to that string.
// truncate any extra zeros after the decimal point.
//
char *dtoa(const double foo)
{
    static char double_buf[28];
    sprintf(double_buf, "%lf", foo);
    char *ptr;
    for (ptr = double_buf; *ptr; ++ptr) {
	if (*ptr == '.') {
	    // we may need to truncate zeroes
	    ptr = double_buf + (strlen(double_buf) - 1);
	    while (*ptr == '0') {
		*ptr-- = 0;
	    }
	    if (*ptr == '.') {
		*ptr = 0;
	    }
	    break;
	}
    }
    return double_buf;
}


// convert an ascii string to a double
//
double atod(char * foo)
{
    double d = 0;
    if (!foo || !*foo) {
	return d;
    }
    if (!isdigit(*foo)) {
	if (*foo != '-' && *foo != '+') {
	    return d;
	}
	if (!isdigit(*(foo + 1))) {
	    return d;
	}
    }
    sscanf(foo, "%lf", &d);
    return d;
}

// -----------------------------------------------------------------------------

// convert a 24-hour time (hhmm) into LMOS string format (hhmmZ - where Z is 'A' or 'P')
//
char *ltoTime(const long date24)
{
    static char time_buf[6];
    *time_buf = 0;
    if (date24 != 0L) {
	long minute = date24 % 100;
	long hour = (date24 - minute) / 100;
	char ampm = 'A';
	if (hour >= 12) {
	    ampm = 'P';
	    if (hour > 12) hour -= 12;
	}
	sprintf(time_buf, "%02d%02d%c", hour, minute, ampm);
	return time_buf;
    }
}


// -----------------------------------------------------------------------------
// scan input until the desired character is found
//
istream & look_for(istream &in, char c)
{
    int input = 0;
    if (getenv("INPUT_DEBUG") != NULL) {
	cerr << "Debug: looking for input character '" << c << "'" << endl;
    }
    while (input != c && input != EOF) {
	input = in.get();
	if (getenv("INPUT_DEBUG") != NULL) {
	    cerr << input;
	}
    }
    return in;
}


// -----------------------------------------------------------------------------
// this function is used by lots of other classes for I/O, also.
// it really is a sort of "general-purpose," non-class-specific routine
// i use it for extracting class memebers from a saved object
//
void scan_string(istream &in, char *ptr, int size)
{
    char buffer[3];
    char *input;
    if (size) --size;
    if (getenv("INPUT_DEBUG") != NULL) {
	cerr << "Debug: scanning for string (length=" << size << ")" << endl;
    }
    if (ptr != NULL) {
	input = ptr;
    }
    else {
	input = buffer;
    }
    *input = 0;
    look_for(in, '\'');				// find first quote
    int endflag = 0;
    int count = 0;
    while (1) {
	int ch;
	if ((ch = in.get()) == EOF) {
	    if (getenv("INPUT_DEBUG") != NULL) {
		cerr << "debug: scan_string(): unexpected EOF found" << endl;
	    }
	    *input = 0;
	    break;
	}
	*input = ch;
	if (getenv("INPUT_DEBUG") != NULL) {
	    cerr << *input;
	}
	if (*input == '\n' && endflag) {	// all done!
	    *input = 0;
	    if (getenv("INPUT_DEBUG") != NULL) {
		cerr << "\nDebug: scan_string() found: '" << ptr << "'" << endl;
	    }
	    break;				// found end of string
	}
	if (count >= size) {			// string is too big for buffer
	    if (getenv("INPUT_DEBUG") != NULL) {
		cerr << "\nDebug: scan_string() size exceeded - truncating string" << endl;
	    }
	    if (ch != '\'') {
		look_for(in, '\'');		// skip to last quote
	    }
	    endflag = 1;
	    continue;
	}
	if (ptr != NULL && endflag) {		// possibly found end of string
	    *(input+1) = *input;
	    *input = '\'';
	    ++input;
	    ++count;
	}
	if ((endflag = (*input == '\'')) == 0) {// got a close quote??
	    if (*ptr) ++input;
	    ++count;
	}
    }
}


// these functions are also used by other classes for I/O.
// they keep track of "indent" levels for printing objects with inheritance

static int no_tab_stops = 0;


// -----------------------------------------------------------------------------
//
ostream & Tab(ostream &out)
{
    out << "\n";
    for (int i = 0; i < no_tab_stops; ++i) {
	out << "    ";				// really one-half a tab stop
    }
    return out;
}


// -----------------------------------------------------------------------------
//
ostream & Inc(ostream &out)
{
    ++no_tab_stops;
    return Tab(out);
}


// -----------------------------------------------------------------------------
//
ostream & Dec(ostream &out)
{
    --no_tab_stops;
    return Tab(out);
}

@//E*O*F Misc.C//
chmod u=rw,g=r,o=r Misc.C
 
echo x - demo.C
sed 's/^@//' > "demo.C" <<'@//E*O*F demo.C//'
#include	<stdlib.h>
#include	<stream.h>
#include	<var.H>

main ()
{
	var value;				// declare an "untyped" var
	value = "hello world";			// initialize it
	cout << value << endl;			// output "hello world"
	value = value(3, value.length() - 6);	// substring example
	cout << value << endl;			// output "lo wo"
	value = 35;				// assignment of int
	value += 42.375;			// add 42.375 to present value
	cout << value << endl;			// output "77.375"
	cout << value.format("formatted output example %05d of value") << endl;
	cout << value.format("multiple outputs #1=%d, #2=%9.2f of value") << endl;
	value.null(2);				// truncate string
	value += " sunset strip";		// concatenate a string
	cout << value.format("%s") << endl;	// output "77 sunset strip"
	cout << value[3] << value[4] << value[5] << endl; // output "sun"
}

@//E*O*F demo.C//
chmod u=rw,g=r,o=r demo.C
 
exit 0
-- 
Lee Hounshell - (510) 823-2432
tlhouns@srv.pacbell.com
Alchemical Engineer and Virtual Realist
Newsgroups: comp.lang.c++