25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more...
Home   Projects   Up   Sitemap   Search   Blog   Forum+Chat   About Us   Privacy   Terms of Use   Feedback   FAQ   Images   Services   Ads   Donate   Humor

C++ functions for MSDOS, EasyWin, or Windows OWL

These C++ functions should be compatible with MSDOS, Borland ObjectWindows Library 2.0 for Windows, Borland's EasyWin console interface for Windows, and maybe any other target type.

backfile.cpp

/*	backfile.cpp		2-14-98
	Copyright (C)1998 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

Creates a backup copy of a file.

Given the name of a file you want to backup before writing to, it deletes filename.bak (the
current backup file), renames the current filename.ext to filename.bak (backs it up), and
returns a reference to the original filename.ext string.
It should work properly with full path names.

Use: ofstream outfile(backupfile(filename.ext).c_str());

*/
#include <stdio.h>
#include <io.h>
#include "c:\bcs\my.h"
//////////////////////////////////////////////////////////////////////////////
const string& backupfile(const string& filename)
{
if(filename.length())
{
	string bakfile(filename);

	if(bakfile.contains("."))                       // delete extension
		bakfile.remove(bakfile.rfind("."));
	bakfile += ".bak";                             	// add ".bak"

	unlink(bakfile.c_str());						// delete .bak file, if any
	rename(filename.c_str(),bakfile.c_str());		// rename current to .bak
}
return(filename);		// return reference to original filename
}

countchr.cpp

/*	countchr.cpp				12-28-96
	Copyright (C)1996 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	counts number of occurrences of a char in a string.  Pulled from code.cpp.

*/
#include "c:\bcs\my.h"

//////////////////////////////////////////////////////////////////////////////
uint countchr(const string& s, char ch)	// string to search, char to look for
{
	int count = 0;
	int N = s.length();
	for(int i = 0 ; i < N ; i++)
		if(s[i] == ch)
			count++;
	return(count);
}

isallspa.cpp

/*  isallspa.cpp		isallspace()		3-12-96
	Copyright (C)1996 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	Returns TRUE if char array is zero-length or all whitespace, FALSE otherwise.
	Could add additional version for a const string&

*/
#include <stdio.h>
#include <ctype.h>
#include "c:\bcs\my.h"

BOOL isallspace(char *s)
{
	char *p = s;
	while(*p)
		if(!isspace(*(p++)))	// first non-space char causes return
			return(FALSE);
	return(TRUE);
}

logerror.cpp

/*	logerror.cpp			1/7/02
	Copyright (C)2000, 2002, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	functions for appending strings to text files:
	logs an error string to an error log file, and keeps count.
*/
#include <classlib\time.h>
#include "c:\bcs\my.h"
//-----------------------------------------------------------------------
// append a string to a text file.
uint logtofile(const string& s, const string& filename)
{
if(s.length()&& filename.length())
{
	ofstream(filename.c_str(),ios::app) << s << endl;
	return(1);
}
return(0);
}							//logtofile
//-----------------------------------------------------------------------
// write error (if provided) to disk.  returns cumulative error count.
// you can call with empty string just to get the count.
uint logerror(string error, string filename, BOOL beep)
{
static uint errorcount = 0;			// # of errors
if(error.length())					// if an error occurred,
{
	ostrstream os;
	os << TTime() << ":  " << error << ends;
	logtofile(os.str(),filename);
	if(beep)						// note: only beeps if we're writing an error
	{
		#if defined(_Windows)
			MessageBeep(MB_ICONEXCLAMATION);	// a global WinSDK function
		#else
			cout << "\a";
			// 	SerialCom.Send(os.str());
		#endif
	}

	delete[] os.str();
	errorcount++;
}
return(errorcount);
}						//logerror
//----------------------------------------------------------------------------

lrandom.cpp

/*	lrandom.cpp				3-12-03
	Copyright (C)1996-99, 2003, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	Contains lrandom() and any other specialized random number generators I need.

*/
#include <stdlib.h>
#include <math.h>
#include "c:\bcs\my.h"

