This is FileTable.m in view mode; [Download] [Up]
// ------------------------------------------------------------------------------------- // FileTable // This software is without warranty of any kind. Use at your own risk. // ------------------------------------------------------------------------------------- #import <objc/objc.h> #import <appkit/appkit.h> #import <mach/mach.h> #import <dbkit/dbkit.h> #import <libc.h> #import <stdio.h> #import <string.h> #import <ctype.h> #import "FileTable.h" // ------------------------------------------------------------------------------------- @implementation FileTable // ------------------------------------------------------------------------------------- /* count items in an unparsed table */ static int dt_countList(char *list) { int c; char *r = list; /* make sure there is at least one entry */ if (!r) return 0; while (isspace(*r)) r++; if (!*r) return 0; /* count remaining entries */ for (c = 0, r = list; *r;) { c++; while (*r && !isspace(*r)) r++; // skip value while (isspace(*r)) r++; // skip white } return c; } /* count items in a parsed table */ static int dt_countTable(char **tbl) { int c; if (!tbl) return 0; // no entries counted for (c = 0; tbl[c]; c++); return c; } /* parse a string table */ static char **dt_parseTable(char *list) { int n, tblSize; char **theTbl, *r; /* skip whitespace in list */ if (!list) return (char**)NULL; while (isspace(*list)) list++; if (!*list) return (char**)NULL; /* count items in table */ tblSize = sizeof(char*) * (dt_countList(list) + 1); // include terminator theTbl = (char**)malloc(tblSize); memset(theTbl, 0, tblSize); /* fill table */ for (n = 0, r = list; *r;) { theTbl[n++] = r; while (*r && !isspace(*r)) r++; while (isspace(*r)) *r++ = 0; } /* return the table */ return theTbl; } // ------------------------------------------------------------------------------------- /* return access timestamp */ - (time_t)timestamp { struct stat st; if (stat((char*)tableHandle->access, &st) < 0) { NXLogError("Unable to stat file %s", tableHandle->access); return 0; } return st.st_mtime; } // ------------------------------------------------------------------------------------- - _addSimpleColumn:(char*)title :(char)cType :(float)size { int t; char *types = CDT_TYPES; dataColumn_t *dc = (dataColumn_t*)malloc(sizeof(dataColumn_t)); memset(dc, 0, sizeof(dataColumn_t)); for (t = 0; types[t] && (types[t] != cType); t++); dc->index = [tableHandle->columnId count]; dc->type = types[t]? t : CDT_UNKNOWN; dc->keyTag = NXCopyStringBuffer(title); dc->title = (char*)nil; dc->size = size; dc->minSize = 0.0; dc->displayOrder = dc->index; dc->alignment = NX_CENTERED; dc->isEditable = dc->index? YES : NO; dc->isHidden = (dc->displayOrder >= 0)? NO : YES; dc->nilValue = (char*)nil; [self addColumnInfo:dc]; return self; } /* load table column info */ - readTableColumns { char buf[2048]; BOOL cLoaded = NO, vLoaded = NO; FILE *fh; /* open table */ if (!(fh = fopen(tableHandle->access, "r"))) { NXLogError("Unable to open file %s", tableHandle->access); return (id)nil; } /* find/read column information */ while (fgets(buf, sizeof(buf), fh) && (*buf == '#')) { /* view information */ if (!vLoaded && !strncmp(buf, "#!t", 3)) { char viewName[128]; NXSize s = { 0.0, 0.0 }; sscanf(buf + 4, "%s %f %f", viewName, &s.width, &s.height); tableHandle->viewSize = s; vLoaded = YES; continue; } /* column information */ if (!cLoaded && (!strncmp(buf, "#!c\t", 4) || !strncmp(buf, "#\t", 2))) { int key, numCols; char **tbl, *b = buf + 1; for (;*b && (*b != ' ') && (*b != '\t'); b++); for (;(*b == ' ') || (*b == '\t'); b++); if (!(tbl = dt_parseTable(b))) continue; numCols = dt_countTable(tbl); for (key = 0; key < numCols; key++) { float size = 0.0; char *title = tbl[key], *p = index(title, ':'), ctype[4]; if (p) { *p++ = 0; sscanf(p, "%c:%f", ctype, &size); } [self _addSimpleColumn:title :*ctype :size]; } free(tbl); cLoaded = YES; continue; } } /* close table */ fclose(fh); return self; } // ------------------------------------------------------------------------------------- /* load table */ - readTableData { FILE *fh; u_int r; char buf[4096]; int count = [tableHandle->columnId count]; /* open table */ if (!tableHandle->access) return (id)nil; if (!(fh = fopen((char*)tableHandle->access, "r"))) { NXLogError("Unable to open file %s", tableHandle->access); return (id)nil; } /* read table data */ for (r = 0; fgets(buf, sizeof(buf), fh);) { int c, tlen; id rowId; char **tbl; if (!*buf || (*buf == '#') || (*buf == '\t') || (*buf == ' ')) continue; if (!(tbl = dt_parseTable(buf))) continue; rowId = [[List alloc] initCount:count]; [tableHandle->dataId insertObject:rowId at:r]; for (tlen = dt_countTable(tbl), c = 0; c < count; c++) { char *val = (c < tlen)? tbl[c] : (char*)nil; dataEntry_t *de = entryNEW; de->value = (char*)[self copyStringValue:val forColumn:c]; de->isValid = -1; [rowId insertObject:(id)de at:c]; } free(tbl); r++; } /* close table */ fclose(fh); return self; } // ------------------------------------------------------------------------------------- - writeTable { int r, c; FILE *fh; struct stat st; /* make backup copy */ if (stat(tableHandle->access, &st) >= 0) { char bku[MAXPATHLEN + 1]; sprintf(bku, "%s~", tableHandle->access); if (rename(tableHandle->access, bku)) { NXLogError("Unable to rename file %s to %s", tableHandle->access, bku); return (id)nil; } } /* open file for writing */ if (!(fh = fopen(tableHandle->access, "w+"))) { NXLogError("Unable to open file %s", tableHandle->access); return (id)nil; } /* view header */ fprintf(fh, "#!t %s %.0f %.0f\n", tableHandle->name, tableHandle->viewSize.width, tableHandle->viewSize.height); /* column headers */ fprintf(fh, "#!c\t"); for (c = 0; c < [tableHandle->columnId count]; c++) { dataColumn_t *ci = [self columnInfoAt:c]; fprintf(fh, "%s:%c:%.0f\t", ci->keyTag, *(CDT_TYPES + ci->type), ci->size); } fprintf(fh, "\n"); /* data */ for (r = 0; r < [tableHandle->dataId count]; r++) { id rowId = [tableHandle->dataId objectAt:r]; for (c = 0; c < [rowId count]; c++) { dataColumn_t *ci = [self columnInfoAt:c]; dataEntry_t *de = entryPTR(rowId, c); if (c) fprintf(fh, "\t"); fprintf(fh, "%s", (*de->value?de->value:(ci->nilValue?ci->nilValue:"*"))); } fprintf(fh, "\n"); } /* close file */ fclose(fh); /* re-stat file to get modified date */ if (stat((char*)tableHandle->access, &st) >= 0) tableHandle->date = st.st_mtime; else NXLogError("Unable to stat file %s", tableHandle->access); return self; } // ------------------------------------------------------------------------------------- /* create value for column */ - (const char*)copyStringValue:(const char*)value forColumn:(int)index { char *vcopy, buff[64]; dataColumn_t *dc = [self columnInfoAt:index]; /* check arguments */ if (!dc) return (char*)nil; /* special return types */ switch (dc->type) { case CDT_BOOLEAN: return NXCopyStringBuffer(((value && strcmp(value,"NO"))?"YES":"NO")); break; case CDT_INTEGER: sprintf(buff, "%d", (value?atoi(value):0)); return NXCopyStringBuffer(buff); break; case CDT_STRING: default: if (!value) return NXCopyStringBuffer(""); for (vcopy = (char*)value; isspace(*vcopy); vcopy++); // skip white space vcopy = strcpy((char*)malloc(strlen(vcopy) + 1), vcopy); { char *b,*v; for (b=v=vcopy;*v;v++) if(!isspace(*v)){if(b!=v)*b=*v;b++;} *b=0; } if (dc->nilValue && !strcmp(dc->nilValue, vcopy)) *vcopy = 0; return (char*)realloc(vcopy, strlen(vcopy) + 1); break; } /* control should not reach here */ return NXCopyStringBuffer(""); } // ------------------------------------------------------------------------------------- /* validate specific value (intended for subclass implementation) */ - (BOOL)verifyValue:(const char*)value dataType:(int)dataType { if (!value) return NO; switch (dataType) { case CDT_STRING: case CDT_INTEGER: default: return YES; } return YES; } // ------------------------------------------------------------------------------------- @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.