frontier5.5 picture




macos picture

windows picture




Powerful
cross-platform
web scripting
Home
Frontier5
Download
Mail
Docs
Bugs
Outline
Thanks!

ODB Engine Sample App

File:main.c
Created:5/29/97; 11:12:27 AM
Modified: 5/29/97; 11:43:08 AM
/*© copyright 1996 UserLand Software, Inc. All Rights Reserved.*/
 
 
/*
ODB Tester -- Demonstrates the use of Frontier's "ODB Engine" library.
*/
 
#ifdef __MWERKS__
	#if __INTEL__
		#define WIN95VERSION
	#else
		#define MACVERSION
	#endif
#endif
 
#define NEWFILETESTER 1
#define PASCALSTRINGVERSION 1
 
typedef unsigned char byte, *ptrbyte;
 
 
#ifdef MACVERSION
	#include <odbEngine.h>
	#include <StandardFile.h>
	#include <Folders.h>
#endif
 
#ifdef WIN95VERSION
	#define WIN32_LEAN_AND_MEAN 1
	#include <windows.h>
	#include <stdio.h>
	#include "odbEngine.h"
 
	#define true 1
	#define false 0
	#define nil NULL
 
	typedef short Boolean;
	typedef byte Str255[256];
 
	extern void GetDateTime (long * secs);
	extern Handle frontierAlloc (long userSize);
	extern long frontierSize (Handle foo);
	extern Handle frontierReAlloc(Handle fooIn, long userSize);
 
	#define GetHandleSize(foo) frontierSize(foo)
	#define NewHandle(fooSize) frontierAlloc(fooSize)
	#define DisposeHandle(foo) GlobalDiscard(foo)
	#define SetHandleSize(h,foosize) frontierReAlloc(h,foosize)
#endif
 
#ifdef MACVERSION
	WindowPtr mainwindow = nil; /*the menu sharing test window*/
 
	Str255 windowmessage; /*the message that's displayed in the main window*/
#endif
 
 
 
static void initmacintosh (void) {
#ifdef MACVERSION
 
	/*
	the magic stuff that every Macintosh application needs to do 
	before doing anything else.
	*/
 
	short i;
	
	MaxApplZone ();
 
	InitGraf (&qd.thePort);
 
	InitFonts ();
 
	FlushEvents (everyEvent, 0);
 
	InitWindows ();
 
	InitMenus ();
 
	TEInit ();
 
	InitDialogs (nil);
 
	InitCursor ();
 
	for (i = 0; i < 5; i++) { /*register with Multifinder*/
	
		EventRecord ev;
	
		EventAvail (everyEvent, &ev); /*see TN180 -- splash screen*/
		} /*for*/
	
	DrawMenuBar ();
#endif
	} /*initmacintosh*/
 
 
static void copystring (Str255 source, Str255 dest) {
 
	/*
	create a copy of source in dest.  copy the length byte and
	all the characters in the source string.
 
	assume the strings are pascal strings, with the length byte in
	the first character of the string.
	*/
 
	short i, len;
 
	len = (short) source [0];
 
	for (i = 0; i <= len; i++) 
		dest [i] = source [i];
	} /*copystring*/
 
 
static Boolean pushstring (Str255 bssource, Str255 bsdest) {
 
	short lensource = bssource [0];
	short lendest = bsdest [0];
	char *psource, *pdest;
 
	if ((lensource + lendest) > 255)
		return (false);
	
	pdest = (char *) bsdest + (char) lendest + 1;
 
	psource = (char *) bssource + 1;
 
	bsdest [0] += (char) lensource;
 
	while (lensource--) *pdest++ = *psource++;
 
	return (true);
	} /*pushstring*/
 
 
static Boolean pushlong (long num, Str255 bsdest) {
 
	Str255 bsint;
 
#ifdef MACVERSION
	NumToString (num, bsint);
#endif
 
#ifdef WIN95VERSION
	wsprintf (bsint+1, "%ld", num);
	bsint[0] = strlen(bsint+1);
#endif
 
	return (pushstring (bsint, bsdest));
	} /*pushlong*/
 
 