//----------------------------------------------------------------------------
// returns a uniformly distributed random double in the range 0 (inclusive) to 1.0 (limit).
// builds as text because that's the only way I could think of that seems foolproof.
// There are some pitfalls to generating random numbers; see a severe one below.
// this is very fast, and works for DOS, Win16, and Win32.
// this method seems to work properly, based on running the results through stats.exe.
double frand()
{
int len = 17;	// "0." plus 15 significant digits is max possible for a double.
char buf[18];	// must be len + 1

buf[0] = '0'; buf[1] = '.';
for(int i = 2 ; i < len ; i++)
{
	// you cannot use random() here because in Win32 random() calls lrandom(), which
	// calls this, creating an infinite recursion, stack overflow, and crash.
	// the method highlighted here is the definition of random() from stdlib.h
	// and is equivalent to random(10).
	//                     vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
	buf[i] = (char)(0x30 + (int)( ((long)rand() * 10) / (RAND_MAX + 1) ));
}
buf[len] = 0;
return(atof(buf));
}   							//frand
//----------------------------------------------------------------------------
// Returns a long random number from 0 to specified upper limit - 1, inclusive.
// This is random() for longs, and I use it as replacement random() for Win32.
// For a possibly negative random number, use this, and then if(random(2)) { make it negative }
// this is very fast, and seems to work, based on running the results through stats.exe.
//
// In Win32 only, Borland has a function _lrand(), which returns a random long
// value (probably 0 to LONG_MAX), but you can't scale it to a different interval
// by the usual method because the result of the required multiplication can
// overflow LONG_MAX and even ULONG_MAX, and that's the largest integral value
// the computer can handle.  Borland's stdlib.h method of using % operator doesn't
// work, in that random(N) has a repeat cycle of N if N is a power of 2, probably
// because of coincidence(?) with cycles inherent in the random # generation.
long lrandom(long top)
{
if(top <= 1L)			// 0, 1 always produce 0, and negative is illegal
	return(0L);
return(frand() * top);
}           	            	//lrandom
//----------------------------------------------------------------------------
// returns a normally distributed random INTEGER from the distribution with the
// given mean and standard deviation, using the method from the TI-59 calculator book
// TI Programmable 58/59 Applied Statistics using the power of your Solid State Software(tm)
// module, (C)1977 Texas Instruments, p.2-6.
int NormalRandom(double mean, double stddev)
{
return round(sqrt(-2.0 * log(frand())) * cos(2.0 * M_PI * frand()) * stddev + mean);
}   							//NormalRandom
//----------------------------------------------------------------------------


//////////////////////////////////////////////////////////////////////////////
// DEAD STORAGE SECTION:
//----------------------------------------------------------------------------
#if 0
// keep this section as a useful warning about the method and any like it.
//----------------------------------------------------------------------------
// #ERROR I THINK THIS ENTIRE METHOD IS UNWORKABLE DUE TO CENTRAL TENDENCY:
// The mean of the aggregate rand() calls is 16k, and the more times (N) you call it,
// the closer their sum will approximate N * 16k. So the random numbers are NOT
// uniformly distributed within the range. This result was verified using test runs.
//
// Notes: RAND_MAX = 32767, LONG_MAX = 2147483647L, ULONG_MAX = 4294967295UL
// method: since rand() can only return an int <= RAND_MAX, determine how many maximum
// rand() intervals are contained in "top".  Calculate rand() for each interval and add
// them together.  Then there's one interval left: the remainder.  Get a random number
// < remainder, add it to the rest, and the result is a random number that could be
// from 0 to top-1.
long lrandom(long top)
{
	if(top <= 1L)			// 0, 1 always produce 0, and negative is illegal
		return(0L);
	long randomnumber = 0L;
	for(long intervals = (top - 1L) / (long)RAND_MAX ; intervals > 0L ; intervals--)
	{
		long i = (long)rand();
		randomnumber += i;
	}
	long remainder = top % (long)RAND_MAX;	// the final interval
	if(remainder == 0L)
		remainder = (long)RAND_MAX;
	// remainder is relatively small, <= RAND_MAX, and overflow impossible,
	// so explicitly use the usual formula for random(top) (see stdlib.h)
	// whose maximum return is (top - 1).  We can't actually use random()
	// because in original flat model, it was redefined and didn't work,
	// and in my new method, it's redefined to use lrandom, which would
	// create endless recursive calls back here.
	randomnumber += ((remainder * (long)rand()) / ((long)RAND_MAX + 1L));
	return(randomnumber);
}           	            	//lrandom
#endif 	// 0
//----------------------------------------------------------------------------

 mystring.cpp

/*	mystring.cpp			8-23-01
	Copyright (C)1997-2001, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

------
Notes:

Additional string functions, including fixes for apparent bugs in the Borland string class.

This file cannot be precompiled.  #include AFTER my.h wherever you use it.
It is automatically included into mylib.cpp.

In DOS, you will get 2 "duplicated symbol" warnings for the string functions.
In Win, you don't get those warnings, possibly because Win calls library
functions from a DLL at runtime, and then only if a static-linked version isn't
already in the program.

//----------------------------------------------------------------------------
Bugs in the Borland C++ 4.0 cstring library:

operator >> and read_token():
string.length() is corrupted after input if the istream buffer does not contain trailing
whitespace before EOF.  The text of the string itself is properly read, but subsequently
anything that uses length(), including [], fails. (HOW?  retest and document)
string += string doesn't work, but string + string does (in another test, it didn't).

It is possible that these buggy functions do work properly when the default values
of paranoid_check (especially), skipwhite, and/or case_sensitive are in effect.
(This is true for rfind().)  In most of my programs, I have NOT been using the default
values for these.  Surprisingly, the string class appears to be one of the more recent ones,
with documentation that appears hastily prepared and has errors.
Static linked code for string classes is in C?.LIB files.

//----------------------------------------------------------------------------
*/
#ifndef __MYSTRING_CPP
#define __MYSTRING_CPP

#include "c:\bcs\my.h"   		// just in case it hasn't been already

