This is Card.m in view mode; [Download] [Up]
#import "Card.h"
/* -------------------------------------------------------------------
#import <objc/Storage.h>
typedef struct _CardData {
char *stringValue;
int stringLength;
int intValue;
float floatValue;
id object; } CardData;
#define cardDescription "{*iif@}"
#define CardFieldAt(C,F) (((NXStorageID *)C)->dataPtr+F)
#define CardStringField(F) CardFieldAt(F)->stringValue
enum {SortStrings, SortInts, SortFloats, SortObjects};
RDR, Inc.
Objective-C source file for the class Card
COPYRIGHT (C), 1991, RDR, Inc.
ALL RIGHTS RESERVED.
Responsible: Approved:
RDR:Ernest Prabhakar
Date: Rev:
1991-Jul-01 0.8
Card
1. Introduction
* A Card is any object to be collected in a Deck.
* Card is expected to receive the following messages
* - findSTR:(const char *)aString (returns self or nil)
* This is to support searching. Can also use the compiled regex.
* - (int)compare:aCard (-,0,+ if self <,=,> aCard)
* This is to support finding.
* This particular implementation is designed for use with
* flashcards, index cards, or playing cards. It implements the
* data as strings which can be read from/to streams.
* Data streams are usually RTF or PostScript, but it doesn't matter.
* The main ideas is that Card is a Storage of strings, numbers, and objects.
2. Revision History
___ The starting point. Ernest Prabhakar/1990-Jun-29
___ Add objects. Ernest Prabhakar/1990-Aug-17
___ Make fully general. ENP/1991-Jul-01
3. Source Code
------------------------------------------------------------------- */
/* ------------------------- Import files ------------------------- */
#import <appkit/nextstd.h>
#import <objc/hashtable.h>
#import <sys/param.h>
#import <regex.h>
/* ------------------------ Classes used ------------------------ */
#import <appkit/Panel.h>
#import "List-Ordered.h"
/* -------------------------- Defines --------------------------- */
#define FieldAt(F) ((CardData *)dataPtr+F)
#define StringField(F) FieldAt(F)->stringValue
#define ValidIndex(f) (f >= 0 && f < numElements)
#define IsEnd(CH) ((CH == '\n') || (CH == EOF))
#define NOUGHT '\0'
/* ------------------------- Constants -------------------------- */
/* ---------------------- Class variables ----------------------- */
static int activeField; /* which field to Find / Search on */
static int sortFlag; /* flag for sorting */
/* -------------------- Auxiliary Functions --------------------- */
static CardData *getString(NXStream *stream)
{
static char temp[MAXPATHLEN];
int i=0;
char c;
static CardData field;
while ((c=NXGetc(stream)) != '"' && c != EOF)
temp[i++] = c; /* NX_MALLOC(field,CardData,1);*/
NX_MALLOC(field.stringValue,char,i+1);
strncpy(field.stringValue,temp,i);
(field.stringValue)[i]=NOUGHT;
field.stringLength = i;
if (IsEnd(c)) NXUngetc(stream);
return &field;
}
static CardData *getWord(NXStream *stream)
{
static char temp[MAXPATHLEN];
int i=0;
char c;
static CardData field;
while (((c=NXGetc(stream)) != '\t') && (c != ' ') && !IsEnd(c))
temp[i++] = c;
NX_MALLOC(field.stringValue,char,i+1);
strncpy(field.stringValue,temp,i);
(field.stringValue)[i]=NOUGHT;
field.stringLength = i;
if (IsEnd(c)) NXUngetc(stream);
return &field;
}
/*====================================================================
Implementation of class Card
====================================================================*/
@implementation Card : Storage
{
}
/*====================================================================
Factory Methods
====================================================================*/
/* Set and Return Parameters */
/*--------------------------------------------------------------------
|+setActiveField:(unsigned)field| Sets the field used for Sorts/searches.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
+setActiveField:(unsigned)field
{
activeField = field;
return self;
}
/*--------------------------------------------------------------------
|+(unsigned)activeField| Returns the field use for sorting/searching.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
+(unsigned)activeField
{
return activeField;
}
/*--------------------------------------------------------------------
|+setSortFlag:(int)flag| Sets the sort flag;
* There are no restrictions on 'flag' value, so to change sorting
* all you would need is redefine the compare method.
* Existing values use String, InvertedStrings, and the Tag to sort;
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
+setSortFlag:(int)flag
{
sortFlag = flag;
return self;
}
/*--------------------------------------------------------------------
|+(int)sortFlag| Returns the sort flag.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
+(int)sortFlag
{
return sortFlag;
}
/*====================================================================
Initialize and Free
====================================================================*/
/*--------------------------------------------------------------------
|-init| * Creates a Card with two (2) fields.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-init
{
return [self initCount:2];
}
/*--------------------------------------------------------------------
|-initCount:(unsigned)count| Creates a Card with count fields
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-initCount:(unsigned)count
{
return [self initCount:count elementSize:sizeof(CardData)
description:cardDescription];
}
/*--------------------------------------------------------------------
|-free| Free all the strings and objects.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-free
{
int i;
for (i = 0; i < numElements; i++) {
if (StringField(i)) NX_FREE( StringField(i) );
if (FieldAt(i)->object) [FieldAt(i)->object free];
}
return [super free];
}
/*====================================================================
Importing and Exporting Data
====================================================================*/
/*--------------------------------------------------------------------
|-importFrom:(NXStream *)stream|
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-importFrom:(NXStream *)stream
{
char c;
while ((c=NXGetc(stream)) != EOF)
switch (c) {
case '\n':
return self;
case '"':
[self addElement:getString(stream)];
break;
case ',':
case '\t': /* Do nothing */
case ' ':
break;
default:
NXUngetc(stream);
[self addElement:getWord(stream)];
break;
}
return nil; /* End of File */
}
/*--------------------------------------------------------------------
|-exportTo:(NXStream *)stream|
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-exportTo:(NXStream *)stream
{
int i;
for (i = 0; i < numElements; i++)
NXPrintf(stream, "\"%s\"%s", StringField(i),
(i < (numElements-1)) ? ",\t" : "\n");
return self;
}
/*====================================================================
String Fields I/O
====================================================================*/
/*--------------------------------------------------------------------
|-setStringValue:(const char *)aString| Defaults to activeField
Creates a copy of the string, and frees when storage is freed.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValue:(const char *)aString
{
return [self setStringValue:aString at:activeField];
}
/*--------------------------------------------------------------------
|-setStringValue:(const char *)aString at:(int)field|
Creates a copy of the string, and frees when storage is freed.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValue:(const char *)aString at:(int)field
{
return [self setStringValueNoCopy:NXCopyStringBuffer(aString) at:field];
}
/*--------------------------------------------------------------------
|-setStringValueNoCopy:(char *)aString| Defaults to activeField
Frees when storage is freed.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValueNoCopy:(char *)aString
{
return [self setStringValueNoCopy:aString at:activeField];
}
/*--------------------------------------------------------------------
|-setStringValueNoCopy:(char *)aString at:(int)field|
Frees when storage is freed.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValueNoCopy:(char *)aString at:(int)field
{
if (ValidIndex(field)) {
if (StringField(field)) NX_FREE(StringField(field));
StringField(field) = aString;
FieldAt(field)->stringLength = strlen(aString);
return self;
}
return nil;
}
/*--------------------------------------------------------------------
|-setStringValueFrom:(NXStream *)aStream| Defaults to activeField
Reads in string from the stream.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValueFrom:(NXStream *)aStream
{
return [self setStringValueFrom:aStream at:activeField];
}
/*--------------------------------------------------------------------
|-setStringValueFrom:(NXStream *)aStream at:(unsigned)field|
Reads in string from the stream.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setStringValueFrom:(NXStream *)aStream at:(unsigned)field
{
char *buf;
int len, maxlen;
if (ValidIndex(field)) {
if (StringField(field)) NX_FREE(StringField(field));
NXGetMemoryBuffer(aStream, &buf, &len, &maxlen);
NX_MALLOC(StringField(field), char, len + 1);
strncpy(StringField(field), buf, len);
StringField(field)[len] = NOUGHT;
FieldAt(field)->stringLength = len;
return self;
}
return nil;
}
/*--------------------------------------------------------------------
|-(const char *)stringValue| Defaults to active field.
Returns the string.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(const char *)stringValue
{
return [self stringValueAt:activeField];
}
/*--------------------------------------------------------------------
|-(const char *)stringValueAt:(unsigned)field|
Returns the string at that position, or NULL if invalid.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(const char *)stringValueAt:(unsigned)field
{
if (ValidIndex(field)) {
return StringField(field);
} else {
return NULL;
}
}
/*--------------------------------------------------------------------
|-(NXStream *)stringStream| Defaults to active field.
Returns a stream pointing to the string.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(NXStream *)stringStream
{
return [self stringStreamAt:activeField];
}
/*--------------------------------------------------------------------
|-(NXStream *)stringStreamAt:(unsigned)field|
Returns a stream pointing to the string, if valid, else NULL.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(NXStream *)stringStreamAt:(unsigned)field
{
if (ValidIndex(field))
return NXOpenMemory(StringField(field), FieldAt(field)->stringLength-1,
NX_READONLY);
return NULL;
}
/*====================================================================
Integer I/O
====================================================================*/
/*--------------------------------------------------------------------
|-setIntValue:(int)anInt| Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setIntValue:(int)anInt
{
return [self setIntValue:anInt at:activeField];
}
/*--------------------------------------------------------------------
|-setIntValue:(int)anInt at:(unsigned)field| Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setIntValue:(int)anInt at:(unsigned)field
{
FieldAt(field)->intValue = anInt;
return self;
}
/*--------------------------------------------------------------------
|-(int)intValue| Defaults to active field.
Returns the integer.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(int)intValue
{
return [self intValueAt:activeField];
}
/*--------------------------------------------------------------------
|-(int)intValueAt:(unsigned)field| Defaults to active field.
Returns the integer.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(int)intValueAt:(unsigned)field
{
return FieldAt(field)->intValue;
}
/*====================================================================
Float I/O
====================================================================*/
/*--------------------------------------------------------------------
|-setFloatValue:(float)aFloat| Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setFloatValue:(float)aFloat
{
return [self setFloatValue:aFloat at:activeField];
}
/*--------------------------------------------------------------------
|-setFloatValue:(float)aFloat at:(unsigned)field|Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setFloatValue:(float)aFloat at:(unsigned)field
{
FieldAt(field)->floatValue = aFloat;
return self;
}
/*--------------------------------------------------------------------
|-(float)floatValue| Defaults to active field.
Returns the float.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(float)floatValue
{
return [self floatValueAt:activeField];
}
/*--------------------------------------------------------------------
|-(float)floatValueAt:(unsigned)field| Defaults to active field.
Returns the float.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(float)floatValueAt:(unsigned)field
{
return FieldAt(field)->floatValue;
}
/*====================================================================
Object I/O
====================================================================*/
/*--------------------------------------------------------------------
|-setObject:anObject| Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setObject:anObject
{
return [self setObject:anObject at:activeField];
}
/*--------------------------------------------------------------------
|-setObject:anObject at:(unsigned)field| Defaults to active field.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-setObject:anObject at:(unsigned)field
{
FieldAt(field)->object = anObject;
return self;
}
/*--------------------------------------------------------------------
|-object| Defaults to active field.
Returns the object.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-object
{
return [self objectAt:activeField];
}
/*--------------------------------------------------------------------
|-objectAt:(unsigned)field| Defaults to active field.
Returns the object.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-objectAt:(unsigned)field
{
return FieldAt(field)->object;
}
/*====================================================================
Finding and Sorting
====================================================================*/
/*--------------------------------------------------------------------
|-findSTR:(const char *) aString|
* If aString matches fields[sortField], return that data string.
* Otherwise return null. Can also use regular expersion (re_cmp).
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-findSTR:(const char *) aString
{
if (re_exec(StringField(activeField)))
return self;
return nil;
}
/*--------------------------------------------------------------------
|-(int)compare:aCard| self(value) - aCard(value)
(-, 0, +) if self <, =, > aCard
Sorts according to activeField and sortType.
* Pulls out the equivalent field and compares it.
* You can overrule this for specialized Card types.
enum {SortStrings, SortInts, SortFloats, SortObjects}
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-(int)compare:aCard
{
/* If not enough fields, sort by size */
if ((numElements <= activeField) || ([aCard count] <= activeField))
return numElements - [aCard count];
switch (sortFlag) {
case SortStrings:
return strcmp(StringField(activeField), [aCard stringValue]);
case SortInts:
return [self intValue] - [aCard intValue];
case SortFloats:
return [self floatValue] - [aCard floatValue];
case SortObjects:
if ([[self object] respondsTo:@selector(compare:)])
return [[self object] compare:[aCard object]];
default:
return numElements - [aCard count];
}
}
/*--------------------------------------------------------------------
|-rotate| Rotate the fields.
The first shall be last, and the last move up one.
Returns self.
Ernest Prabhakar/1991-Jul-01
--------------------------------------------------------------------*/
-rotate
{
CardData field;
field = *(CardData *)[self elementAt:0];
[[self removeAt:0] addElement:(void *)&field];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.