static Boolean pushtype (OSType mytype, Str255 bsdest) {
#ifdef MACVERSION
 
	Str255 bs;
 
	bs [0] = sizeof (OSType);
 
	BlockMove (&mytype, &bs [1], sizeof (OSType));
 
	return (pushstring (bs, bsdest));
#endif
 
#ifdef WIN95VERSION
 
	Str255 bs;
 
	_asm 
		{
		mov eax,mytype
		bswap eax
		mov mytype,eax
		}
	memmove (bs+1, &mytype, sizeof (OSType));
 
	bs [0] = sizeof (OSType);
 
	return (pushstring (bs, bsdest));
 
#endif
	} /*pushtype*/
 
 
static void ellipsize (Str255 s, short width) {
#ifdef MACVERSION
 
	/*
	if the string fits inside the given number of pixels, fine -- do nothing
	and return.
 
	if not, return a string that does fit, with ellipses representing the 
	deleted characters.  ellipses are generated by pressing option-semicolon.
	*/
 
	char len;
	short newwidth;
 
	if ((newwidth = StringWidth (s)) <= width) /*nothing to do, the string fits*/
		return;
 
	len = s [0]; /* current length in characters*/
 
	width -= CharWidth ('...'); /* subtract width of ellipses*/
	
	do { /*until it fits (or we run out of characters)*/
 
		newwidth -= CharWidth (s [len]);
	
		--len;
	} while ((newwidth > width) && (len != 0));
 
	++len; /*make room for the ellipses*/
 
	s [len] = '...'; 
 
	s [0] = (char) len;
#endif
	} /*ellipsize*/
 
 
static void centerstring (Rect r, Str255 s) {
#ifdef MACVERSION
 
	/*
	draw the string in the current font, size and style, centered inside
	the indicated rectangle.
	*/
 
	short rh = r.bottom - r.top;
	short rw = r.right - r.left;
	short h, v;
	FontInfo fi;
 
	GetFontInfo (&fi);
 
	ellipsize (s, rw); /*make sure it fits inside the rectangle, width-wise*/
 
	h = r.left + ((rw - StringWidth (s)) / 2);
 
	v = r.top + ((rh - (fi.ascent + fi.descent)) / 2) + fi.ascent;
 
	MoveTo (h, v);
 
	ClipRect (&r);
 
	DrawString (s);
#endif
	} /*centerstring*/
 
 
static void setfontsizestyle (short fontnum, short fontsize, short fontstyle) {
#ifdef MACVERSION
 
	TextFont (fontnum);
 
	TextSize (fontsize);
 
	TextFace (fontstyle);
#endif
	} /*setfontsizestyle*/
 
#ifdef MACVERSION
static odbBool fileopen (tyfilespec * pfs, short *fnum) {
 
	OSErr ec;
 
	ec = FSpOpenDF (pfs, fsCurPerm, fnum);
 
	return (ec == noErr);
	} /*fileopen*/
#endif
 