//////////////////////////////////////////////////////////////////////////////
#if 0
//////////////////////////////////////////////////////////////////////////////
// OBSOLETE.  keep only as long as useful for reference or backup.
//----------------------------------------------------------------------------
// 2-26-98
// skips leading whitespace, reads a string from the stream, stopping at whitespace or EOF.
// Causes stream to fail only if nothing, or only whitespace, was read,
// in which case the target string s remains unchanged.
// This should be an exact replacement for buggy version.  No length limit.
istream _FAR & _Cdecl _FARFUNC operator >> (istream _FAR &is, string _FAR &s)
{
int i;
string temp;                // so s won't be changed if nothing is read.
is >> ws;					// discard leading space
while(1)
{
	i = is.peek();
	if((i == EOF) || isspace(i))	// non-whitespace control chars can be part of string
		break;
	temp += (char)(is.get());		// append the char to string
}
if(temp.length())
	s = temp;
return(is);
}                       	// old operator >>
//////////////////////////////////////////////////////////////////////////////
#endif 	// 0


//////////////////////////////////////////////////////////////////////////////
// BUG FIXES
//----------------------------------------------------------------------------
// 2-28-99
// skip leading whitespace, and read a string from a stream, up to whitespace or EOF.
// This should be an exact replacement for the buggy version, plus an enhancement:
// It can also read quoted multi-token strings:
// If first char encountered is a QUOTE, reads everything up to the closing QUOTE.
istream _FAR & _Cdecl _FARFUNC operator >> (istream _FAR &is, string _FAR &s)
{
// so s won't be changed if nothing is read for single token,
// and to protect s from error when reading quoted string with read_to_delim.
string temp;

is >> ws;					// discard leading space
int i = is.peek();          // peek the first char

// if first char encountered is a quote, read the quoted string.
// a null string ("") will empty s, allowing writing and retrieving empty
// strings from a file, which ordinarily is not possible.
if(i == '\"')
{
	is.get();				// get the first quote

	// For now, trust read_to_delim.  it is fine as long as the delim is present.
	// if EOF is hit before delim, it will return the stream as failed NOW,
	// even if something was legitimately read into the string.  Thus, in this case,
	// while(istream >> s) will stop prematurely, the loop not being executed
	// for the last string read.  BUT this may be good, because if delim was not
	// present, the file may be corrupt and the input invalid.
	// Note that if this happens, although the last string read won't be processed,
	// there won't be any warning about the situation.

	// read up to the trailing quote, and extract and discard the quote
	temp.read_to_delim(is,'\"');

	// if read_to_delim has bugs, reading into temp might protect s from corruption.
	// getline(is, s, '\"'); might also be an alternative
	s = temp;
	return(is);
}
// if it falls through, read an ordinary 1-token string.
// causes stream to fail now only if nothing, or only whitespace, is read,
// in which case the target string s remains unchanged.
while(1)
{
	// on entry, i already contains the original peek
	if((i == EOF) || isspace(i))	// non-whitespace control chars can be part of string
		break;
	temp += (char)(is.get());		// append the char to string
	i = is.peek();         			// peek at the next one
}
if(temp.length())					// if nothing, s is unchanged.
	s = temp;
return(is);
}                       	// operator >>
//----------------------------------------------------------------------------
// 2-26-98
// skip leading whitespace, and read one token from a stream,
// stopping at whitespace or EOF.  Does NOT handle quoted strings,
// since a token should be just 1 word or equivalent.
// This is almost identical to the earlier operator >>, before enhancement.
istream _FAR & string::read_token(istream _FAR &is)
{
int i;
string temp;                // so s won't be changed if nothing is read.
is >> ws;					// discard leading space
while(1)
{
	i = is.peek();
	if((i == EOF) || isspace(i))	// non-whitespace control chars can be part of string
		break;
	temp += (char)(is.get());		// append the char to string
}
if(temp.length())
	*this = temp;
return(is);
}                      		// read_token
//----------------------------------------------------------------------------
// 7-4-00
// if paranoid_check is ON, the original rfind always returns NPOS for a multi-char s.
// otherwise, it seems to work ok.
//
// A better solution MAY be just to turn paranoid check OFF and watch for any problems.
// That's what I'm currently doing, and is why this fix is disabled.
// Paranoid check does have an inherent problem in that it will consider a string with
// embedded zeroes to terminate at the first zero.
//
// In a brief test, this version seems to do what it's supposed to, but makes no use of
// paranoid_check or any other string settings.
// throw() means it does NOT throw anything.
#if 0
size_t _RTLENTRY string::rfind(const string _FAR &s, size_t pos) const throw()
{
size_t u = find(s);
if(u == NPOS)							// if not found at all, quit
	return(NPOS);
size_t temp;
while((temp = find(s, u + 1)) < pos)	// find next occurrence beyond u, but not
	u = temp;							// at or beyond pos.
return(u);
}							//rfind
#endif	// 0
//----------------------------------------------------------------------------
// 							END BUG FIXES
//////////////////////////////////////////////////////////////////////////////
// MORE STRING FUNCTIONS
// If I ever create a true library, these should go in their own source files.
//----------------------------------------------------------------------------
// change a string to "title case", all lower case except first letter of each word
string& titlecase(string& s)
{
s.to_lower();      							// start with all lower case

BOOL spacebefore = TRUE;               		// whether the previous char was space
for(int i = 0 ; i < s.length() ; i++)
{
	if(spacebefore)
		s[i] = (char)toupper(s[i]);
	spacebefore = !isalnum(s[i]);
}
return(s);
}    						// titlecase
//----------------------------------------------------------------------------
// for one-step output of a string in quotes: cout << qstring(s). source string is unchanged.
string qstring(const string& s)
{
	string t(s);
	t += ("\"");
	t.prepend("\"");
	return(t);
}							// qstring
//----------------------------------------------------------------------------
// remove the quotes from around a quoted string.  source string is unchanged.
string unqstring(const string& s)
{
string t(s);
if((t.length() >= 2) && (t[0] == '\"') && (t[t.length() - 1] == '\"'))
{
	t.remove(0,1);
	t.remove(t.length() - 1);
}
return(t);
}							// unqstring
//----------------------------------------------------------------------------
// for one-step output of a string in brackets: cout << bstring(s). source string is unchanged.
string bstring(const string& s)
{
	string t(s);
	t += ("]");
	t.prepend("[");
	return(t);
}							// bstring
//----------------------------------------------------------------------------
// fromstring													1-1-99
// A strings-only override of my template version. Necessary because if this situation
// fromstring(string,string) were in template version, the compiler, when instantiating the template,
// would have to GENERATE the code for the line (below) "var = value" for ALL instantiations,
// including those where that line is inapplicable because the types are not the same.
// But if the types aren't the same, the code itself is illegal, a compile-time error.
// (and there's no RTTI at compile time, so you can't conditionally exclude the code)
// (am I sure there's not?  Even if there is, probably not for templates.)
// copies ALL of a multi-word string, which the >> procedure in template version would not.
string& fromstring(string& var, const string& value)
{
	var = value;   		// just copy the whole string
	return(var);
}                      		// fromstring
//----------------------------------------------------------------------------
// measures how similar two strings, usually tokens (single words), are.
// This is an experimental concept that was interesting to work on.
// I think this is used in wtalk.cpp; some other programs have similarity() or
// SimilarityTo() functions that explore a more generalized concept of measuring
// "similarity" of two objects.
// returns a value between 0 (no similarity at all) and 1.0 (identical)
// Measure is the same regardless of which string is first or second.
double similarity(const string& first, const string& second)
{
string shorter = first, longer = second;	// copy to local for use

if(!shorter.length() && !longer.length())	// 2 empties are equal.
	return(1.0);
if(!shorter.length() || !longer.length())	// now require both to have length
	return(0.0);
if(shorter.length() > longer.length())		// comparisons easier if we know which is which
	swap(shorter,longer);

// calculates return value as a percentage of longer, so a short word that "contains" shorter
// is a better match than a longer word that also does.  if they're equal, score = 1.0
double denominator = longer.length();		// save now; processing may destroy the string

//----------
// Version 3.  NEWER version OF version 1!  More restrictive.
// find what chars they share at the exact same locs.  no displacements allowed for.
// you don't want "UNfastened" to match "fastened", which version 1 would do.
// e.g. run and ran match 2 chars in order, = 2/3 = .67 match.
uint count = 0;						// count of matching chars
for(uint i = 0 ; i < shorter.length() ; i++)
	if(shorter[i] == longer[i])
		count++;
return(count / denominator);
//----------

#if 0
//----------
// Version 2.  Still not convinced I've found a satisfactory one.
// newest version.  It destroys the strings as it finds matches.
// it tends to overrate the degree of match.
uint totmatches = 0;						// total matching chars found
while(shorter.length() && longer.length())
{
	// in each string, delete all chars that don't occur in the other.
	// those chars can't possibly match.  Do it each loop pass because a char can
	// become newly unmatched when one string has more occurrences of it than the other.
	size_t u;
	while((u = shorter.find_first_not_of(longer)) != NPOS) shorter.remove(u,1);
	while((u = longer.find_first_not_of(shorter)) != NPOS) longer.remove(u,1);

	// if either was emptied, further matches are impossible
	if(!shorter.length() || !longer.length())
		break;
	if(shorter.length() > longer.length())		// test again
		swap(shorter,longer);

	uint matches = 0;			// new char matches found during this loop pass
	// find, tally, and delete any sequential leading matching chars (prefixes)
	while(shorter.length() && (shorter[0] == longer[0]))
	{
		matches++;
		shorter.remove(0,1);
		longer.remove(0,1);
	}
	// start from the other end and work backwards.
	// This will find matching suffixes in strings of different length.
	int i = shorter.length() - 1;
	int j = longer.length() - 1;
	for( ; shorter.length() && (shorter[i] == longer[j]) ; i--, j--)
	{
		matches++;
		shorter.remove(i,1);
		longer.remove(j,1);
	}
	if(matches)     				// if new matches were found
		totmatches += matches;
	else       						// if no new matches, MUST prevent endless loop
		break;						// in case strings still have contents.
}									//while(shorter.length() && longer.length())
// experimental final test (from below), untested even on paper.
// strings may have substantial internal matches that still haven't been caught.
// (such as when they're displaced by one loc).  I don't do this inside loop
// because doing it multiple times looks like it can degenerate into "matching
// chars regardless of order", which must be avoided.

// test yet again
size_t u;
while((u = shorter.find_first_not_of(longer)) != NPOS) shorter.remove(u,1);
while((u = longer.find_first_not_of(shorter)) != NPOS) longer.remove(u,1);
if(shorter.length() > longer.length())
	swap(shorter,longer);

uint highcount = 0;						// longest sequence of matching chars
uint remaining = shorter.length();      // chars left to search in shorter
for(uint i = 0 ; (i < shorter.length()) && (highcount < remaining) ; i++, remaining--)
{
	uint j = longer.find(shorter[i]);
	if(j != NPOS)           			// if first char found, search subsequent chars
	{
		uint count = 0;
		for(uint k = i ; (k < shorter.length()) && (j < longer.length()) ; k++, j++)
			if(shorter[k] == longer[j])
				count++;
		highcount = max(highcount,count);
	}
}
totmatches += highcount;
return(totmatches / denominator);

//----------
// version 1.  seems to work better than Version 2.
// find what chars they share in the same order.
// Start a new search at EACH position in shorter, and use the highest count found.
// the first nonmatching char does not abort the search.  internal nonmatches are allowed.
// #error DOES THIS ACCURATELY DESCRIBE WHAT'S BELOW? NO.
// e.g. run and ran match 2 chars in order, = 2/3 = .67 match.
// You could also factor in a measure of the displacements of the shared chars
// (i.e. they match, but are not at exactly the same locs in the strings), using a method
// similar to that for the Q-set deck, but it doesn't seem that useful or necessary.
uint highcount = 0;						// longest (maybe broken) sequence of matching chars
uint remaining = shorter.length();      // chars left to search in shorter
// for speed, if there's not enough string left to search to improve highcount, quit looking.
for(uint i = 0 ; (i < shorter.length()) && (highcount < remaining) ; i++, remaining--)
{
	uint j = longer.find(shorter[i]);
	if(j != NPOS)           			// if first char found, search subsequent chars
	{
		// a test here similar to "remaining", above, is more trouble than it's worth.
		uint count = 0;
		for(uint k = i ; (k < shorter.length()) && (j < longer.length()) ; k++, j++)
			if(shorter[k] == longer[j])
				count++;
		highcount = max(highcount,count);
	}
}
return(highcount / denominator);

//----------
// in oldest version, this was the final step.
// This section is useless, *especially* for strings.  Kept only for the method.
// find what percent of the chars in shorter are found in longer, regardless of order.
// this test destroys longer
highcount = 0;
for(i = 0 ; i < shorter.length() ; i++)
{
	uint j = longer.find(shorter[i]);
	if(j != NPOS)						// char was found
	{
		highcount++;             		// increment count
		longer.remove(j,1);             // remove the char so it doesn't get found again
	}
}
double anyorder = (double)highcount / (double)shorter.length() * .25;
#endif 0

}							//similarity
//----------------------------------------------------------------------------
// returns string with each LF changed to CR.  source string is unchanged.
string LFtoCR(const string& s)
{
string t;
for(uint i = 0 ; i < s.length() ; i++)
	if(s[i] == '\n')
		t += '\r';
	else
		t += s[i];
return t;
}                   		//LFtoCR
//----------------------------------------------------------------------------
// returns string with each CR changed to LF.  source string is unchanged.
// useful for making text from a TEdit suitable for writing to disk in text mode,
// (will prevent writing double-CRs).
// #error (where, if anywhere, do I use this?  It would change CRLF to LFLF.)
string CRtoLF(const string& s)
{
string t;
for(uint i = 0 ; i < s.length() ; i++)
	if(s[i] == '\r')
		t += '\n';
	else
		t += s[i];
return t;
}                   		//CRtoLF
//----------------------------------------------------------------------------
// returns string with each LF changed to CRLF.  source string is unchanged.
// useful for output to modem or to a TEdit.
string LFtoCRLF(const string& s)
{
string t;
for(uint i = 0 ; (i < s.length()) && (t.length() < NPOS) ; i++)
{
	if(s[i] == '\n')
		t += '\r';		// insert CR before LF
	t += s[i];
}
return t;
}                   		//LFtoCRLF
//----------------------------------------------------------------------------
// returns string with each CRLF changed to LF.  source string is unchanged.
string CRLFtoLF(const string& s)
{
string t(s);
size_t u;
while((u = t.find("\r\n")) != NPOS)		// find each CRLF
	t.remove(u,1);						// only remove each CR
return t;
}                   		//CRLFtoLF
//----------------------------------------------------------------------------
// 8/23/01
// These fns I've implemented as string class MEMBERS, and declared in cstring.h.
// To use, you must also declare them in cstring.h (the string class header file).
//----------------------------------------------------------------------------
int _RTLENTRY string::startswith( const string _FAR &s ) const THROW_NONE
{ return(find(s) == 0); }
//----------------------------------------------------------------------------
int _RTLENTRY string::endswith( const string _FAR &s ) const THROW_NONE
{ return( rfind(s) == (length() - s.length()) ); }
//----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////
#endif			// __MYSTRING_CPP

