📄 sim_log.c
字号:
// $Id: sim_log.c,v 1.6 2008/06/11 00:46:26 razvanm Exp $
/*
* "Copyright (c) 2005 Stanford University. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose, without fee, and without written
* agreement is hereby granted, provided that the above copyright
* notice, the following two paragraphs and the author appear in all
* copies of this software.
*
* IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* STANFORD UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
* PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND STANFORD UNIVERSITY
* HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
* ENHANCEMENTS, OR MODIFICATIONS."
*/
/**
* The TOSSIM logging system.
*
* @author Phil Levis
* @date November 9 2005
*/
#include <sim_log.h>
#include <stdio.h>
#include <stdarg.h>
#include <hashtable.h>
#include <string.h>
enum {
DEFAULT_CHANNEL_SIZE = 8
};
typedef struct sim_log_output {
int num;
FILE** files;
} sim_log_output_t;
typedef struct sim_log_channel {
const char* name;
int numOutputs;
int size;
FILE** outputs;
} sim_log_channel_t;
enum {
SIM_LOG_OUTPUT_COUNT = uniqueCount("TOSSIM.debug")
};
sim_log_output_t outputs[SIM_LOG_OUTPUT_COUNT];
struct hashtable* channelTable = NULL;
static unsigned int sim_log_hash(void* key);
static int sim_log_eq(void* key1, void* key2);
// First we count how many outputs there are,
// then allocate a FILE** large enough and fill it in.
// This FILE** might be larger than needed, because
// the outputs of the channels might have redundancies.
// E.g., if two channels A and B are both to stdout, then
// you don't want a channel of "A,B" to be doubly printed
// to stdout. So when the channel's FILE*s are copied
// into the debug point output array, this checks
// for redundancies by checking file descriptors.
static void fillInOutput(int id, char* name) {
char* termination = name;
char* namePos = name;
int count = 0;
char* newName = (char*)malloc(strlen(name) + 1);
memset(newName, 0, strlen(name) + 1);
// Count the outputs
while (termination != NULL) {
sim_log_channel_t* channel;
termination = strrchr(namePos, ',');
// If we've reached the end, just copy to the end
if (termination == NULL) {
strcpy(newName, namePos);
}
// Otherwise, memcpy over and null terminate
else {
memcpy(newName, namePos, (termination - namePos));
newName[termination - namePos] = 0;
}
channel = hashtable_search(channelTable, namePos);
if (channel != NULL) {
count += channel->numOutputs;
}
namePos = termination + 1;
}
termination = name;
namePos = name;
// Allocate
outputs[id].files = (FILE**)malloc(sizeof(FILE*) * count);
outputs[id].num = 0;
// Fill it in
while (termination != NULL) {
sim_log_channel_t* channel;
termination = strrchr(namePos, ',');
// If we've reached the end, just copy to the end
if (termination == NULL) {
strcpy(newName, namePos);
}
// Otherwise, memcpy over and null terminate
else {
memcpy(newName, namePos, (termination - namePos));
newName[termination - namePos] = 0;
}
channel = hashtable_search(channelTable, namePos);
if (channel != NULL) {
int i, j;
for (i = 0; i < channel->numOutputs; i++) {
int duplicate = 0;
int outputCount = outputs[id].num;
// Check if we already have this file descriptor in the output
// set, and if so, ignore it.
for (j = 0; j < outputCount; j++) {
if (fileno(outputs[id].files[j]) == fileno(channel->outputs[i])) {
duplicate = 1;
j = outputCount;
}
}
if (!duplicate) {
outputs[id].files[outputCount] = channel->outputs[i];
outputs[id].num++;
}
}
}
namePos = termination + 1;
}
}
void sim_log_init() {
int i;
channelTable = create_hashtable(128, sim_log_hash, sim_log_eq);
for (i = 0; i < SIM_LOG_OUTPUT_COUNT; i++) {
outputs[i].num = 1;
outputs[i].files = (FILE**)malloc(sizeof(FILE*));
outputs[i].files[0] = fdopen(1, "w"); // STDOUT
}
}
void sim_log_add_channel(char* name, FILE* file) {
sim_log_channel_t* channel;
channel = (sim_log_channel_t*)hashtable_search(channelTable, name);
// If there's no current entry, allocate one, initialize it,
// and insert it.
if (channel == NULL) {
char* newName = (char*)malloc(strlen(name) + 1);
strcpy(newName, name);
newName[strlen(name)] = 0;
channel = (sim_log_channel_t*)malloc(sizeof(sim_log_channel_t));
channel->name = newName;
channel->numOutputs = 0;
channel->size = DEFAULT_CHANNEL_SIZE;
channel->outputs = (FILE**)malloc(sizeof(FILE*) * channel->size);
memset(channel->outputs, 0, sizeof(FILE*) * channel->size);
hashtable_insert(channelTable, newName, channel);
}
// If the channel output table is full, double the size of
// channel->outputs.
if (channel->numOutputs == channel->size) {
FILE** newOutputs;
int newSize = channel->size * 2;
newOutputs = (FILE**)malloc(sizeof(FILE*) * newSize);
memcpy(newOutputs, channel->outputs, channel->size * sizeof(FILE**));
free(channel->outputs);
channel->outputs = newOutputs;
channel->size = newSize;
}
channel->outputs[channel->numOutputs] = file;
channel->numOutputs++;
sim_log_commit_change();
}
bool sim_log_remove_channel(char* output, FILE* file) {
sim_log_channel_t* channel;
int i;
channel = (sim_log_channel_t*)hashtable_search(channelTable, output);
if (channel == NULL) {
return FALSE;
}
// Note: if a FILE* has duplicates, this removes all of them
for (i = 0; i < channel->numOutputs; i++) {
FILE* f = channel->outputs[i];
if (file == f) {
memcpy(&channel->outputs[i], &channel->outputs[i + 1], (channel->numOutputs) - (i + 1));
channel->outputs[channel->numOutputs - 1] = NULL;
channel->numOutputs--;
}
}
return TRUE;
}
void sim_log_commit_change() {
int i;
for (i = 0; i < SIM_LOG_OUTPUT_COUNT; i++) {
if (outputs[i].files != NULL) {
outputs[i].num = 0;
free(outputs[i].files);
outputs[i].files = NULL;
}
}
}
void sim_log_debug(uint16_t id, char* string, const char* format, ...) {
va_list args;
int i;
if (outputs[id].files == NULL) {
fillInOutput(id, string);
}
for (i = 0; i < outputs[id].num; i++) {
FILE* file = outputs[id].files[i];
va_start(args, format);
fprintf(file, "DEBUG (%i): ", (int)sim_node());
vfprintf(file, format, args);
fflush(file);
}
}
void sim_log_error(uint16_t id, char* string, const char* format, ...) {
va_list args;
int i;
if (outputs[id].files == NULL) {
fillInOutput(id, string);
}
for (i = 0; i < outputs[id].num; i++) {
FILE* file = outputs[id].files[i];
va_start(args, format);
fprintf(file, "ERROR (%i): ", (int)sim_node());
vfprintf(file, format, args);
fflush(file);
}
}
void sim_log_debug_clear(uint16_t id, char* string, const char* format, ...) {
va_list args;
int i;
if (outputs[id].files == NULL) {
fillInOutput(id, string);
}
for (i = 0; i < outputs[id].num; i++) {
FILE* file = outputs[id].files[i];
va_start(args, format);
vfprintf(file, format, args);
fflush(file);
}
}
void sim_log_error_clear(uint16_t id, char* string, const char* format, ...) {
va_list args;
int i;
if (outputs[id].files == NULL) {
fillInOutput(id, string);
}
for (i = 0; i < outputs[id].num; i++) {
FILE* file = outputs[id].files[i];
va_start(args, format);
vfprintf(file, format, args);
fflush(file);
}
}
/* This is the sdbm algorithm, taken from
http://www.cs.yorku.ca/~oz/hash.html -pal */
static unsigned int sim_log_hash(void* key) {
char* str = (char*)key;
unsigned int hashVal = 0;
int hashChar;
while ((hashChar = *str++))
hashVal = hashChar + (hashVal << 6) + (hashVal << 16) - hashVal;
return hashVal;
}
static int sim_log_eq(void* key1, void* key2) {
return strcmp((char*)key1, (char*)key2) == 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -