📄 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 + -