static odbBool filecreateandopen (const tyfilespec *fs, OSType creator, OSType filetype, hdlfilenum *fnum) {
#ifdef MACVERSION
	OSErr ec;
 
	ec = FSpCreate (fs, creator, filetype, smSystemScript);
 
	if (ec == dupFNErr) {
 
#ifdef NEWFILETESTER
		if (FSpDelete (fs) != noErr)
			return (false);
	
		ec = FSpCreate (fs, creator, filetype, smSystemScript);
#else
		ec = noErr;
#endif
		}
 
	if (ec != noErr)
		return (false);
 
	ec = FSpOpenDF (fs, fsRdWrPerm, fnum);
 
	if (ec != noErr) {
	
		FSpDelete (fs);
	
		return (false); /*failed to open the file for writing*/
		}
#endif
 
#ifdef WIN95VERSION
#ifdef NEWFILETESTER
	*fnum = CreateFile ("odbTester.root", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
						NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
#else
	*fnum = CreateFile ("odbTester.root", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
						NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
#endif
	if (*fnum == INVALID_HANDLE_VALUE)
		{
		printf ("Error opening file.\n");
		return (false);
		}
 
#endif
	return (true);
	} /*filecreateandopen*/
 
 
static void fileclose (hdlfilenum fnum) {
#ifdef MACVERSION
	if (fnum != 0)
		FSClose (fnum);
#endif
 
#ifdef WIN95VERSION
	if (fnum != 0)
		CloseHandle (fnum);
#endif
	} /*fileclose*/
 
 
static odbBool getdesktopspec (Str255 name, tyfilespec *fs) {
#ifdef MACVERSION
	short vnum = 0;
	long dirid = 0;
	OSErr ec = noErr;
 
//	actually, let's leave it in the default directory...
//	ec = FindFolder (kOnSystemDisk, kDesktopFolderType, false, &vnum, &dirid);
 
	if (ec == noErr)
		ec = FSMakeFSSpec (vnum, dirid, name, fs);
 
	return (ec == noErr);
#endif
 
#ifdef WIN95VERSION
	copystring (name, (*fs).fullSpecifier);
	pushstring ("\x01" "\0", (*fs).fullSpecifier);
	return (true);
#endif
	} /*getdesktopspec*/
 
 
static void updatemainwindow (void) {
#ifdef MACVERSION
	Rect r;
	Str255 s;
 
	r = (*mainwindow).portRect;
 
	EraseRect (&r);
 
	setfontsizestyle (helvetica, 12, 0);
 
	centerstring (r, windowmessage);
 
	NumToString (FreeMem () / 1024, s);
 
	MoveTo (r.left + 3, r.bottom - 3);
 
	setfontsizestyle (geneva, 9, 0);
 
	DrawString (s);
 
	DrawString ("\pK");
#endif
	} /*updatemainwindow*/
 
 
static void waitseconds (long n) {
#ifdef MACVERSION
	long endticks;
 
	endticks = TickCount () + (n * 60);
 
	while (TickCount () < endticks)
		SystemTask ();
#endif
 
#ifdef WIN95VERSION
	long endticks;
 
	endticks = gettickcount () + (n * 60);
 
	while (gettickcount () < endticks)
		Yield ();
#endif
	} /*waitseconds*/
 
 
static void setwindowmessage (Str255 message, short wait) {
#ifdef MACVERSION
	copystring (message, windowmessage);
 
	SetPort (mainwindow);
 
	updatemainwindow ();
#endif
 
#ifdef WIN95VERSION
	message[message[0]+1]=0;
	printf ("%s\n",message+1);
#endif
 
	if (wait > 0)
		waitseconds (wait);
	} /*setwindowmessage*/
 
 
static Boolean initmainwindow (void) {
#ifdef MACVERSION
	WindowPtr w;
 
	w = mainwindow = GetNewWindow (128, nil, (WindowPtr) -1);
 
	if (w == nil)
		return (false);
 
	ShowWindow (w);
#endif
 
	return (true);
	} /*initmainwindow*/
 
 
static Boolean stringtotext (Str255 s, Handle *htext) {
 
	long len;
	Handle h;
 
	len = s [0];
 
	h = NewHandle (len);
 
	if (h == nil)
		return (false);
	
#ifdef MACVERSION
	BlockMove (&s [1], *h, len);
#endif
 
#ifdef WIN95VERSION
	memmove (*h, s+1, len);
#endif
 
	*htext = h;
 
	return (true);
	} /*stringtotext*/
 
 
static Boolean texttostring (Handle htext, Str255 s) {
 
	long len;
 
	len = GetHandleSize (htext);
 
	if (len > 255)
		len = 255;
	
#ifdef MACVERSION
	BlockMove (*htext, &s [1], len);
#endif
 
#ifdef WIN95VERSION
	memmove (s+1, *htext, len);
#endif
 
	s [0] = (char) len;
 
	return (true);
	} /*texttostring*/
 
 
static void ODBAccessTest (odbRef odb, Str255 bslookup) {
 
	odbValueRecord val;
	odbString bs, msg;
	OSType type;
	long count;
 
	copystring (bslookup, msg);
 
	pushstring ((ptrbyte) "\x03" ":  ", msg);
 
	if (odbDefined (odb, bslookup)) {
	
		odbGetType (odb, bslookup, &type);
	
		switch (type) {
			case stringvaluetype:
				if (odbGetValue (odb, bslookup, &val)) {
				
					texttostring (val.data.stringvalue, bs);
				
					odbDisposeValue (odb, &val);
					}
				else
					odbGetError (bs);
			
				pushstring (bs, msg);
			
				break;
		
			case tablevaluetype:
				if (odbCountItems (odb, bslookup, &count)) {
				
					pushlong (count, msg);
				
					pushstring ((ptrbyte) "\x07" " items.", msg);
					}
				else {
					odbGetError (bs);
				
					pushstring (bs, msg);
					}
			
				break;
		
			default:
				pushstring ((ptrbyte) "\x08" "type is ", msg);
			
				pushtype (type, msg);
			
				break;
			}
		}
	else
		pushstring ((ptrbyte) "\x1A" "The value was not defined.", msg);
 
	setwindowmessage (msg, 0);
	} /*ODBAccessTest*/
 
 
#ifdef MACVERSION
static void handledrag (EventRecord ev, WindowPtr w) {
	Rect r;
 
	r = qd.screenBits.bounds; 
   
	r.top = r.top + GetMBarHeight (); 
               
	r.left = r.left + 4;  
               
	r.right = r.right - 4;
               
	r.bottom = r.bottom - 4;
             
	DragWindow (w, ev.where, &r);   
	} /*handledrag*/
#endif
 
 
static Boolean exitprogram (void) {
#ifdef MACVERSION
	/*
	returns true if the user clicks in the go-away box.
	*/
 
	EventRecord ev;
	WindowPtr w;
 
	if (!WaitNextEvent (everyEvent, &ev, 1, nil))
		return (false);
 
	if (ev.what != mouseDown)
		return (false);
	
	switch (FindWindow (ev.where, &w)) {
 
		case inGoAway: /*click in go-away box to exit program*/
			return (TrackGoAway (w, ev.where));
	
		case inSysWindow:
			SystemClick (&ev, w); 
		
			return (false);
	
		case inDrag:
			handledrag (ev, w);
		
			return (false);
		
		} /*switch*/
#endif	
	return (false); /*don't exit the program*/
	} /*exitprogram*/
 
 
static unsigned char * paths [] = {
 
	(ptrbyte) "\x0A" "scratchpad",
 
	(ptrbyte) "\x18" "scratchpad.odbTestString",
 
	(ptrbyte) "\x16" "scratchpad.odbTestTime",
 
	(ptrbyte) "\x04" "user",
 
	(ptrbyte) "\x10" "user.preferences",
 
	(ptrbyte) "\x1C" "user.preferences.odbTestSpec",
 
	(ptrbyte) "\x1F" "user.preferences.odbTestStrings",
 
	nil
	};
 
 
void main (void) {
 
	Boolean error = false;
	tyfilespec fs;
	short i;
	unsigned char **s;
	unsigned long ticks;
	unsigned long date;
	Str255 msg;
	Str255 address;
	odbValueRecord val;
	hdlfilenum fnum = (hdlfilenum)-1;
	odbRef odb = nil;
	static byte testString [] = "\x29" "this is a test of the ODB Engine library.";
 
	initmacintosh ();
 
	initmainwindow (); 
 
	getdesktopspec ((ptrbyte) "\x0E" "odbTester.root", &fs);
 
	if (!filecreateandopen (&fs, 'LAND', 'TABL', &fnum)) {
 
		setwindowmessage ((ptrbyte) "\x20" "Error creating new database file", 1);
	
		goto error;
		}
 
#ifdef NEWFILETESTER
	if (!odbNewFile (fnum)) {
 
		setwindowmessage ((ptrbyte) "\x1B" "Error creating new database", 1);
	
		goto error;
		}
#endif
	if (!odbOpenFile (fnum, &odb)) {
 
		setwindowmessage ((ptrbyte) "\x16" "Error opening database", 1);
	
		goto error;
		}
 
#ifdef NEWFILETESTER
	/*start by creating a few tables in the new database*/
 
	odbNewTable (odb, paths [0]);
 
	odbNewTable (odb, paths [3]);
 
	odbNewTable (odb, paths [4]);
 
	odbNewTable (odb, paths [6]);
 
	/*create a string value*/
 
	val.valuetype = stringvaluetype;
 
#ifdef MACVERSION
	PtrToHand (testString+1, &val.data.stringvalue, *testString);
#endif
 
#ifdef WIN95VERSION
	val.data.stringvalue = GlobalAlloc(GMEM_MOVEABLE, testString [0]+2);
	memmove (*(val.data.stringvalue), testString+1, testString [0]);
#endif
 
	odbSetValue (odb, paths [1], &val);
 
	/*add a bunch of strings to odbTestStrings*/
 
	setwindowmessage ((ptrbyte) "\x3B" "add 100 testing strings to user.preferences.odbTestStrings.", 2);
 
	for (i = 1; i <= 100; i++) {
	
		copystring (paths [6], address);
	
		pushstring ((ptrbyte) "\x07" ".string", address);
	
		pushlong (i, address);
	
		odbSetValue (odb, address, &val);
		} /*for*/
 
	odbDisposeValue (odb, &val);
 
	/*create a date value*/
 
	val.valuetype = datevaluetype;
 
	GetDateTime (&val.data.datevalue);
 
	odbSetValue (odb, paths [2], &val);
 
	/*create a filespec value*/
#ifdef MACVERSION
	val.valuetype = filespecvaluetype;
 
	PtrToHand (&fs, (Handle *) &val.data.filespecvalue, sizeof (fs));
 
	odbSetValue (odb, paths [5], &val);
 
	odbDisposeValue (odb, &val);
#endif
	/*first, test reading slowly*/
#endif
	for (s = paths; *s != nil; s++) {
	
		if (exitprogram ()) /*returns true if user clicks in go away box*/
			return;
	
		ODBAccessTest (odb, *s);
	
		waitseconds (1); /*give user more time to see the result*/
		} /*for*/
 
	/*now, test fast*/
 
	ticks = gettickcount ();
 
	for (i = 1; i <= 20; i++) {
	
		for (s = paths; *s != nil; s++) {
		
			if (exitprogram ()) /*returns true if user clicks in go away box*/
				return;
		
			ODBAccessTest (odb, *s);
			} /*for*/
		} /*for*/
 
	/*report statistics*/ {
 
		ticks = gettickcount () - ticks;
	
		copystring ((ptrbyte) "\x10" "140 accesses in ", msg);
	
		pushlong (ticks, msg);
	
		pushstring ((ptrbyte) "\x07" " ticks.", msg);
	
		setwindowmessage (msg, 2);
		}
 
	/*now let's delete a value we added*/
 
	odbDelete (odb, paths [1]);
 
	/*change an existing value*/
 
	val.valuetype = datevaluetype;
 
	GetDateTime (&val.data.datevalue);
 
	odbSetValue (odb, paths [2], &val);
 
	/* check that the mod date changed*/
 
	odbGetModDate (odb, (ptrbyte) "\x0A" "scratchpad", &date);
 
	if (date >= val.data.datevalue)
		setwindowmessage ((ptrbyte) "\x15" "mod date was updated.", 2);
	else
		setwindowmessage ((ptrbyte) "\x19" "mod date was not updated.", 1);
 
	/*finally, save changes*/
 
	odbSaveFile (odb);
 
	setwindowmessage ((ptrbyte) "\x0F" "database saved.", 2);
 
	error:
 
	odbCloseFile (odb);
 
	fileclose (fnum);
	} /*main*/
 
 


Notes

ODB Tester is a simple program illustrating the use of the ODB Engine library. It creates a database file, adds three tables, and puts three data items to those tables. It then accesses the values and displays information about them:

For string values, the program displays the string. For table values, the number of items is displayed. For other value, the type is displayed.

After cycling through the six values, a tight loop is entered to provide rough timing statistics.

You can Quit the ODB Tester before completion by closing its status window.


This page was originally posted on 9/4/96; 10:34:39 AM. It was last built on 10/5/97; 12:40:43 PM with Frontier. Internet service provided by Conxion.