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.