strand.cpp

/* 	strand.cpp		STRing AND				12-2-96
	Copyright (C)1996, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	An "AND" operator for strings.
	Searches a given string (such as "ABCDE") for a pattern given by another
	string (such as "?B??E", where the question marks are "don't care").
	The above example would return TRUE, because the target string does
	contain a B in the 2nd position, and E in the 5th.
	Returns TRUE if pattern matched, FALSE if not.

	Used in CLASSIFY.CPP.  Another planned use for this is in LIFE.C,
	for matching strings that encode the neighboring colors around a pixel.
	See paper file A-LIFE in file cabinet.

	Briefly tested, seems to work ok.

*/
#include <stdio.h>
#include <cstring.h>
#include "c:\bcs\my.h"

//----------------------------------------------------------------------------
// string to search, pattern to search for, the dont-care char in pattern.
BOOL strand(const char *searchin, const char *pattern, char dontcare)
{
if(strlen(pattern) > strlen(searchin))	// can't find pattern in a shorter string
	return(FALSE);

int slen = strlen(pattern);
for(int i = 0 ; i < slen ; i++)
	if(pattern[i] != dontcare)
		if(pattern[i] != searchin[i])
			return(FALSE);
return(TRUE);
}

//----------------------------------------------------------------------------
// version for strings
BOOL strand(const string& searchin, const string& pattern, char dontcare)
{
if(pattern.length() > searchin.length()) // can't find pattern in a shorter string
	return(FALSE);
int slen = pattern.length();
for(int i = 0 ; i < slen ; i++)
	if(pattern[i] != dontcare)
		if(pattern[i] != searchin[i])
			return(FALSE);
return(TRUE);
}

