?? history.c
字號:
if(!glh) return bufsize > 0;/* * If the new size doesn't differ from the existing size, do nothing. */ if(glh->buflen == bufsize) return 0;/* * Cancel any ongoing search. */ (void) _glh_cancel_search(glh);/* * Create a wholly new buffer? */ if(glh->buflen == 0) { glh->buffer = (char *) malloc(bufsize); if(!glh->buffer) return 1; glh->buflen = bufsize;/* * Delete an existing buffer? */ } else if(bufsize == 0) { _glh_clear_history(glh, 1); free(glh->buffer); glh->buffer = NULL; glh->buflen = 0;/* * To get here, we must be shrinking or expanding from one * finite size to another. */ } else {/* * If we are shrinking the size of the buffer, then we first need * to discard the oldest lines that won't fit in the new buffer. */ if(bufsize < glh->buflen) { size_t nbytes = 0; /* The number of bytes used in the new buffer */ GlLineNode *oldest; /* The oldest node to be kept *//* * Searching backwards from the youngest line, find the oldest * line for which there will be sufficient room in the new buffer. */ for(oldest = glh->list.tail; oldest && (nbytes += oldest->nchar) <= bufsize; oldest = oldest->prev) ;/* * We will have gone one node too far, unless we reached the oldest line * without exceeding the target length. */ if(oldest) { nbytes -= oldest->nchar; oldest = oldest->next; };/* * Discard the nodes that can't be retained. */ while(glh->list.head && glh->list.head != oldest) _glh_discard_node(glh, glh->list.head);/* * If we are increasing the size of the buffer, we need to reallocate * the buffer before shifting the lines into their new positions. */ } else { char *new_buffer = (char *) realloc(glh->buffer, bufsize); if(!new_buffer) return 1; glh->buffer = new_buffer; glh->buflen = bufsize; };/* * If there are any lines to be preserved, copy the block of lines * that precedes the end of the existing buffer to what will be * the end of the new buffer. */ if(glh->list.head) { int shift; /* The number of bytes to shift lines in the buffer *//* * Get the oldest line to be kept. */ GlLineNode *oldest = glh->list.head;/* * Count the number of characters that are used in the lines that * precede the end of the current buffer (ie. not including those * lines that have been wrapped to the start of the buffer). */ int n = 0; for(node=oldest,prev=oldest->prev; node && node->start >= oldest->start; prev=node, node=node->next) n += node->nchar;/* * Move these bytes to the end of the resized buffer. */ memmove(glh->buffer + bufsize - n, glh->buffer + oldest->start, n);/* * Adjust the buffer pointers to reflect the new locations of the moved * lines. */ shift = bufsize - n - oldest->start; for(node=prev; node && node->start >= oldest->start; node=node->prev) node->start += shift; };/* * Shrink the buffer? */ if(bufsize < glh->buflen) { char *new_buffer = (char *) realloc(glh->buffer, bufsize); if(new_buffer) glh->buffer = new_buffer; glh->buflen = bufsize; /* Mark it as shrunk, regardless of success */ }; }; return 0;}/*....................................................................... * Set an upper limit to the number of lines that can be recorded in the * history list, or remove a previously specified limit. * * Input: * glh GlHistory * The input-line history maintenance object. * max_lines int The maximum number of lines to allow, or -1 to * cancel a previous limit and allow as many lines * as will fit in the current history buffer size. */void _glh_limit_history(GlHistory *glh, int max_lines){ if(!glh) return;/* * Apply a new limit? */ if(max_lines >= 0 && max_lines != glh->max_lines) {/* * Count successively older lines until we reach the start of the * list, or until we have seen max_lines lines (at which point 'node' * will be line number max_lines+1). */ int nline = 0; GlLineNode *node; for(node=glh->list.tail; node && ++nline <= max_lines; node=node->prev) ;/* * Discard any lines that exceed the limit. */ if(node) { GlLineNode *oldest = node->next; /* The oldest line to be kept *//* * Delete nodes from the head of the list until we reach the node that * is to be kept. */ while(glh->list.head && glh->list.head != oldest) _glh_discard_node(glh, glh->list.head); }; };/* * Record the new limit. */ glh->max_lines = max_lines; return;}/*....................................................................... * Discard either all history, or the history associated with the current * history group. * * Input: * glh GlHistory * The input-line history maintenance object. * all_groups int If true, clear all of the history. If false, * clear only the stored lines associated with the * currently selected history group. */void _glh_clear_history(GlHistory *glh, int all_groups){/* * Check the arguments. */ if(!glh) return;/* * Cancel any ongoing search. */ (void) _glh_cancel_search(glh);/* * Delete all history lines regardless of group? */ if(all_groups) { _rst_FreeList(glh->list.node_mem); glh->list.head = glh->list.tail = NULL; glh->nline = 0; glh->id_node = NULL;/* * Just delete lines of the current group? */ } else { GlLineNode *node; /* The line node being checked */ GlLineNode *prev; /* The line node that precedes 'node' */ GlLineNode *next; /* The line node that follows 'node' *//* * Search out and delete the line nodes of the current group. */ for(node=glh->list.head; node; node=next) {/* * Keep a record of the following node before we delete the current * node. */ next = node->next;/* * Discard this node? */ if(node->group == glh->group) _glh_discard_node(glh, node); };/* * If there are any lines left, and we deleted any lines, there will * be gaps in the buffer. These need to be removed. */ if(glh->list.head) { int epos; /* The index of the last used element in the buffer *//* * Find the line nearest the end of the buffer. */ GlLineNode *enode; for(node=glh->list.head, prev=NULL; node && node->start >= glh->list.head->start; prev=node, node = node->next) ; enode = prev;/* * Move the end line to abutt the end of the buffer, and remove gaps * between the lines that precede it. */ epos = glh->buflen; for(node=enode; node; node=node->prev) { int shift = epos - (node->start + node->nchar); if(shift) { memmove(glh->buffer + node->start + shift, glh->buffer + node->start, node->nchar); node->start += shift; }; epos = node->start; };/* * Move the first line in the buffer to the start of the buffer, and * remove gaps between the lines that follow it. */ epos = 0; for(node=enode ? enode->next : NULL; node; node=node->next) { int shift = epos - node->start; if(shift) { memmove(glh->buffer + node->start + shift, glh->buffer + node->start, node->nchar); node->start += shift; }; epos = node->start + node->nchar; }; }; }; return;}/*....................................................................... * Temporarily enable or disable the history list. * * Input: * glh GlHistory * The input-line history maintenance object. * enable int If true, turn on the history mechanism. If * false, disable it. */void _glh_toggle_history(GlHistory *glh, int enable){ if(glh) glh->enable = enable;}/*....................................................................... * Remove a given line location node from the history list, and return * it to the freelist. * * Input: * glh GlHistory * The input-line history maintenance object. * node GlLineNode * The node to be removed. This must be currently * in the list who's head is glh->list.head, or * be NULL. */static void _glh_discard_node(GlHistory *glh, GlLineNode *node){ if(node) {/* * Make the node that precedes the node being removed point * to the one that follows it. */ if(node->prev) node->prev->next = node->next; else glh->list.head = node->next;/* * Make the node that follows the node being removed point * to the one that precedes it. */ if(node->next) node->next->prev = node->prev; else glh->list.tail = node->prev;/* * If we are deleting the node that is marked as the start point of the * last ID search, remove the cached starting point. */ if(node == glh->id_node) glh->id_node = NULL;/* * Return the node to the free list. */ node = (GlLineNode *) _del_FreeListNode(glh->list.node_mem, node);/* * Decrement the count of the number of lines in the buffer. */ glh->nline--; };}/*....................................................................... * Lookup the details of a given history line, given its id. * * Input: * glh GlHistory * The input-line history maintenance object. * id GlLineID The sequential number of the line. * Input/Output: * line const char ** A pointer to the history line will be assigned * to *line. * group unsigned * The group membership of the line will be assigned * to *group. * timestamp time_t * The timestamp of the line will be assigned to * *timestamp. * Output: * return int 0 - The requested line wasn't found. * 1 - The line was found. */int _glh_lookup_history(GlHistory *glh, GlhLineID id, const char **line, unsigned *group, time_t *timestamp){ GlLineNode *node; /* The located line location node *//* * Check the arguments. */ if(!glh) return 0;/* * Search for the line that has the specified ID. */ node = _glh_find_id(glh, (GlhLineID) id);/* * Not found? */ if(!node) return 0;/* * Return the details of the line. */ if(line) *line = glh->buffer + node->start; if(group) *group = node->group; if(timestamp) *timestamp = node->timestamp; return 1;}/*....................................................................... * Lookup a node in the history list by its ID. * * Input: * glh GlHistory * The input-line history maintenance object. * id GlhLineID The ID of the line to be returned. * Output: * return GlLIneNode * The located node, or NULL if not found. */static GlLineNode *_glh_find_id(GlHistory *glh, GlhLineID id){ GlLineNode *node; /* The node being checked *//* * Is history enabled? */ if(!glh->enable || !glh->list.head) return NULL;/* * If possible, start at the end point of the last ID search. * Otherwise start from the head of the list. */ node = glh->id_node; if(!node) node = glh->list.head;/* * Search forwards from 'node'? */ if(node->id < id) { while(node && node->id != id) node = node->next; glh->id_node = node ? node : glh->list.tail;/* * Search backwards from 'node'? */ } else { while(node && node->id != id) node = node->prev; glh->id_node = node ? node : glh->list.head; };/* * Return the located node (this will be NULL if the ID wasn't found). */ return node;}/*....................................................................... * Query the state of the history list. Note that any of the input/output * pointers can be specified as NULL. * * Input: * glh GlHistory * The input-line history maintenance object. * Input/Output: * enabled int * If history is enabled, *enabled will be * set to 1. Otherwise it will be assigned 0. * group unsigned * The current history group ID will be assigned * to *group. * max_lines int * The currently requested limit on the number * of history lines in the list, or -1 if * unlimited. */void _glh_state_of_history(GlHistory *glh, int *enabled, unsigned *group, int *max_lines){ if(glh) { if(enabled) *enabled = glh->enable; if(group) *group = glh->group; if(max_lines) *max_lines = glh->max_lines; };}/*....................................................................... * Get the range of lines in the history buffer. * * Input: * glh GlHistory * The input-line history maintenance object. * Input/Output: * oldest unsigned long * The sequential entry number of the oldest * line in the history list will be assigned * to *oldest, unless there are no lines, in * which case 0 will be assigned. * newest unsigned long * The sequential entry number of the newest * line in the history list will be assigned * to *newest, unless there are no lines, in * which case 0 will be assigned. * nlines int * The number of lines currently in the history * list. */void _glh_range_of_history(GlHistory *glh, unsigned long *oldest, unsigned long *newest, int *nlines){ if(glh) { if(oldest) *oldest = glh->list.head ? glh->list.head->id : 0; if(newest) *newest = glh->list.tail ? glh->list.tail->id : 0; if(nlines) *nlines = glh->nline; };}/*....................................................................... * Return the size of the history buffer and the amount of the * buffer that is currently in use. * * Input: * glh GlHistory * The input-line history maintenance object. * Input/Output: * buff_size size_t * The size of the history buffer (bytes). * buff_used size_t * The amount of the history buffer that * is currently occupied (bytes). */void _glh_size_of_history(GlHistory *glh, size_t *buff_size, size_t *buff_used){ if(glh) { if(buff_size) *buff_size = glh->buflen;/* * Determine the amount of buffer space that is currently occupied. */ if(buff_used) { size_t used = 0; GlLineNode *node; for(node=glh->list.head; node; node=node->next) used += node->nchar; *buff_used = used; }; };}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -