home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-22 | 27.5 KB | 1,036 lines |
- /*
- * This sourcecode is part of FileSpy, a logfile observing utility.
- * Copyright (C) 1996 Felix Rauch
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Notice that this program may not be possessed, used, copied,
- * distributed or modified by people having to do with nuclear
- * weapons. See the file CONDITIONS for details.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * To contact the original author, try:
- * e-mail: Felix.Rauch@nice.ch
- * Traditional mail: Felix Rauch
- * Sempacherstrasse 33
- * 8032 Zurich
- * Switzerland
- */
-
- #import <appkit/Text.h>
- #import <appkit/ScrollView.h>
- #import <appkit/graphics.h>
- #import "SpyTextFieldCell.h"
-
- #define MAXSIZE 1.0e38 // Maximum size of a text object
- #define MAXSLOWDOWN 32 // maximum of file updates to ignore in case of nfs-errors (could be a default-value). Must be power of 2!
-
- @implementation SpyTextFieldCell
-
- static List *tmpList = nil; // list for selected cells in exMatrix
-
- + (void)setSharedTmpList:newList
- {
- tmpList = newList;
- }
-
- + sharedTmpList
- {
- return tmpList;
- }
-
- - init
- {
-
- [super init];
- fileLenght = lastFileLenght = 0;
- fileex = oldfileex = NO;
- textloaded = NO;
- dirloaded = NO;
- firstTime = 2;
- permissionOK = oldpermissionOK = YES;
- maxLines = 0;
- zeroFlag = NO;
- nrEINVAL = 0;
-
- // init font object
- myFont = [Font newFont:"Ohlfs"
- size:10
- style:0
- matrix:NX_FLIPPEDMATRIX];
- [Text setDefaultFont:myFont];
- myDoc = [Document new:self];
- myWindow = [[myDoc scrollView] window];
- myScrollView = [myDoc scrollView];
- myText = [[myDoc scrollView] docView];
- [myWindow setFreeWhenClosed:NO];
- color = NX_COLORBLACK;
-
- return self;
- }
-
- - delete
- {
- if(exCell) {
- int row, col;
-
- [exMatrix getRow:&row andCol:&col ofCell:exCell];
- [exMatrix removeRowAt:row andFree:YES];
- }
- [myDoc free];
- [myWindow setDelegate:nil];
- [myWindow setFreeWhenClosed:YES];
- [myWindow close];
- return self;
- }
-
- - free
- {
- return [super free];
- }
-
- - (long int)lastFileLenght
- {
- return lastFileLenght;
- }
-
- - setLastFileLenght:(long int)lenght
- {
- lastFileLenght = lenght;
- return self;
- }
-
- - (BOOL)fileExists
- {
- return fileex;
- }
-
- - updateFile
- // This is important. It checks the file and looks whether something has changed with it
- {
- if(nrEINVAL > 0) { // if we had nfs errors recently then wait for next check with
- // exponentially increasing time between two checks (proposed by mwa)
- unsigned int i = MAXSLOWDOWN;
-
- while((i > 0) && (i >= nrEINVAL)) {
- if(nrEINVAL % i == 0)
- break;
- i /= 2;
- }
- if(nrEINVAL % i != 0) {
- nrEINVAL++;
- return self;
- }
- }
- oldfileex = fileex;
- oldpermissionOK = permissionOK;
- if(firstTime > 0) { // if we're here for the first or second time
- // firstTime has the following meanings: 2: first time here
- // 1: second time here
- // 0: nth time here, no more special cases
- struct stat st;
-
- if(stat([self stringValue], &st) < 0) {
- switch(errno) {
- case ENOENT: // file doesn't exist
- case ENOTDIR: // part of path-prefix is not a directory, so file doesn't exist
- fileType = FILETYPE_NOTHING;
- break;
- case EACCES:
- fileType = FILETYPE_NOTHING;
- if((firstTime == 2) && !(spytype & SPY_EXISTENCE))
- printf("filespy: no permission for %s\n", [self stringValue]);
- permissionOK = NO;
- break;
- case EINVAL: // in case of 'nfs-server blafasel not responding still trying'
- if(nrEINVAL++ == 0) {
- perror("filespy: stat");
- }
- break;
- default:
- perror("filespy: stat");
- fileex = NO;
- }
- firstTime = 1; // next time we will be here for the second time
- } else { // stat() was ok
- fileex = YES; // yes, the file exists
- permissionOK = YES; // yes, we can read the file
- nrEINVAL = 0; // no more nfs errors
- if(st.st_mode & S_IFDIR) { // the file is a deriectory
- fileType = FILETYPE_DIR;
- lastmtime = (time_t)0; // as we're here for the first or second time, we haven't checked the file before
- if((firstTime == 1) && !(spytype & SPY_EXISTENCE)) { // if dir was created and we're not spying for ex.
- printf("filespy: created directory %s\n", [self stringValue]); // (if we were spying for existence,
- // then this would be noted in the existence-log, so we wouldn't need a printf)
- }
- } else if(st.st_mode & S_IFREG) { // the file is a regular file
- fileType = FILETYPE_FILE;
- fileLenght = st.st_size; // remember its current size
- if(fileMode == RADIO_ENTIRE) // if we will have to read the whole content,
- lastFileLenght = 0; // just pretend that the file grew from 0 length.
- else if(fileMode == RADIO_NEW) // otherwise, this is the initial file length
- lastFileLenght = fileLenght;
- if((firstTime == 1) && (fileLenght == 0) && !(spytype & SPY_EXISTENCE)) {
- // if we're here for the second time (i.e. the file didn't exist before) and the new file's length
- // is 0 bytes and we're not spying for existence, we have to make the user aware of the new file.
- printf("filespy: created empty file %s\n", [self stringValue]);
- }
- } else {
- printf("filespy: not supported filetype in file %s\n", [self stringValue]); // what should I do with other filetypes?
- }
- firstTime = 0; // now we can handle this file in the regular way
- }
- } else if(fileType == FILETYPE_FILE) { // this is a regular file
- struct stat st;
-
- if(stat([self stringValue], &st) < 0) {
- switch (errno) {
- case ENOENT: // no such file or directory
- case ENOTDIR: // some part of the path changed from directory to file -> file can't exist anymore
- [self fileRemoved];
- lastFileLenght = fileLenght;
- fileLenght = 0;
- firstTime = 2; // well, the file doesn't exist anymore, so it's a special case again
- if(!permissionOK) { // if we didn't have permission before...
- if(!(spytype & SPY_EXISTENCE)) {
- printf("filespy: regained permission for not existing file %s\n", [self stringValue]);
- // I'm sure whether this message makes much sense...
- }
- permissionOK = YES; // we have permissions (well, sort of..)
- }
- break;
- case EACCES: // access denied
- if(permissionOK) {
- if(!(spytype & SPY_EXISTENCE))
- printf("filespy: lost permission for file %s\n", [self stringValue]);
- permissionOK = NO;
- }
- break;
- case EINVAL: // nfs server not responding
- if(nrEINVAL++ == 0) { // do not report nfs-error each time the file is checked
- perror("filespy: stat");
- }
- break;
- default:
- perror("filespy: stat");
- }
- } else { // stat() was ok
- nrEINVAL = 0; // no more nfs errors
- if(!permissionOK) { // if we didn't have permission before
- if(!(spytype & SPY_EXISTENCE))
- printf("filespy: regained permission for file %s\n", [self stringValue]);
- permissionOK = YES;
- }
- if(!(st.st_mode & S_IFREG)) { // the file is no longer a regular file
- [self fileRemoved];
- lastFileLenght = fileLenght;
- fileLenght = 0;
- firstTime = 2;
- } else {
- lastFileLenght = fileLenght;
- fileLenght = st.st_size;
- fileex = YES; // yes, the file exists
- }
- }
- } else if(fileType == FILETYPE_DIR) { // this file is a directory
- struct stat st;
-
- if(stat([self stringValue], &st) < 0) {
- switch(errno) {
- case ENOENT:
- case ENOTDIR:
- [self fileRemoved];
- lastmtime = mtime;
- firstTime = 2;
- if(!permissionOK) {
- if(!(spytype & SPY_EXISTENCE))
- printf("filespy: regained permission for not existing directory %s\n", [self stringValue]);
- permissionOK = YES;
- }
- break;
- case EACCES:
- if(permissionOK) {
- if(!(spytype & SPY_EXISTENCE))
- printf("filespy: lost permission for directory %s\n", [self stringValue]);
- permissionOK = NO;
- }
- break;
- case EINVAL: // nfs server not responding
- if(nrEINVAL++ == 0) {
- perror("filespy: stat");
- }
- break;
- default:
- perror("filespy: stat");
- }
- } else {
- nrEINVAL = 0; // no more nfs errors
- if(!permissionOK) {
- if(!(spytype & SPY_EXISTENCE))
- printf("filespy: regained permission for directory %s\n", [self stringValue]);
- permissionOK = YES;
- }
- if(!(st.st_mode & S_IFDIR)) { // this file is no longer a directory
- [self fileRemoved];
- lastmtime = mtime;
- firstTime = 2;
- } else {
- oldfileex = fileex;
- lastmtime = mtime;
- mtime = st.st_mtime; // when was the directory last modified?
- if(!dirStore) { // if we don't have the directory's contents yet, then read them
- DIR *dirp;
- struct direct *dp;
- // read all filenames and put them in dirStore
- dirp = opendir([self stringValue]);
- if(dirp != NULL) {
- dirStore = [[Storage alloc]
- initCount:0 elementSize:MAXFILENAMELENGHT
- description:"[MAXFILENAMELENGHT c]"];
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
- [dirStore addElement:dp->d_name];
- closedir(dirp);
- }
- }
- }
- }
- }
- if((spytype & SPY_EXISTENCE) && fileex) {
- time_t myTime = time(NULL);
- [exCell changeTime:myTime];
- }
- return self;
- }
-
- - updateText
- // This one checks whether it is necessary to read the contents of the file or update the existencewindow
- {
- if((fileType == FILETYPE_FILE) && (spytype & SPY_CONTENTS))
- [self readText];
- else if((fileType == FILETYPE_DIR) && (spytype & SPY_CONTENTS))
- [self readDir];
- if(spytype & SPY_EXISTENCE)
- [self updateExistence];
- return self;
- }
-
- - readText
- // read contents of changed regular file
- {
- if(fileLenght < lastFileLenght) { // if the file shrunk
- if((fileLenght > 0) || zeroFlag) { // if there's still something in it or it had 0 length last time we checked...
- // (we do not report that a file has shrunken to 0 bytes the first time we notice it. there are
- // commands in /usr/adm/daily which produce length-0-files for a very short time (e.g. with 'tail'))
- printf("filespy: file %s reduced its size from %ld to %ld bytes\n", [self stringValue], lastFileLenght, fileLenght);
- switch(fileMode) {
- case RADIO_NEW: lastFileLenght = fileLenght; break;
- case RADIO_ENTIRE: lastFileLenght = 0; break;
- }
- zeroFlag = NO;
- } else {
- zeroFlag = YES; // first check that this file has length 0 for a longer time
- fileLenght = lastFileLenght; // ignore new filelength it until next check
- }
- [self contentChanged]; // however, something did change
- }
- if(fileLenght > lastFileLenght) { // if the file grew then get the new text and send it to addText
- int diff = fileLenght - lastFileLenght;
- char *newString = malloc(diff + 2);
- FILE *fp;
-
- if((fp = fopen([self stringValue], "r")) == (FILE *)NULL) {
- printf("filespy: couldn't open file %s\n", [self stringValue]);
- } else {
- if(fseek(fp, lastFileLenght, SEEK_SET) == 0) {
- if(fread(newString, sizeof(char), diff, fp) != 0) {
- newString[diff] = '\000';
- newString[diff+1] = '\000';
- [self addText:newString];
- } else {
- perror("filespy: fread");
- }
- } else {
- perror("filespy: fseek");
- }
- fclose(fp);
- }
- free(newString);
- } else if(fileLenght == lastFileLenght)
- textloaded = YES;
- return self;
- }
-
- - readDir
- // the contents of a directory and remember it
- {
- DIR *dirp;
- struct direct *dp;
- unsigned int pos = 0, count = [dirStore count];
- node root, actnode, tmpnode; // pointers to nodedescs
-
- if((dirp = opendir([self stringValue])) == NULL) {
- if(errno == EACCES)
- printf("filespy: no permission to read directory %s\n", [self stringValue]);
- else
- perror("filespy: opendir");
- return self;
- }
- actnode = root = NULL;
- for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- if((pos >= count) || (strcmp(dp->d_name, [dirStore elementAt:pos]) != 0)) {
- unsigned int i = pos;
- while(i < count && (strcmp(dp->d_name, (char *)[dirStore elementAt:i]) != 0))
- i++;
- if(i >= count) { // not found, so it's a new file
- // remember all new files in a linked list so that we can print them later
- char str[MAXFILENAMELENGHT + 10] = "new file: ";
-
- [dirStore insertElement:dp->d_name at:pos]; // remember new file
- count++;
- strcat(str, dp->d_name);
- strcat(str, "\n");
- tmpnode = (node)malloc(sizeof(nodedesc));
- if(actnode != NULL) {
- actnode->next = tmpnode;
- } else {
- root = tmpnode;
- }
- tmpnode->string = (char *)malloc(strlen(str)+1);
- strcpy(tmpnode->string, str);
- tmpnode->next = NULL;
- actnode = tmpnode;
- } else { // found, so files between pos and i are deleted
- // remember the deleted files so that we can print them later
- unsigned int j;
- for(j = pos; j < i; j++) {
- char str[MAXFILENAMELENGHT + 14] = "removed file: ";
- strcat(str, (char *)[dirStore elementAt:j]);
- strcat(str, "\n");
- tmpnode = (node)malloc(sizeof(nodedesc));
- if(actnode != NULL) {
- actnode->next = tmpnode;
- } else {
- root = tmpnode;
- }
- tmpnode->string = (char *)malloc(strlen(str)+1);
- strcpy(tmpnode->string, str);
- tmpnode->next = NULL;
- actnode = tmpnode;
- [dirStore removeElementAt:j];
- count--;
- }
- }
- }
- pos++;
- }
- closedir(dirp);
- if(pos < count) { // rest of the files in dirStore have been deleted
- unsigned int i, max = [dirStore count];
- for(i = pos; i < max; i++) {
- char str[MAXFILENAMELENGHT + 14] = "removed file: ";
- strcat(str, (char *)[dirStore elementAt:pos]);
- strcat(str, "\n");
- tmpnode = (node)malloc(sizeof(nodedesc));
- if(actnode != NULL) {
- actnode->next = tmpnode;
- } else {
- root = tmpnode;
- }
- tmpnode->string = (char *)malloc(strlen(str)+1);
- strcpy(tmpnode->string, str);
- tmpnode->next = NULL;
- actnode = tmpnode;
- [dirStore removeElementAt:pos];
- }
- }
- if(root != NULL) {
- // contents of the directory changed (linked list exists), so put all changes together in
- // a single string and pass it to addText
- unsigned int len = 0;
- char *totstr, *actstr;
-
- actnode = root;
- while(actnode != NULL) {
- len += strlen(actnode->string);
- actnode = actnode->next;
- }
- actstr = totstr = (char *)malloc(len+1);
- actnode = root;
- while(actnode != NULL) {
- strcpy(actstr, actnode->string);
- actstr = actstr + strlen(actnode->string);
- actnode = actnode->next;
- }
- [self addText:totstr];
- free(totstr);
- actnode = root; // remove the linked list
- while(actnode != NULL) {
- tmpnode = actnode;
- actnode = actnode->next;
- free(tmpnode->string);
- free(tmpnode);
- }
- }
- return self;
- }
-
- - addText:(char *)givenString
- // output the text givenString depending on the settings and preferences of the user
- {
- BOOL changed = YES, filterMode, mode = NO;
- // Bugreport Nr. 5 and 6 by Karsten Heinze: malloc()ed memory was too small (I forgot the terminating 0-Byte)
- char *newString = (char *)malloc(strlen(givenString)+1);
- int textlenght;
-
- if(maxLines > 0) // if a maximum number of lines is set, then cut the old parts of the existing text off
- [self shortText];
- filterMode = [myDelegate filterMode];
- strcpy(newString, givenString);
- textlenght = [myText textLength];
- if(useFilter) { // if the filter is active, the filter the text first
- switch(filterMode) {
- case FILTER_DONTCOPY: mode = YES; break;
- case FILTER_DONTBEEP: mode = NO; break;
- }
- changed = [myDelegate filterString:newString andRemove:mode who:self];
- if(timeStamp && (changed || (filterMode == FILTER_DONTBEEP))) { // insert timestamp in front of each line
- [self addTimeStamp:&newString];
- }
- if(changed || (filterMode == FILTER_DONTBEEP)) {
- [self appendText:newString unfilteredString:givenString didChange:changed];
- }
- } else { // without filter, just add the timeStamp if that feature is active and append the text
- if(timeStamp) {
- [self addTimeStamp:&newString];
- }
- [self appendText:newString unfilteredString:givenString didChange:changed];
- }
- if(fileType == FILETYPE_FILE)
- textloaded = YES;
- else if(fileType == FILETYPE_DIR)
- dirloaded = YES;
- free(newString);
- return self;
- }
-
- - appendText:(char *)string unfilteredString:(char *)ufString didChange:(BOOL)changed
- // append string to the text-object in myWindow. changed is YES if something passed the filter (or if the filter is not active)
- {
- int textlenght;
-
- textlenght = [myText textLength];
- [myText setSel :textlenght :textlenght];
- [myText replaceSel:string];
- [myText setSel :textlenght :[myText textLength]];
- [[[myText sizeToFit] scrollSelToVisible] display];
-
- if(!useFilter || changed) {
- if(autoPopUp && !logToSuperlog)
- [self displayWindow];
- if(beepOnChange && !logToSuperlog)
- [myDelegate nxbeep];
- }
- [self contentChanged];
- if(logToSuperlog && (fileex || !dontCopySuperlog)) {
- if([myDelegate superUsesFilter]) {
- [myDelegate updateSuperlog:self :string :changed :beepOnChange :autoPopUp];
- } else { // if the superlog doesn't use the filter, then send the unchanged string
- // changed is YES here, because nothing could have been filtered out if the multilog doesn't filter
- [myDelegate updateSuperlog:self :ufString :YES :beepOnChange :autoPopUp];
- }
- }
- return self;
- }
-
- - (BOOL)changedState
- // checks whether anything changed with this file
- {
- int ret = 0;
-
- if((spytype & SPY_CONTENTS) != 0) {
- if((fileType == FILETYPE_FILE) && (fileLenght != lastFileLenght)) {
- ret++;
- } else if((fileType == FILETYPE_DIR) && (mtime != lastmtime)) {
- ret++;
- }
- }
- if((spytype & SPY_EXISTENCE) != 0) {
- if((fileex != oldfileex) || (permissionOK != oldpermissionOK)) {
- ret++;
- }
- }
- return ret > 0;
- }
-
- - displayWindow
- {
- if(![myWindow isVisible]) {
- [myWindow orderFrontRegardless];
- [myDelegate addWindow:self];
- }
- if([myDelegate becomeKey]) {
- [myWindow makeKeyWindow];
- [myDelegate unhideApp:self];
- }
- return self;
- }
-
- - moveWindowTo:(NXCoord)x:(NXCoord)y
- {
- [myDoc moveWindowTo:x:y];
- return self;
- }
-
- - setFileMode:(int)mode
- {
- fileMode = mode;
- return self;
- }
-
- - (int)fileMode
- {
- return fileMode;
- }
-
- - setAutoPopUp:(BOOL)state
- {
- autoPopUp = state;
- return self;
- }
-
- - (BOOL)autoPopUp
- {
- return autoPopUp;
- }
-
- - window
- {
- return myWindow;
- }
-
- - setMyDelegate:sender
- {
- myDelegate = sender;
- exMatrix = [myDelegate existenceMatrix];
- return self;
- }
-
- - myDelegate
- {
- return myDelegate;
- }
-
- - setBeepOnChange:(BOOL)state
- {
- beepOnChange = state;
- return self;
- }
-
- - (BOOL)beepOnChange
- {
- return beepOnChange;
- }
-
- - setLogToSuperlog:(BOOL)state;
- {
- logToSuperlog = state;
- return self;
- }
-
- - (BOOL)logToSuperlog
- {
- return logToSuperlog;
- }
-
- - setUseFilter:(BOOL)state
- {
- useFilter = state;
- return self;
- }
-
- - (BOOL)useFilter
- {
- return useFilter;
- }
-
- - setDontCopy:(BOOL)state
- {
- dontCopySuperlog = state;
- return self;
- }
-
- - (BOOL)dontCopy
- {
- return dontCopySuperlog;
- }
-
- - setTimeStamp:(BOOL)state
- {
- timeStamp = state;
- return self;
- }
-
- - (BOOL)timeStamp;
- {
- return timeStamp;
- }
-
- - setSpytype:(unsigned short int)type
- {
- int rowCount, colCount;
- if((type & SPY_EXISTENCE) != (spytype & SPY_EXISTENCE)) { // if the type changed in existence
- if(!exCell) { // we haven't spyed for existence yet
- // so insert new exCell in existence-matrix
- [exMatrix addRow];
- [exMatrix getNumRows:&rowCount numCols:&colCount];
- exCell = [exMatrix cellAt:rowCount-1 :0];
- [exCell setStringValue:[self stringValue]];
- [exCell setMyDelegate:self];
- [exCell setTime:time(NULL)];
- [exMatrix sizeToCells];
- [exMatrix scrollCellToVisible:rowCount-1 :0];
- [exMatrix display];
- } else {
- // we were spying for this file, so we aren't any longer from now on -> remove the exCell
- [exMatrix getRow:&rowCount andCol:&colCount ofCell:exCell];
- [exMatrix removeRowAt:rowCount andFree:YES];
- [exMatrix display];
- exCell = nil;
- }
- }
- spytype = type;
- return self;
- }
-
- - (unsigned short int)spytype
- {
- return spytype;
- }
-
- - updateExistence
- {
- time_t myTime = time(NULL);
- List *tmpList = [SpyTextFieldCell sharedTmpList];
-
- if((fileex != oldfileex) || (permissionOK != oldpermissionOK)) { // existence or permission changed
- [tmpList addObject:exCell]; // remember cell to update later in controller
- if(fileex)
- [exCell setTime:myTime];
- else
- [exCell changeTime:myTime];
- if(beepOnChange)
- [myDelegate nxbeep];
- if(autoPopUp)
- [myDelegate showExistencelogRegardless];
- }
- return self;
- }
-
- - setSuperCopyFilename:(unsigned int)state
- {
- superCopyFilename = state;
- return self;
- }
-
- - (unsigned int)superCopyFilename;
- {
- return superCopyFilename;
- }
-
- - setStringValue:(const char *)str
- {
- [myWindow setTitleAsFilename:str];
- return [super setStringValue:str];
- }
-
- - clearBuffer:sender
- {
- [myText setSel :0 :[myText textLength]];
- [myText replaceSel:""];
- [[myText sizeToFit] scrollSelToVisible];
- [self contentChanged];
- return self;
- }
-
- - contentChanged
- {
- if(![myWindow isKeyWindow] && ![myWindow isDocEdited])
- [myWindow setDocEdited:YES];
- return self;
- }
-
- - fileRemoved
- // prepares string that says which file/directories have been removed
- {
- char str[MAXFILENAMELENGHT + 14] = "removed ";
-
- if(fileType == FILETYPE_FILE) { // this file has been removed
- strcat(str, "file: ");
- } else if(fileType == FILETYPE_DIR) { // the whole directory has been removed, so output the names of all the files in it
- if([dirStore count] > 2) {
- unsigned int i, max = [dirStore count];
- node root, actnode, tmpnode;
-
- actnode = root = NULL;
- for(i = 2; i < max; i++) {
- char str[MAXFILENAMELENGHT + 14] = "removed file: ";
- strcat(str, (char *)[dirStore elementAt:2]);
- strcat(str, "\n");
- tmpnode = (node)malloc(sizeof(nodedesc));
- if(actnode != NULL) {
- actnode->next = tmpnode;
- } else {
- root = tmpnode;
- }
- tmpnode->string = (char *)malloc(strlen(str)+1);
- strcpy(tmpnode->string, str);
- tmpnode->next = NULL;
- actnode = tmpnode;
- [dirStore removeElementAt:2];
- }
- if(root != NULL) {
- unsigned int len = 0;
- char *totstr, *actstr;
-
- actnode = root;
- while(actnode != NULL) {
- len += strlen(actnode->string);
- actnode = actnode->next;
- }
- actstr = totstr = (char *)malloc(len+1);
- actnode = root;
- while(actnode != NULL) {
- strcpy(actstr, actnode->string);
- actstr = actstr + strlen(actnode->string);
- actnode = actnode->next;
- }
- [self addText:totstr];
- free(totstr);
- actnode = root;
- while(actnode != NULL) {
- tmpnode = actnode;
- actnode = actnode->next;
- free(tmpnode->string);
- free(tmpnode);
- }
- }
- }
- strcat(str, "dir: ");
- }
- strcat(str, [self stringValue]);
- if(!(spytype & SPY_EXISTENCE)) // only print message if we're not spying for existence
- puts(str); // otherwise we have to update the existence-log
- fileType = FILETYPE_NOTHING;
- fileex = NO;
- return self;
- }
-
- - windowDidBecomeKey:sender
- {
- if([sender isDocEdited])
- [sender setDocEdited:NO];
- [myDelegate windowDidBecomeKey:sender];
- return self;
- }
-
- - windowWillClose:sender
- {
- [myDelegate windowWillClose:sender];
- return self;
- }
-
- - text
- {
- return myText;
- }
-
- - (NXColor)color
- {
- return color;
- }
-
- - setColor:(NXColor)newColor
- {
- color = newColor;
- [myText setTextColor:color];
- [myText display];
- return self;
- }
-
- - setSpyFont:newFont
- {
- myFont = newFont;
- [myText setFont:myFont];
- [myText scrollSelToVisible];
- return self;
- }
-
- - addTimeStamp:(char **)string
- // add current time in front of each line in string
- {
- #define TIMELEN 19 // length of timestring
- time_t mytime = time((time_t *)NULL);
- struct tm *tp = localtime(&mytime);
- char tstr[TIMELEN], *tmpText, *p, *cp;
- unsigned int n = 0, tlen;
- BOOL copied;
-
- strftime(tstr, (size_t)TIMELEN, "{%b %d %H:%M:%S} ", tp);
- tlen = strlen(tstr);
- p = *string;
- while(*p != '\000') {
- if(*p++ == '\n')
- n++; // count number of lines
- }
- tmpText = (char *)malloc(strlen(*string) + n*TIMELEN + 1);
- tmpText[0] = '\000';
- p = *string;
- cp = tmpText;
- copied = NO;
- while(*p != '\000') {
- if(!copied) {
- strcpy(cp, tstr);
- cp += tlen;
- copied = YES;
- }
- *cp++ = *p;
- if(*p++ == '\n')
- copied = NO;
- }
- *cp = '\000';
- free(*string);
- *string = tmpText;
- return self;
- }
-
- - spyFont
- {
- return myFont;
- }
-
- - setMaxLines:(int)lines
- {
- maxLines = lines;
- return self;
- }
-
- - shortText
- // remove lines from the beginning of the text so that the text has not more than maxLines lines
- {
- int textLen = [myText textLength];
- int textLines = [myText lineFromPosition:textLen];
-
- if(textLines > maxLines) {
- [[myText setSel:0 :[myText positionFromLine:(textLines - maxLines)]] replaceSel:""];
- }
- return self;
- }
-
- - (BOOL)permissionOk
- {
- return permissionOK;
- }
-
- - setShowTime:(BOOL)state
- {
- // [exCell setTime:time(NULL)];
- showTime = state;
- return self;
- }
-
- - (BOOL)showTime
- {
- return showTime;
- }
-
- - (BOOL)askUpdateTime
- {
- return (spytype & SPY_EXISTENCE) && fileex; // need to update time in existenceTextFieldCell
- }
-
- - drawInside:(const NXRect *)cellFrame inView:controlView // taken from 'ScrollDoodScroll' and modified
- {
- #define IMAGEMARGIN 4.0
- /* every CustomCell needs these two */
- static id sharedTextCell = nil;
- NXRect rect = *cellFrame;
- NXRect boxRect;
- NXCoord size;
- NXSize ESize;
- NXPoint imageOrigin;
-
- /* erase the cell */
- PSsetgray((cFlags1.state || cFlags1.highlighted) ? NX_WHITE : NX_LTGRAY);
- NXRectFill(cellFrame);
- size = NX_HEIGHT(cellFrame) - 2*IMAGEMARGIN;
- if(spytype & SPY_CONTENTS) { // If we're only spying for existence, we don't need a colorbox
- NXSetColor(color);
- NXSetRect(&boxRect, NX_X(cellFrame) + IMAGEMARGIN, NX_Y(cellFrame) + IMAGEMARGIN,
- size, size);
- NXRectFill(&boxRect);
- } else {
- if(!EImage) {
- EImage = [NXImage findImageNamed:"E"];
- }
- [EImage getSize:&ESize];
- imageOrigin.x = NX_X(cellFrame) + IMAGEMARGIN;
- imageOrigin.y = NX_Y(cellFrame) + NX_HEIGHT(cellFrame) -
- (NX_HEIGHT(cellFrame) - ESize.height) / 2.0;
-
- [EImage composite:NX_SOVER toPoint:&imageOrigin];
- }
- NX_WIDTH(&rect) -= (size + IMAGEMARGIN * 2.0 - NX_X(&rect));
- NX_X(&rect) += size + IMAGEMARGIN * 2.0;
-
- if (!sharedTextCell) {
- sharedTextCell = [[Cell alloc] init];
- [sharedTextCell setWrap:NO];
- }
- [sharedTextCell setFont:[self font]];
- [sharedTextCell setStringValue:[self stringValue]];
- [sharedTextCell drawInside:&rect inView:controlView];
-
- /* all drawing from now on will be in dark gray */
- PSsetgray(NX_DKGRAY);
-
- /* draw the two dark gray lines above and below the cell */
- if (cFlags1.state || cFlags1.highlighted) {
- NXRect rectArray[2];
- /*
- * draw 1-pixel tall rectangles instead of lines (this is faster than
- * PSmoveto(); PSlineto()).
- */
- NXSetRect(&(rectArray[0]), NX_X(cellFrame), NX_Y(cellFrame),
- NX_WIDTH(cellFrame), 1.0);
- NXSetRect(&(rectArray[1]), NX_X(cellFrame), NX_MAXY(cellFrame) - 1.0,
- NX_WIDTH(cellFrame), 1.0);
-
- /* using NXRectFillList is faster than separate calls to NXRectFill */
- NXRectFillList(rectArray, 2);
- }
-
- return self;
- }
-
- - highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag
- {
- if (cFlags1.highlighted != flag) {
- cFlags1.highlighted = flag;
- [self drawInside:cellFrame inView:controlView];
- }
- return self;
- }
-
- @end
-