gettoken.cpp

/*	gettoken.cpp			5-16-00
	Copyright (C)1995-2000, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	Token extraction functions and sentence extraction functions.
	A token is a punctuation mark or an alphanumeric string, which can contain
	hyphens or apostrophes.  This is DIFFERENT from what string::read_token() extracts.

*/
#include "c:\bcs\my.h"

//----------------------------------------------------------------------------
// get token from a string
// this has a minor unfixable bug: if the source string ends with a "-" (such as might
// happen when reading lines from a file), it means the token continues on the next line,
// but this function must quit looking because the source string is used up.
//
// returns the index of the location in the provided string that is 1 char beyond
// all skipped chars and the gotten token (might be beyond end of string, too).
// or 0 if no token was created.  If it returns 0, it also means there is nothing
// left to get.  You can use: while(gettoken()){...};
//
// sentence to scan, start, token holder
uint gettoken(const string& s, unsigned startpos, string& buf)
{
buf.remove(0);		// must empty each call: it's a reference, and we're using +=

if(startpos >= s.length())				// startpos invalid index
	return(0);                        	// means string is used up

int i = (int)startpos;                  // pointer into s
while(iscntrl(s[i]) || (s[i] == ' '))   // skip over control-chars (incl. nulls) & spaces
	if(++i >= s.length())               // string ended
		return(0);                   	// before any valid token-starting char found

// got to here means there is a token to be got
if(ispunct(s[i]))                   	// punctuation
{                    // identical multiples, like --, allowed.  Also gets "" as 1 token
	string t = "?!";					// allows !?  ?!?!?!  ???! etc. as a single token.
	char ch = s[i];
	while((s[i] == ch) || (t.contains(s[i]) && t.contains(ch)) )
	{
		buf += s[i];
		if(++i >= s.length())  			// hit end of string
			break;
	}
}
else             // alphanumeric, and non-leading hyphens, apostrophes all legal
	while(isalnum(s[i]) || (s[i] == '-') || (s[i] == '\''))
	{
		buf += s[i];
		if(++i >= s.length())  			// hit end of string
			break;
	}
return(i);              				// return new search-start loc.
}                    	// end gettoken
//----------------------------------------------------------------------------
// get token from a stream
// returns number of chars in the retrieved token.  if 0, there is also nothing more to get.
// You can use: while(gettoken()){...};
uint gettoken(istream& is, string& buf)	// stream to read from, token holder
{
buf.remove(0);			// must empty each call: it's a reference, and we're using +=

char ch = ' ';
while(iscntrl(ch) || (ch == ' '))   	// skip over control-chars (incl. nulls) & spaces
	if(!is.get(ch))						// stream used up
		return(0);	                    // before valid token-starting char found
										// got to here means there is a token to be got
if(ispunct(ch))                   		// punctuation
{                                       // identical multiples, like --, allowed)
	string t = "?!";					// allows !?  ?!?!?!  ???! etc. as a single token.
	char p;
	buf += ch;
	// peek() can only return a value that will fit into a char.
	// you should decide schar vs. uchar, but probably makes no difference. 
	while(is.good() && (((p = (char)(is.peek())) == ch) || (t.contains(p) && t.contains(ch))))
	{
		is.get(ch);
		buf += ch;
	}
}
else             // alphanumeric, and non-leading hyphens, apostrophes all legal
{
	buf += ch;
	int test = is.peek();
	while(is.good() && (isalnum(test) || (test == '-') || (test == '\'')))
	{
		is.get(ch);
		buf += ch;
		if(ch == '-')					// if the char is a hyphen, extract and discard
			is >> ws;					// trailing or line-ending whitespace, if any
		test = is.peek();
	}
}
return(buf.length());
}                    		// gettoken
//----------------------------------------------------------------------------
// returns TRUE if token is a type that terminates a sentence
BOOL isterminator(const string& s)
{
if( (s == ".") || (s == ";") ||
// 	(s == ":") || 					// unsure about ":". for now, it's not a term.
	s.contains("...") || s.contains("?") || s.contains("!") )
		return(TRUE);
return(FALSE);
}                     		//isterminator
//----------------------------------------------------------------------------
// get a sentence from a string
// returns the index of the location in the provided string that is 1 char beyond
// all skipped chars and the gotten sentence (might be beyond end of string, too).
// or 0 if no sentence was created.  0 also means there is nothing left to get.
// You can use: while(getsentence()){...};
// text block to scan, starting position, sentence holder
uint getsentence(const string& source, uint startpos, string& sentence)
{
sentence.remove(0);  				// always empty it at start
if(startpos >= source.length())		// source used up?
	return(0);
string token;
while((startpos = gettoken(source,startpos,token)) != 0)
{
	sentence += token + " ";
	if(isterminator(token))    		// end of sentence?
		break;
}
if(sentence.length() && !isterminator(token)) 	// if it has contents, and no terminator,
	sentence += ".";							// give it one.
sentence = sentence.strip(string::Both);

// if gettoken failed, we might first have gotten a sentence before it did.
// so THIS function shouldn't report failure until the next call.
if(!startpos && sentence.length())
	startpos = source.length();		// set startpos so next call fails

return(startpos);
}                    		//getsentence
//----------------------------------------------------------------------------
// extract a sentence from a stream.
// returns number of chars in the retrieved sentence.  if 0, there is also nothing more to get.
// You can use: while(getsentence()){...};
uint getsentence(istream& is, string& sentence)
{
sentence.remove(0);  				// always empty it at start
string token;
while(gettoken(is,token))
{
	sentence += token + " ";
	if(isterminator(token))    		// end of sentence?
		break;
}
if(sentence.length() && !isterminator(token)) 	// if it has contents, and no terminator,
	sentence += ".";							// give it one.
sentence = sentence.strip(string::Both);
return(sentence.length());
}                    		//getsentence
//----------------------------------------------------------------------------

