?? history.c
字號:
* dim size_t The allocated dimensions of the line buffer. * Output: * return char * The line requested, or NULL if no matching line * was found. */char *_glh_find_forwards(GlHistory *glh, char *line, size_t dim){ GlLineNode *node; /* The line location node being checked *//* * Check the arguments. */ if(!glh || !line) { fprintf(stderr, "_glh_find_forwards: NULL argument(s).\n"); return NULL; };/* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return NULL;/* * Check the line dimensions. */ if(dim < strlen(line) + 1) { fprintf(stderr, "_glh_find_forwards: 'dim' inconsistent with strlen(line) contents.\n"); return NULL; };/* * From where should we start the search? */ if(glh->recall) node = glh->recall->next; else return NULL;/* * If there is no search prefix, the prefix last set by glh_search_prefix() * doesn't exist in the history buffer. */ if(!glh->prefix) return NULL;/* * Search forwards through the list for the first match with the * prefix string. */ for( ; node && (node->group != glh->group || strncmp(glh->buffer + node->start, glh->prefix, glh->prefix_len) != 0); node = node->next) ;/* * Was a matching line found? */ if(node) {/* * Did we hit the line that was originally being edited when the * current history traversal started? */ if(node == glh->list.tail) return _glh_restore_line(glh, line, dim);/* * Copy the matching line into the provided line buffer. */ strncpy(line, glh->buffer + node->start, dim); line[dim-1] = '\0';/* * Record the starting point of the next search. */ glh->recall = node;/* * Return the matching line to the user. */ return line; };/* * No match was found. */ return NULL;}/*....................................................................... * If a search is in progress, cancel it. * * This involves discarding the line that was temporarily saved by * _glh_find_backwards() when the search was originally started, * and reseting the search iteration pointer to NULL. * * Input: * glh GlHistory * The input-line history maintenance object. * Output: * return int 0 - OK. * 1 - Error. */int _glh_cancel_search(GlHistory *glh){/* * Check the arguments. */ if(!glh) { fprintf(stderr, "_glh_cancel_search: NULL argument(s).\n"); return 1; };/* * If there wasn't a search in progress, do nothing. */ if(!glh->recall) return 0;/* * Delete the node of the preserved line. */ _glh_discard_node(glh, glh->list.tail);/* * Reset the search pointers. */ glh->recall = NULL; glh->prefix = ""; glh->prefix_len = 0; return 0;}/*....................................................................... * Set the prefix of subsequent history searches. * * Input: * glh GlHistory * The input-line history maintenance object. * line char * The command line who's prefix is to be used. * prefix_len int The length of the prefix. * Output: * return int 0 - OK. * 1 - Error. */int _glh_search_prefix(GlHistory *glh, const char *line, int prefix_len){ GlLineNode *node; /* The line location node being checked *//* * Check the arguments. */ if(!glh) { fprintf(stderr, "_glh_search_prefix: NULL argument(s).\n"); return 1; };/* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return 0;/* * Record a zero length search prefix? */ if(prefix_len <= 0) { glh->prefix_len = 0; glh->prefix = ""; return 0; };/* * Record the length of the new search prefix. */ glh->prefix_len = prefix_len;/* * If any history line starts with the specified prefix, record a * pointer to it for comparison in subsequent searches. If the prefix * doesn't match any of the lines, then simply record NULL to indicate * that there is no point in searching. Note that _glh_add_history() * clears this pointer by calling _glh_cancel_search(), so there is * no danger of it being used after the buffer has been modified. */ for(node = glh->list.tail ; node && (node->group != glh->group || strncmp(glh->buffer + node->start, line, prefix_len) != 0); node = node->prev) ;/* * If a matching line was found record it for use as the search * prefix. */ glh->prefix = node ? glh->buffer + node->start : NULL; return 0;}/*....................................................................... * Recall the oldest recorded line. * * Input: * glh GlHistory * The input-line history maintenance object. * line char * The input line buffer. On input this should contain * the current input line, and on output, its contents * will have been replaced with the oldest line. * dim size_t The allocated dimensions of the line buffer. * Output: * return char * A pointer to line[0], or NULL if not found. */char *_glh_oldest_line(GlHistory *glh, char *line, size_t dim){ GlLineNode *node; /* The line location node being checked */ int first; /* True if this is the start of a new search *//* * Check the arguments. */ if(!glh || !line) { fprintf(stderr, "_glh_oldest_line: NULL argument(s).\n"); return NULL; };/* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return NULL;/* * Check the line dimensions. */ if(dim < strlen(line) + 1) { fprintf(stderr, "_glh_oldest_line: 'dim' inconsistent with strlen(line) contents.\n"); return NULL; };/* * Is this the start of a new search? */ first = glh->recall==NULL;/* * If this is the first search backwards, save the current line * for potential recall later, and mark it as the last line * recalled. */ if(first) { if(_glh_add_history(glh, line, 1)) return NULL; glh->recall = glh->list.tail; };/* * Locate the oldest line that belongs to the current group. */ for(node=glh->list.head; node && node->group != glh->group; node = node->next) ;/* * No line found? */ if(!node) return NULL;/* * Record the above node as the starting point for subsequent * searches. */ glh->recall = node;/* * Copy the recalled line into the provided line buffer. */ strncpy(line, glh->buffer + node->start, dim); line[dim-1] = '\0'; return line;}/*....................................................................... * Recall the line that was being entered when the search started. * * Input: * glh GlHistory * The input-line history maintenance object. * line char * The input line buffer. On input this should contain * the current input line, and on output, its contents * will have been replaced with the line that was * being entered when the search was started. * dim size_t The allocated dimensions of the line buffer. * Output: * return char * A pointer to line[0], or NULL if not found. */char *_glh_current_line(GlHistory *glh, char *line, size_t dim){/* * Check the arguments. */ if(!glh || !line) { fprintf(stderr, "_glh_current_line: NULL argument(s).\n"); return NULL; };/* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return NULL;/* * Check the line dimensions. */ if(dim < strlen(line) + 1) { fprintf(stderr, "_glh_current_line: 'dim' inconsistent with strlen(line) contents.\n"); return NULL; };/* * Restore the original line. */ return _glh_restore_line(glh, line, dim);}/*....................................................................... * Remove the line that was originally being edited when the history * traversal was started, from its saved position in the history list, * and place it in the provided line buffer. * * Input: * glh GlHistory * The input-line history maintenance object. * line char * The input line buffer. On input this should contain * the current input line, and on output, its contents * will have been replaced with the saved line. * dim size_t The allocated dimensions of the line buffer. * Output: * return char * A pointer to line[0], or NULL if not found. */static char *_glh_restore_line(GlHistory *glh, char *line, size_t dim){ GlLineNode *tail; /* The tail node to be discarded *//* * If there wasn't a search in progress, do nothing. */ if(!glh->recall) return NULL;/* * Get the list node that is to be removed. */ tail = glh->list.tail;/* * If a pointer to the saved line is being used to record the * current search prefix, reestablish the search prefix, to * have it recorded by another history line if possible. */ if(glh->prefix == glh->buffer + tail->start) (void) _glh_search_prefix(glh, glh->buffer + tail->start, glh->prefix_len);/* * Copy the recalled line into the input-line buffer. */ strncpy(line, glh->buffer + tail->start, dim); line[dim-1] = '\0';/* * Discard the line-location node. */ _glh_discard_node(glh, tail);/* * Mark the search as ended. */ glh->recall = NULL; return line;}/*....................................................................... * Query the id of a history line offset by a given number of lines from * the one that is currently being recalled. If a recall session isn't * in progress, or the offset points outside the history list, 0 is * returned. * * Input: * glh GlHistory * The input-line history maintenance object. * offset int The line offset (0 for the current line, < 0 * for an older line, > 0 for a newer line. * Output: * return GlhLineID The identifier of the line that is currently * being recalled, or 0 if no recall session is * currently in progress. */GlhLineID _glh_line_id(GlHistory *glh, int offset){ GlLineNode *node; /* The line location node being checked *//* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return 0;/* * Search forward 'offset' lines to find the required line. */ if(offset >= 0) { for(node=glh->recall; node && offset != 0; node=node->next) { if(node->group == glh->group) offset--; }; } else { for(node=glh->recall; node && offset != 0; node=node->prev) { if(node->group == glh->group) offset++; }; }; return node ? node->id : 0;}/*....................................................................... * Recall a line by its history buffer ID. If the line is no longer * in the buffer, or the id is zero, NULL is returned. * * Input: * glh GlHistory * The input-line history maintenance object. * id GlhLineID The ID of the line to be returned. * line char * The input line buffer. On input this should contain * the current input line, and on output, its contents * will have been replaced with the saved line. * dim size_t The allocated dimensions of the line buffer. * Output: * return char * A pointer to line[0], or NULL if not found. */char *_glh_recall_line(GlHistory *glh, GlhLineID id, char *line, size_t dim){ GlLineNode *node; /* The line location node being checked *//* * Is history enabled? */ if(!glh->enable || !glh->buffer || glh->max_lines == 0) return NULL;/* * If we are starting a new recall session, save the current line * for potential recall later. */ if(!glh->recall && _glh_add_history(glh, line, 1)) return NULL;/* * Search for the specified line. */ node = _glh_find_id(glh, id);/* * Not found? */ if(!node || node->group != glh->group) return NULL;/* * Record the node of the matching line as the starting point * for subsequent searches. */ glh->recall = node;/* * Copy the recalled line into the provided line buffer. */ strncpy(line, glh->buffer + node->start, dim); line[dim-1] = '\0'; return line;}/*....................................................................... * Save the current history in a specified file. * * Input: * glh GlHistory * The input-line history maintenance object. * filename const char * The name of the new file to record the * history in. * comment const char * Extra information such as timestamps will * be recorded on a line started with this * string, the idea being that the file can * double as a command file. Specify "" if * you don't care. * max_lines int The maximum number of lines to save, or -1 * to save all of the lines in the history * list. * Output: * return int 0 - OK. * 1 - Error. */int _glh_save_history(GlHistory *glh, const char *filename, const char *comment, int max_lines){ FILE *fp; /* The output file */ GlLineNode *node; /* The line being saved */ GlLineNode *head; /* The head of the list of lines to be saved *//* * Check the arguments. */ if(!glh || !filename || !comment) { fprintf(stderr, "_glh_save_history: NULL argument(s).\n"); return 1; };/* * Attempt to open the specified file. */ fp = fopen(filename, "w"); if(!fp) { fprintf(stderr, "_glh_save_history: Can't open %s (%s).\n", filename, strerror(errno)); return 1; };/* * If a ceiling on the number of lines to save was specified, count * that number of lines backwards, to find the first line to be saved. */ head = NULL; if(max_lines >= 0) { for(head=glh->list.tail; head && --max_lines > 0; head=head->prev) ; }; if(!head) head = glh->list.head;/* * Write the contents of the history buffer to the history file, writing * associated data such as timestamps, to a line starting with the * specified comment string. */ for(node=head; node; node=node->next) {/* * Write peripheral information associated with the line, as a comment. */ if(fprintf(fp, "%s ", comment) < 0 || _glh_write_timestamp(fp, node->timestamp) || fprintf(fp, " %u\n", node->group) < 0) { fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno)); (void) fclose(fp); return 1; };
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -