void __saveds __asm ULogA(register __a0 PagerHandle_t * ph, register __d0 LONG level, register __a1 STRPTR fmt, register __a2 LONG *args)
{
	BPTR loghandle = NULL;
	struct DateTime dat;
	UBYTE Date[LEN_DATSTRING + 1];
	UBYTE Time[LEN_DATSTRING + 1];
	BOOL didLock = FALSE;
	STRPTR logFilename;

	if (level > ph->ph_LogLevel)
		return;

	DateStamp(&dat.dat_Stamp);

	dat.dat_Format = FORMAT_DOS;
	dat.dat_Flags = 0;
	dat.dat_StrDay = NULL;
	dat.dat_StrDate = Date;
	dat.dat_StrTime = Time;

	memset(Date, 0, LEN_DATSTRING + 1);
	memset(Time, 0, LEN_DATSTRING + 1);
	DateToStr(&dat);

	ObtainSemaphore(&ph->ph_Sema);

	if (ph->ph_LogRetries++ == 0) {
		if (LockFile(ph, "LOG-UPDATE")) {
			didLock = TRUE;
			if (logFilename = FindPagerConfig(ph, "LOGFILE")) {
				loghandle = Open(logFilename, MODE_READWRITE);

				/*
				 * we don't actually call
				 * FreePagerConfig(logFilename) here.  this
				 * way, the config entry will remain loaded
				 * in memory and any subsequent calls the
				 * client makes to ULog will not have to
				 * re-read the config file to find out where
				 * the log file is located.  when the client
				 * calls FreePagerHandle() the config entry
				 * for the logfile name will finally go away.
				 */
			}
			else if (logFilename = NameInSpool(ph, "LOGFILE")) {
				loghandle = Open(logFilename, MODE_READWRITE);
				FreeNameInSpool(logFilename);
			}
		}
	}

	if (loghandle) {
		Seek(loghandle, 0, OFFSET_END);

		FPrintf(loghandle, "(%s %s) %s,%s,%s ", Date, Time, ph->ph_LogProgram, ph->ph_LogService, ph->ph_LogWho);
		VFPrintf(loghandle, fmt, args);
		FPutC(loghandle, '\n');
	}

	if (--ph->ph_LogRetries == 0) {
		if (loghandle)
			Close(loghandle);

		if (didLock)
			UnLockFile(ph, "LOG-UPDATE");
	}

	ReleaseSemaphore(&ph->ph_Sema);
}

void ULog(PagerHandle_t * ph, LONG level, STRPTR fmt,...)
{
	va_list args;

	va_start(args, fmt);
	ULogA(ph, level, fmt, (LONG *)args);
	va_end(args);
}

void __saveds __asm SetLogLevel(register __a0 PagerHandle_t * ph, register __d0 LONG level)
{
	ObtainSemaphore(&ph->ph_Sema);

	ph->ph_LogLevel = level;

	ReleaseSemaphore(&ph->ph_Sema);
}

void __saveds __asm SetLogService(register __a0 PagerHandle_t * ph, register __a1 STRPTR serviceName)
{
	ObtainSemaphore(&ph->ph_Sema);

	ph->ph_LogService = (serviceName ? serviceName : "-");

	ReleaseSemaphore(&ph->ph_Sema);
}

void __saveds __asm SetLogWho(register __a0 PagerHandle_t * ph, register __a1 STRPTR whoName)
{
	ObtainSemaphore(&ph->ph_Sema);

	ph->ph_LogWho = (whoName ? whoName : "-");

	ReleaseSemaphore(&ph->ph_Sema);
}