tranctrl.cpp

/*	tranctrl.cpp			11-5-99
	Copyright (C)1999, 2006 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

*/
#include "c:\bcs\my.h"

//----------------------------------------------------------------------------
// replaces control chars in a string with their corresponding ASCII mnemonics.
// CRLF turns into the STRING "<CR><LF>", etc.
// returns a string containing the translation; source string s is unchanged.
string TranslateControls(const string& s)
{
static char* ControlText[32] =
{
	"<NUL>","<SOH>","<STX>","<ETX>","<EOT>","<ENQ>","<ACK>","<BEL>","<BS>","<HT>",
	"<LF>","<VT>","<FF>","<CR>","<SO>","<SI>","<DLE>","<DCl>","<DC2>","<DC3>",
	"<DC4>","<NAK>","<SYN>","<ETB>","<CAN>","<EM>","<SUB>","<ESC>","<FS>","<GS>",
	"<RS>","<US>"
};
string t;
int ch;
for(int i = 0 ; i < s.length(); i++)
{
	ch = s[i] & 0xFF;			// mapdown into ASCII range
	if(ch < 32)
		t += ControlText[ch];	// control code
	else
		if(ch == 127)        	// special, DEL is out of normal sequence
			t += "<DEL>";
		else
			t += s[i];			// normal char (retains original parity bit, if set)
}
return(t);
}                 		//TranslateControls

