blob: 8a1dce1409d1d122ab3a4f4719f8d2ec3dbcd008 [file] [log] [blame]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#include "log.h"
#include "log_history.h"
#include "timing.h"
struct LogEntryStruct {
struct LogEntryStruct *previous;
TimeValue time;
unsigned int count;
unsigned noSquash:1;
char text[0];
};
const LogEntry *
getPreviousLogEntry (const LogEntry *entry) {
return entry->previous;
}
const char *
getLogEntryText (const LogEntry *entry) {
return entry->text;
}
const TimeValue *
getLogEntryTime (const LogEntry *entry) {
return &entry->time;
}
unsigned int
getLogEntryCount (const LogEntry *entry) {
return entry->count;
}
int
pushLogEntry (LogEntry **head, const char *text, LogEntryPushOptions options) {
int log = !(options & LPO_NOLOG);
LogEntry *entry = NULL;
if (options & LPO_SQUASH) {
if ((entry = *head)) {
if (!entry->noSquash && (strcmp(entry->text, text) == 0)) {
entry->count += 1;
} else {
entry = NULL;
}
}
}
if (!entry) {
const size_t size = sizeof(*entry) + strlen(text) + 1;
if (!(entry = malloc(size))) {
if (log) logMallocError();
return 0;
}
memset(entry, 0, sizeof(*entry));
entry->count = 1;
strcpy(entry->text, text);
entry->previous = *head;
*head = entry;
}
getCurrentTime(&entry->time);
return 1;
}
int
popLogEntry (LogEntry **head) {
if (!*head) return 0;
LogEntry *entry = *head;
*head = entry->previous;
free(entry);
return 1;
}
static CriticalSectionLock logMessageLock = CRITICAL_SECTION_LOCK_INITIALIZER;
static void
lockLogMessages (void) {
enterCriticalSection(&logMessageLock);
}
static void
unlockLogMessages (void) {
leaveCriticalSection(&logMessageLock);
}
static LogEntry *logMessageStack = NULL;
const LogEntry *
getNewestLogMessage (int freeze) {
lockLogMessages();
LogEntry *message = logMessageStack;
if (freeze && message) message->noSquash = 1;
unlockLogMessages();
return message;
}
void
pushLogMessage (const char *message) {
lockLogMessages();
pushLogEntry(&logMessageStack, message, (LPO_NOLOG | LPO_SQUASH));
unlockLogMessages();
}