home *** CD-ROM | disk | FTP | other *** search
- //
- // DAYLockFile.h -- a generic class to simplify keeping an atomic lock file
- // Written by Don Yacktman (c) 1993 by Don Yacktman.
- // Version 1.0. All rights reserved.
- //
- // This is a free object! Contact the author for the latest version.
- // Don Yacktman, 4279 N. Ivy Lane, Provo, UT, 84604
- // e-mail: Don_Yacktman@byu.edu
- //
- // You may use and copy this class freely as long as you
- // comply with the following terms:
- // (1) Do not remove the author's name or any of the
- // copyright notices from this file.
- // (2) If you redistribute an application which uses this
- // object, you must either include the source code for
- // this object with the application or state in your
- // application's documentation that you (a) use this
- // object and (b) where to obtain the source code for
- // the object.
- // (3) In no way shall the author or his employer(s) be held
- // responsible for any damages caused by what this object
- // does or does not do.
- // (4) You have no warranty whatsoever that this object is
- // good for any purpose at all. If you find it useful
- // for something, consider yourself lucky and leave it at that.
- //
-
- // ***** denotes an unfinished/unimplemented method.
-
- #import <daymisckit/daymisckit.h>
- #import <stdio.h>
-
- @interface DAYLogFile(private)
-
- - _newLine; // forces the log to start without any history.
- - _printRepeats; // "Last line repeated x times."
-
- @end
-
- @implementation DAYLogFile
-
- - init
- {
- id ret = [super init];
- fileOpen = NO; special = NO;
- return ret;
- }
-
- - fileName { return fileName; }
- - setFileName:aString
- {
- if (fileOpen) [self closeFile];
- [lockFile free];
- lockFile = nil;
- special = NO;
- fileName = aString;
- return self;
- }
-
- - setLockFile:newLockFile
- {
- [lockFile free];
- lockFile = newLockFile;
- return self;
- }
-
- - (BOOL)addLineToLogFile:aString
- {
- if (![self openFile]) return NO;
- if (![self appendToLogFile:aString andFlush:NO]) return NO;
- if (![self closeFile]) return NO;
- return YES;
- }
-
- - _newLine // forces the log to start without any history.
- {
- repeats = 0;
- if (lastLine) {
- [lastLine free]; lastLine = nil;
- }
- return self;
- }
-
- - (BOOL)openFile
- {
- if (special) return YES; // stdin and stdout are open already
- if (fileOpen) return YES; // file is already open
- if (lockFile) if (![lockFile lock]) return NO; // lock if needed
- file = fopen([fileName stringValue], "a"); // do the open
- if (!file) return NO;
- fileOpen = YES;
- [self _newLine];
- return YES;
- }
-
- - (BOOL)closeFile
- {
- if (special) return YES; // don't close stdin or stdout
- if (!fileOpen) return NO; // can't close an unopened file
- [self _printRepeats];
- fclose(file);
- if (lockFile) if (![lockFile unlock]) return NO; // unlock if needed
- fileOpen = NO;
- return YES;
- }
-
- - _printRepeats
- {
- if (repeats) {
- fprintf(file, "Last line repeated %d time%s\n", repeats,
- ((repeats == 1) ? "." : "s."));
- }
- [self _newLine];
- return self;
- }
-
- - (BOOL)appendToLogFile:aString andFlush:(BOOL)flushFlag
- {
- if (!fileOpen) return NO;
- // if the file is open, then we should have the lock.
- // however, the user can get around our mechanism if they want, so
- // we'd best check anyway, just to be sure.
- if (lockFile && !special) if (![lockFile haveLock]) return NO;
- // flushing will force a write; not flushing allows us to "compress"
- // log messages by printing only number of repeats.
- if (lastLine && !flushFlag) { // have a previous line, see if it repeats...
- if ([lastLine isEqual:aString]) { // same as before
- repeats++;
- return YES; // don't print; keep tallying
- } }
- // if got here, the log line is different than last time.
- [self _printRepeats];
- fprintf(file, "%s", [aString stringValue]);
- lastLine = [aString copy];
- if (flushFlag) if (fflush(file) == EOF) return NO;
- return YES;
- }
-
- - usestdout
- {
- [self setFileName:[[DAYString alloc] initString:"stdout"]];
- special = YES;
- fileOpen = YES;
- file = stdout;
- return self;
- }
-
- - usestderr
- {
- [self setFileName:[[DAYString alloc] initString:"stderr"]];
- special = YES;
- fileOpen = YES;
- file = stderr;
- return self;
- }
-
- - (FILE *)file { if (fileOpen) return file; else return NULL; }
- - (BOOL)fileIsOpen { return fileOpen; }
- - (BOOL)special { return special; }
- - lockFile { return lockFile; }
-
- - copy
- { // copies do not have locks or open logs... only original can!
- id myCopy = [[DAYLogFile alloc] init];
- [myCopy setFileName:fileName];
- [myCopy setLockFile:[lockFile copy]];
- return myCopy;
- }
-
- - read:(NXTypedStream *)stream
- {
- [super read:stream];
- fileName = NXReadObject(stream);
- lockFile = NXReadObject(stream);
- return self;
- }
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteObject(stream, fileName);
- NXWriteObject(stream, lockFile);
- return self;
- }
-
- // NXTransport protocol implementation:
- - encodeUsing:(id <NXEncoding>)portal
- {
- [portal encodeObjectBycopy:fileName];
- [portal encodeObjectBycopy:lockFile];
- return self;
- }
-
- - decodeUsing:(id <NXDecoding>)portal
- {
- fileName = [portal decodeObject];
- lockFile = [portal decodeObject];
- return self;
- }
-
- - encodeRemotelyFor:(NXConnection *)connection
- freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy
- {
- if (isByCopy) {
- *flagp = NO; // object will copy.
- return self; //encode object (copy it)
- }
- *flagp = NO; // object will copy.
- // super will encode the proxy otherwise
- return [super encodeRemotelyFor:connection
- freeAfterEncoding:flagp isBycopy:isByCopy];
- }
-
- - free
- {
- if (fileOpen) [self closeFile];
- [lockFile free];
- [fileName free];
- return [super free];
- }
-
- @end
-