datetime.cpp

//----------------------------------------------------------------------------
// datetime.cpp               4/14/2000
// Fix for Y2K bug in Borland C++ 4.0 class TTime.  Overrides library version.
// Could just change the code in time.cpp, but this override avoids recompiling the libraries.
//----------------------------------------------------------------------------
#if defined(__CLASSLIB_TIME_H)
	// default constructor: creates a TTime object with the current date and time.
	TTime::TTime()
	{
		//----------------------------------------------------------------------------
		// one revised version, which works.
		// struct time t;
		// gettime(&t);
		// *this = TTime(TDate(), t.ti_hour, t.ti_min, t.ti_sec);
		//----------------------------------------------------------------------------
		// but this version is more like the original.  Although I don't use them,
		// it makes use of localtime's adjustment features.  And is more portable.
		time_t ltime;
		time(&ltime);
		struct tm _FAR *t = localtime(&ltime);
		// the following line uses the TDate() default constructor for today's date, which is Y2KOK.
		// the version in time.cpp uses an explicit TDate constructor that is not Y2KOK
		// because it relies on Jday(), which is not Y2KOK.
		*this = TTime(TDate(),(HourTy)t->tm_hour,(MinuteTy)t->tm_min,(SecondTy)t->tm_sec);
	}
	// If you revise the TDate operator << below, you should insert HERE
	// the entire body of the following function from timeio.cpp:
	// ostream _BIDSFAR & _BIDSFUNC operator << (ostream _BIDSFAR & s, const TTime _BIDSFAR & t)
	// You must supply it here; otherwise, the existing library version of << will be used, instead.

