This is ElementController.m in view mode; [Download] [Up]
/**************************************************
* SynthBuilder
* Copyright 1993 Nick Porcaro All Rights Reserved
**************************************************/
#import <stdlib.h>
#import <string.h>
#import <objc/List.h>
#import <appkit/Application.h>
#import <appkit/Panel.h>
#import <appkit/Control.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import "ViewController.h"
#import "DragView.h"
#import "UGDef.h"
#import "UGMethodDef.h"
#import "UGArgDef.h"
#import "NGDef.h"
#import "NGArgDef.h"
#import "NFDef.h"
#import "NFMethodDef.h"
#import "NFArgDef.h"
#import "Controller.h"
#import "Utilities.h"
#import "ElementController.h"
extern id savePanel;
extern id openPanel;
extern char *getSavePath(char *banner);
extern char *getOpenPath(char *banner);
extern char *getAppName();
@implementation ElementController
static char TempString[1024];
- awakeFromNib
{
if (! theViewController)
{
theViewController = [[ViewController alloc] init];
[theViewController setMultiView:theMultiView];
[theViewController setDragView:theDragView];
[theViewController setFocusLock:NO];
}
[theDragView setViewController:theViewController];
if (! theUGList)
{
theUGList = [[List alloc] init];
}
if (! theNFList)
{
theNFList = [[List alloc] init];
}
if (! theNGList)
{
theNGList = [[List alloc] init];
}
// Only do this to bootstrap [self buildStandardUGDefs];
[self readStandardDefs];
[theViewController switchViewToNumber:1];
[theController displayMainWindow];
[theViewController setFocusLock:YES];
return self;
}
- init
{
[super init];
return self;
}
- switchView:sender
{
[theViewController switchView:sender];
return self;
}
- displayInspector:sender
{
[theViewController displayInspector:sender];
return self;
}
- readStandardDefs
{
[self readStandardUGDefs:self];
[self readStandardNGDefs:self];
[self readStandardNFDefs:self];
return self;
}
- readStandardUGDefs:sender
{
int len;
char *dir;
char *path;
if ( ! (dir = [utilities getAppDir]))
{
return self;
}
len = strlen(dir) + 100;
path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
sprintf(path, "%s/StandardUGDefs", dir);
[self readUGDefs:path];
NXZoneFree([self zone], path);
return self;
}
- readStandardNGDefs:sender
{
int len;
char *dir;
char *path;
if ( ! (dir = [utilities getAppDir]))
{
return self;
}
len = strlen(dir) + 100;
path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
sprintf(path, "%s/StandardNGDefs", dir);
[self readNGDefs:path];
NXZoneFree([self zone], path);
return self;
}
- readStandardNFDefs:sender
{
int len;
char *dir;
char *path;
if ( ! (dir = [utilities getAppDir]))
{
return self;
}
len = strlen(dir) + 100;
path = (char *) NXZoneCalloc([self zone], len, sizeof(char));
sprintf(path, "%s/StandardNFDefs", dir);
[self readNFDefs:path];
NXZoneFree([self zone], path);
return self;
}
- setUGList: aUGList
{
theUGList = aUGList;
return self;
}
- setNGList: aNGList
{
theNGList = aNGList;
return self;
}
- setNFList: aNFList
{
theNFList = aNFList;
return self;
}
- getUGList
{
return theUGList;
}
- getNGList
{
return theNGList;
}
- getNFList
{
return theNFList;
}
- initViews
/* Call setNGList/setNFList/setUGList first */
{
[self initUGView];
[self initNFView];
[self initNGView];
return self;
}
- initUGView
{
[theViewController initView: 1
list: theUGList
class: [UGDef class]
name: "Unit Generators"];
return self;
}
- initNGView
{
[theViewController initView: 2
list: theNGList
class: [NGDef class]
name: "Note Generators"];
return self;
}
- initNFView
{
[theViewController initView: 3
list: theNFList
class: [NFDef class]
name: "Note Filters"];
return self;
}
/************ This monster was the original way that
************ "FakeUGs" were defined in the old program
****************************************************/
#define MAXCONNECTIONS 5
#define MAXNOTEPARAMETERS 9 /* The number of rows in the FakeUG inspector also */
#define MK_UG 0
#define CLM_UG 1
#define PP_UG 2 // A PatchParameter
#define CLAV_UG 3 // A clavier
#define MIDI_UG 4 // A midi input
#define NF_UG 5 // A note filter (users should be able to add these)
#define INT 0
#define DOUBLE 1
#define ENV 2
#define BOOLEAN 3
#define DSPDATUM 4
#define PARTIALS 5
typedef struct
{
char *niceName;
char *type;
int ugType; // Type of UG
char *iconName;
BOOL isEnvelopeHandler;
BOOL isADSwitch;
BOOL isData;
BOOL isOscg;
BOOL isSineROM;
BOOL hasLength;
BOOL hasConstant;
BOOL isStorage;
struct
{
char *methodName;
int x;
int y;
BOOL isOutput;
} connection[MAXCONNECTIONS];
struct
{
char *methodName;
int argType;
char *defaultArgValue;
} noteParameters[MAXNOTEPARAMETERS];
} oldFakeUGInfoType;
/* The first connection is for the output. */
/*
* The methods are in order that the corresponding memory segments are in
* in the name of the include file.
*/
/*
* Also, synthdata, and the relevant memory issues, have not been handled
* yet, i.e. for delay, Oscgaf, and Oscgafi.
*/
const oldFakeUGInfoType oldFakeUGInfo[] =
{
/***************************************
Explanation of initialization for AllPass1UG:
type = Allpass1UG
iconName = allpass1
isEnvelopeHandler = isADSwitch = isData = isOscg = isSineROM = hasLength = hasConstant = NO
connection struct:
methodName1 = setOutput: x1 = 28 x2 = 15
methodName2 = setInput: x1 = 28 x2 = 15
noteParameters struct:
methodName1 = setBB0 argType1 = DOUBLE
defaultArgValue = "0"
The number of connection and noteParameters
is obtainable by finding out how many are non-NULL
***********************************/
{"Allpass Filter", "Allpass1UG", MK_UG, "allpass1", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput:", 28, 42, NO}},
{{"setBB0:", DOUBLE, "0"}}
},
{"Add2", "Add2UG", MK_UG, "add2", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{}
},
{"Envelope", "AsympUG", MK_UG, "asymp", YES, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{{"setRate:", DOUBLE, "0"},
{"setReleaseXScale:", DOUBLE, "0"},
{"setTargetVal:", DOUBLE, "0"},
{"setT60:", DOUBLE, "0"},
{"setEnvelope: ...", ENV, ""}}
},
{"Constant", "ConstantUG", MK_UG, "constant", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{{"setConstant:", DOUBLE, "1.00"}}
},
{"Delay", "DelayUG", MK_UG, "delay", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 51, 28, YES},
{"setInput:", 3, 28, NO},
{"setDelayMemory:", 27, 28, NO}},
{{"adjustLength:", INT, "0"}}
},
{"Dswitch", "DswitchUG", MK_UG, "dswitch", NO, YES, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{{"setDelaySamples:", INT, "0"},
{"setScale1:", DOUBLE, "0"}}
},
{"Dswitcht", "DswitchtUG", MK_UG, "dswitcht", NO, YES, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{{"setDelayTicks:", INT, "0"},
{"setScale1:", DOUBLE, "0"},
{"setScale2:", DOUBLE, "0"}}
},
{"Interpolator", "InterpUG", MK_UG, "interp", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 17, 42, NO},
{"setInput2:", 36, 42, NO},
{"setInterpInput:", 26, 42, NO}},
{}
},
{"Mult/add2", "Mul1add2UG", MK_UG, "mul1add2", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 27, 42, NO},
{"setInput3:", 40, 42, NO}},
{}
},
{"Mult2", "Mul2UG", MK_UG, "mul2", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{}
},
{"One pole filter", "OnepoleUG", MK_UG, "onepole", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput:", 28, 42, NO}},
{{"setA1:", DOUBLE, "0"},
{"setB0:", DOUBLE, "0"}}
},
{"One zero filter", "OnezeroUG", MK_UG, "onepole", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput:", 28, 42, NO}},
{{"setB0:", DOUBLE, "0"},
{"setB1:", DOUBLE, "0"}}
},
{"Osc", "OscgUG", MK_UG, "oscg", NO, NO, NO, YES, NO, NO, NO, NO,
{{"setOutput:", 27, 15, YES},
{"setTable:", 27, 29, NO}},
{{"setInc:", INT, "0"},
{"setFreq:", DOUBLE, "440.0"},
{"setAmp:", DOUBLE, "0.5"},
{"setPhase:", DOUBLE, "0.0"}}
},
{"Osc freq/amp", "OscgafUG", MK_UG, "oscgaf", NO, NO, NO, YES, NO, NO, NO, NO,
{{"setOutput:", 27, 15, YES},
{"setAmpInput:", 17, 43, NO},
{"setIncInput:", 42, 43, NO},
{"setTable:", 27, 29, NO}},
{{"setIncScaler:", INT, "0"}, /* checked */
{"setPhase:", DOUBLE, "0"}, /* checked */
{"setIncRatio:", DOUBLE, "1.0"}}
},
{"Osc interp/freq/amp", "OscgafiUG", MK_UG, "oscgafi", NO, NO, NO, YES, NO, NO, NO, NO,
{{"setOutput:", 27, 15, YES},
{"setAmpInput:", 17, 43, NO},
{"setIncInput:", 42, 43, NO},
{"setTable:", 27, 29, NO}},
{{"setIncScaler:", INT, "0"},
{"setPhase:", DOUBLE, "0"},
{"setIncRatio:", DOUBLE, "1.0"}}
},
{"Speaker A", "Out1aUG", MK_UG, "out1a", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setInput:", 28, 48, NO}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Speaker B", "Out1bUG", MK_UG, "out1b", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setInput:", 28, 48, NO}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Stereo Out", "Out2sumUG", MK_UG, "out2sum", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setInput:", 28, 48, NO}},
{{"setBearing:", DOUBLE, "0"}, /* checked */
{"setLeftScale:", DOUBLE, "1.0"}, /* checked */
{"setRightScale:", DOUBLE, "1.0"}}
},
{"Scale", "ScaleUG", MK_UG, "scale", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 51, 28, YES},
{"setInput:", 3, 28, NO}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Scale add2", "Scl1add2UG", MK_UG, "scl1add2", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Scale2 add2", "Scl2add2UG", MK_UG, "scl2add2", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput1:", 15, 42, NO},
{"setInput2:", 40, 42, NO}},
{{"setScale1:", DOUBLE, "1.0"},
{"setScale2:", DOUBLE, "1.0"}}
},
{"S Noise", "SnoiseUG", MK_UG, "snoise", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 27, 15, YES}},
{}
},
{"U Noise", "UnoiseUG", MK_UG, "unoise", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 27, 15, YES}},
{}
},
{"Constant PatchPoint", "Constantpp", MK_UG, "constantpp", NO, NO, YES, NO, NO, NO, YES, NO,
{{"", 27, 29, YES}},
{{"setToConstant", DSPDATUM, "1.0"}}
},
{"Partials", "Partials", MK_UG, "partials", NO, NO, YES, NO, NO, YES, NO, NO,
{{"", 27, 29, YES}},
{{"length", INT, "0"},
{"partials", PARTIALS, "0"}}
},
{"Sine ROM", "SineROM", MK_UG, "sinerom", NO, NO, YES, NO, YES, NO, NO, NO,
{{"", 27, 29, YES}},
{}
},
{"Memory", "Storage", MK_UG, "storage", NO, NO, YES, NO, NO, YES, YES, YES,
{{"", 27, 29, YES}},
{{"length:", INT, "300"},
{"setToConstant:", DSPDATUM, "1000"}}
},
{"Table Lookup", "TablookUG", MK_UG, "tablelookup", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutputAout:", 27, 15, YES}, // the output is on the bottom.
{"setInputAinv:", 27, 42, NO}, // the input is on the top.
{"setAddressAtablook:",27, 30, NO}}, // the table is the center one
{{"setTableSize:", INT, "0"}}
},
{"Digital In A", "In1aUG", MK_UG, "in1a", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Digital In B", "In1bUG", MK_UG, "in1b", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{{"setScale:", DOUBLE, "1.0"}}
},
{"Biquad filter", "BiquadUG", MK_UG, "biquad", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES},
{"setInput:", 28, 42, NO}},
{
{"setA1:", DOUBLE, "0.5"},
{"setA2:", DOUBLE, "0.5"},
{"setB1:", DOUBLE, "0.5"},
{"setB2:", DOUBLE, "0.5"},
{"setComplexPolesRadius:", DOUBLE, "0.5"}, /* Sorry only one argument for now */
{"setComplexZerosRadius:", DOUBLE, "0.5"}, /* Sorry only one argument for now */
{"setComplexPolesFrequency:", DOUBLE, "0.5"}, /* Sorry only one argument for now */
{"setComplexZerosFrequency:", DOUBLE, "0.5"}, /* Sorry only one argument for now */
{"setGain:", DOUBLE, "1.0"}, /* I hope the default is reasonable */
{"setFirstDelayedSample:", DOUBLE, "0"}, /* I hope the default is reasonable */
{"setSecondDelayedSample:", DOUBLE, "0"} /* I hope the default is reasonable */
}
},
{"Patch Parameter", "PatchParameter", PP_UG, "PatchParameter", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setInput:", 28, 42, NO}},
{}
},
{"Clavier", "Clavier", CLAV_UG, "Clavier", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{}
},
{"MIDI IN-A", "MIDI-A", MIDI_UG, "MIDI-A", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{}
},
{"MIDIIN-B", "MIDI-B", MIDI_UG, "MIDI-B", NO, NO, NO, NO, NO, NO, NO, NO,
{{"setOutput:", 28, 15, YES}},
{}
}
};
#define NUM_UG_DEFS sizeof(oldFakeUGInfo)/sizeof(oldFakeUGInfoType)
- buildStandardUGDefs
/* This is legacy code that hopefully can go away real soon!
* Call setUGList first
*/
{
int i, j;
id aDef, aMethod, anArg;
for (i=0; i<NUM_UG_DEFS; i++)
{
if (oldFakeUGInfo[i].ugType == MK_UG)
{
aDef = [[UGDef alloc] init];
[theUGList addObject:aDef];
[aDef setMetaType:MK_UG];
[aDef setNibFile:"FakeUG.nib"]; /* Change if you dare */
}
else if (oldFakeUGInfo[i].ugType == PP_UG)
{
aDef = [[UGDef alloc] init];
[theNFList addObject:aDef];
[aDef setMetaType:PP_UG];
[aDef setNibFile:"PatchParam.nib"];
[aDef setIsPatchParameter:YES];
}
else if (oldFakeUGInfo[i].ugType == NF_UG)
{
aDef = [[UGDef alloc] init];
[theNFList addObject:aDef];
[aDef setMetaType:NF_UG];
[aDef setNibFile:"NoteFilter.nib"];
[aDef setIsNoteFilter:YES];
}
else if (oldFakeUGInfo[i].ugType == MIDI_UG)
{
aDef = [[UGDef alloc] init];
[theNGList addObject:aDef];
[aDef setMetaType:MIDI_UG];
[aDef setNibFile:""];
[aDef setIsMidi:YES];
}
else if (oldFakeUGInfo[i].ugType == CLAV_UG)
{
aDef = [[UGDef alloc] init];
[theNGList addObject:aDef];
[aDef setMetaType:CLAV_UG];
[aDef setNibFile:"Clavier.nib"];
[aDef setIsClavier:YES];
}
else
{
aDef = nil;
printf("barf fart splat\n");
}
[(UGDef *) aDef setName:oldFakeUGInfo[i].niceName];
[aDef setTheType:oldFakeUGInfo[i].type];
[aDef setIconFile:oldFakeUGInfo[i].iconName];
[aDef setIsEnvelopeHandler:oldFakeUGInfo[i].isEnvelopeHandler];
[aDef setIsADSwitch:oldFakeUGInfo[i].isADSwitch];
[aDef setIsData:oldFakeUGInfo[i].isData];
[aDef setIsOscg:oldFakeUGInfo[i].isOscg];
[aDef setIsSineROM:oldFakeUGInfo[i].isSineROM];
[aDef setHasLength:oldFakeUGInfo[i].hasLength];
[aDef setHasConstant:oldFakeUGInfo[i].hasConstant];
[aDef setIsStorage:oldFakeUGInfo[i].isStorage];
for (j=0; j<MAXCONNECTIONS; j++)
{
if (oldFakeUGInfo[i].connection[j].methodName)
{
aMethod = [aDef addNewMethod:oldFakeUGInfo[i].connection[j].methodName];
[aMethod setIsOutput:oldFakeUGInfo[i].connection[j].isOutput];
[aMethod setXCoord:oldFakeUGInfo[i].connection[j].x];
[aMethod setYCoord:oldFakeUGInfo[i].connection[j].y];
}
}
for (j=0; j<MAXNOTEPARAMETERS; j++)
{
if (oldFakeUGInfo[i].noteParameters[j].methodName)
{
anArg = [aDef addNewArg:oldFakeUGInfo[i].noteParameters[j].methodName];
[anArg setArgType:oldFakeUGInfo[i].noteParameters[j].argType];
[anArg setDefaultValue:oldFakeUGInfo[i].noteParameters[j].defaultArgValue];
}
}
printf("Added: %s icon: %s (index: %d)\n", [aDef getName], [aDef getIconFile], i);
}
return self;
}
- oldUGTypeToUGDef: (int) old_index
/* This converts an index into the old table
* into a UGDef. It does this by getting the type
* name corresponding to old_index from theUGList
*/
{
char *old_type;
int i;
if (old_index >= NUM_UG_DEFS)
{
NXRunAlertPanel(getAppName(), "Invalid index on attempt to convert", NULL, NULL, NULL);
return nil;
}
if (! theUGList)
{
NXRunAlertPanel(getAppName(), "theUGList is nil", NULL, NULL, NULL);
return nil;
}
old_type = oldFakeUGInfo[old_index].type;
if (! old_type)
{
NXRunAlertPanel(getAppName(), "old_type is NULL", NULL, NULL, NULL);
return nil;
}
for (i=0; i<[theUGList count]; i++)
{
if (strcmp(old_type, [[theUGList objectAt:i] getType]) == 0)
{
return [theUGList objectAt:i];
}
}
return nil;
}
- writeUGDefs:sender
{
char *file;
sprintf(TempString, "%s Save Unit Generator Defs", getAppName());
file = getSavePath(TempString);
if (! file)
{
return self;
}
[self writeDefsFrom:theUGList To:file];
return self;
}
- writeNFDefs:sender
{
char *file;
sprintf(TempString, "%s Save Note Filter Defs", getAppName());
file = getSavePath(TempString);
if (! file)
{
return self;
}
[self writeDefsFrom:theNFList To:file];
return self;
}
- writeNGDefs:sender
{
char *file;
sprintf(TempString, "%s Save Note Generator Defs", getAppName());
file = getSavePath(TempString);
if (! file)
{
return self;
}
[self writeDefsFrom:theNGList To:file];
return self;
}
- writeDefsFrom: aList To:(char *) aFile
{
NXTypedStream *ts;
if (! aFile || ! aList)
{
return nil;
}
ts = NXOpenTypedStreamForFile(aFile, NX_WRITEONLY);
NXWriteRootObject(ts, aList);
NXCloseTypedStream(ts);
return self;
}
- readUGDefsFromMenu:sender
{
char *file;
file = getOpenPath("Load Unit Generators");
if (! file)
{
return self;
}
[self readUGDefs:file];
return self;
}
- readNGDefsFromMenu:sender
{
char *file;
file = getOpenPath("Load Note Generators");
if (! file)
{
return self;
}
[self readNGDefs:file];
return self;
}
- readNFDefsFromMenu:sender
{
char *file;
file = getOpenPath("Load Note Generators");
if (! file)
{
return self;
}
[self readNFDefs:file];
return self;
}
- readUGDefs:(char *) file
{
id aList;
aList = [self readDefsFrom:file];
if (aList)
{
[theUGList freeObjects];
[theUGList free];
}
theUGList = aList;
[self initUGView];
[theViewController switchViewToNumber:1];
return self;
}
- readNGDefs:(char *) file
{
id aList;
aList = [self readDefsFrom:file];
if (aList)
{
[theNGList freeObjects];
[theNGList free];
}
theNGList = aList;
[self initNGView];
[theViewController switchViewToNumber:2];
return self;
}
- readNFDefs:(char *) file
{
id aList;
aList = [self readDefsFrom:file];
if (aList)
{
[theNFList freeObjects];
[theNFList free];
}
theNFList = aList;
[self initNFView];
[theViewController switchViewToNumber:3];
return self;
}
static int defCompare(const void *def1, const void *def2)
{
return strcmp([*(id *)def1 getName],[*(id *)def2 getName]);
}
- (List *) readDefsFrom: (char *) file
{
NXTypedStream *ts;
List *aList = nil;
if (! file)
{
return nil;
}
ts = NXOpenTypedStreamForFile(file, NX_READONLY);
if (! ts)
{
sprintf(TempString, "Error cannot open file: %s", file);
NXRunAlertPanel(getAppName(), TempString, NULL, NULL, NULL);
return nil;
}
aList = NXReadObject(ts);
NXCloseTypedStream(ts);
if (! aList)
{
printf("ElementController nil list\n");
return nil;
}
else
{
/* Sort the List and return it */
[utilities sortList:aList sortFunction:defCompare];
return aList;
}
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.