#endif	// (__CLASSLIB_TIME_H)

//----------------------------------------------------------------------------
// 4/14/00
// Minor mod to output of TDate, so numeric fields are always 2 digits wide, zero-filled: 01-01-96
// modified from date.cpp. It also needs a revised Jday(). (don't bother for now)
// note the accidental *extra* underline before DATE in next line, to match the .H file's #define.

#if defined(__CLASSLIB__DATE_H)

#if 0

ostream _BIDSFAR & _BIDSFUNC operator << (ostream _BIDSFAR & s, const TDate _BIDSFAR & d)
{
	// In order to implement this change, insert here a revised version of this function from date.cpp
	// insert << setfill('0') << setw(2) before the output of fields you want to make 2-digits.
}

#endif  // 0

#endif	//(__CLASSLIB__DATE_H)

rounding.cpp

/*	rounding.cpp		2/13/03
	Copyright (C)2000, 2003 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	rounding function for converting the result of a double calculation to int,
	such that "rounding up" always means increasing the magnitude in the correct
	direction from zero: positive #s are rounded up, negative #s rounded down.
	This might be achievable using floor() or ceil(), but I think I decided it wasn't.

*/
#include "c:\bcs\my.h"

//----------------------------------------------------------------------------
// duplicates of this may exist local to some project. also keep a watch for places where I
// now round incorrectly or not at all, and could use this instead.
// usage: int x = round(speed * sine(30) * x);
int round(double d)
{
if(d > 0)    		// if positive, make more positive before rounding
	d += .5;
else
	if(d < 0)    	// if negative, make more negative before rounding
		d -= .5;
return(d);			// truncates decimal portion
}
//----------------------------------------------------------------------------

sine.cpp

/*	sine.cpp					7-9-99
	Copyright (C)1997 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	Same as sin(), but takes an argument in degrees instead of radians.
*/
#include <stdio.h>
#include <math.h>
#include "c:\bcs\my.h"

double sine(double degrees)
{
	return(sin(degrees * M_PI_180));		// radians = degrees * pi/180
}

cosine.cpp

/*	cosine.cpp				7-9-99
	Copyright (C)1997 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	Same as cos(), but takes an argument in degrees instead of radians.
*/
#include <stdio.h>
#include <math.h>
#include "c:\bcs\my.h"

double cosine(double degrees)
{
	return(cos(degrees * M_PI_180));		// radians = degrees * pi/180
}

 


trigtabl.h

/*	trigtabl.h			6-27-99
	Copyright (C)1997-99 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	A sine/cosine lookup table for whole degrees.
*/
#ifndef __TRIGTABL_H
#define __TRIGTABL_H

//////////////////////////////////////////////////////////////////////////////
//
struct Trigtable
{
	Trigtable();

	double cosines[360];
	double sines[360];
};
//////////////////////////////////////////////////////////////////////////////
#endif			// __TRIGTABL_H

trigtabl.cpp

/*	trigtabl.cpp		7-9-99
	Copyright (C)1997-99 Steven Whitney.
	Published under GNU GPL (General Public License) Version 2, with ABSOLUTELY NO WARRANTY.

	A sine/cosine lookup table for whole degrees.
*/
#include "c:\bcs\library\trigtabl.h"

//----------------------------------------------------------------------------
// constructor
Trigtable::Trigtable()
{
	for(int i = 0 ; i < 360 ; i++)
	{
		cosines[i] = cosine(i);
		sines[i] = sine(i);
	}
	// set some exact entries to avoid rounding errors.
	cosines[90] = cosines[270] = sines[0] = sines[180] = 0;
	cosines[0] = sines[90] = 1;
	cosines[180] = sines[270] = -1;
	sines[30] = sines[150] = cosines[60] = cosines[300] = .5;
	sines[330] = sines[210] = cosines[120] = cosines[240] = -.5;
}
//----------------------------------------------------------------------------

 

 

Valid HTML 4.01 Transitional Valid CSS
View content labeling at ICRA.
Copyright ©2008 Steven Whitney. Last modified 02/27/2008.