?? history.c
字號:
/* * Write the history line. */ if(fprintf(fp, "%s\n", glh->buffer + node->start) < 0) { fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno)); (void) fclose(fp); return 1; }; };/* * Close the history file. */ if(fclose(fp) == EOF) { fprintf(stderr, "Error writing %s (%s).\n", filename, strerror(errno)); return 1; }; return 0;}/*....................................................................... * Restore previous history lines from a given file. * * Input: * glh GlHistory * The input-line history maintenance object. * filename const char * The name of the file to read from. * comment const char * The same comment string that was passed to * _glh_save_history() when this file was * written. * line char * A buffer into which lines can be read. * dim size_t The allocated dimension of line[]. * Output: * return int 0 - OK. * 1 - Error. */int _glh_load_history(GlHistory *glh, const char *filename, const char *comment, char *line, size_t dim){ FILE *fp; /* The output file */ size_t comment_len; /* The length of the comment string */ time_t timestamp; /* The timestamp of the history line */ unsigned group; /* The identifier of the history group to which */ /* the line belongs. */ int lineno; /* The line number being read *//* * Check the arguments. */ if(!glh || !filename || !comment || !line) { fprintf(stderr, "_glh_load_history: NULL argument(s).\n"); return 1; };/* * Measure the length of the comment string. */ comment_len = strlen(comment);/* * Clear the history list. */ _glh_clear_history(glh, 1);/* * Attempt to open the specified file. Don't treat it as an error * if the file doesn't exist. */ fp = fopen(filename, "r"); if(!fp) return 0;/* * Attempt to read each line and preceding peripheral info, and add these * to the history list. */ for(lineno=1; fgets(line, dim, fp) != NULL; lineno++) { char *lptr; /* A pointer into the input line *//* * Check that the line starts with the comment string. */ if(strncmp(line, comment, comment_len) != 0) { return _glh_cant_load_history(glh, filename, lineno, "Corrupt history parameter line", fp); };/* * Skip spaces and tabs after the comment. */ for(lptr=line+comment_len; *lptr && (*lptr==' ' || *lptr=='\t'); lptr++) ;/* * The next word must be a timestamp. */ if(_glh_decode_timestamp(lptr, &lptr, ×tamp)) { return _glh_cant_load_history(glh, filename, lineno, "Corrupt timestamp", fp); };/* * Skip spaces and tabs. */ while(*lptr==' ' || *lptr=='\t') lptr++;/* * The next word must be an unsigned integer group number. */ group = (int) strtoul(lptr, &lptr, 10); if(*lptr != ' ' && *lptr != '\n') { return _glh_cant_load_history(glh, filename, lineno, "Corrupt group id", fp); };/* * Skip spaces and tabs. */ while(*lptr==' ' || *lptr=='\t') lptr++;/* * There shouldn't be anything left on the line. */ if(*lptr != '\n') { return _glh_cant_load_history(glh, filename, lineno, "Corrupt parameter line", fp); };/* * Now read the history line itself. */ lineno++; if(fgets(line, dim, fp) == NULL) return _glh_cant_load_history(glh, filename, lineno, "Read error", fp);/* * Append the line to the history buffer. */ if(_glh_add_history(glh, line, 1)) { return _glh_cant_load_history(glh, filename, lineno, "Insufficient memory to record line", fp); };/* * Record the group and timestamp information along with the line. */ if(glh->list.tail) { glh->list.tail->timestamp = timestamp; glh->list.tail->group = group; }; };/* * Close the file. */ (void) fclose(fp); return 0;}/*....................................................................... * This is a private error return function of _glh_load_history(). */static int _glh_cant_load_history(GlHistory *glh, const char *filename, int lineno, const char *message, FILE *fp){ fprintf(stderr, "%s:%d: %s.\n", filename, lineno, message); (void) fclose(fp); return 1;}/*....................................................................... * Switch history groups. * * Input: * glh GlHistory * The input-line history maintenance object. * group unsigned The new group identifier. This will be recorded * with subsequent history lines, and subsequent * history searches will only return lines with * this group identifier. This allows multiple * separate history lists to exist within * a single GlHistory object. Note that the * default group identifier is 0. * Output: * return int 0 - OK. * 1 - Error. */int _glh_set_group(GlHistory *glh, unsigned group){/* * Check the arguments. */ if(!glh) { fprintf(stderr, "_glh_set_group: NULL argument(s).\n"); return 1; };/* * Is the group being changed? */ if(group != glh->group) {/* * Cancel any ongoing search. */ if(_glh_cancel_search(glh)) return 1;/* * Record the new group. */ glh->group = group; }; return 0;}/*....................................................................... * Query the current history group. * * Input: * glh GlHistory * The input-line history maintenance object. * Output: * return unsigned The group identifier. */int _glh_get_group(GlHistory *glh){ return glh ? glh->group : 0;}/*....................................................................... * Write a timestamp to a given stdio stream, in the format * yyyymmddhhmmss * * Input: * fp FILE * The stream to write to. * timestamp time_t The timestamp to be written. * Output: * return int 0 - OK. * 1 - Error. */static int _glh_write_timestamp(FILE *fp, time_t timestamp){ struct tm *t; /* THe broken-down calendar time *//* * Get the calendar components corresponding to the given timestamp. */ if(timestamp < 0 || (t = localtime(×tamp)) == NULL) { if(fprintf(fp, "?") < 0) return 1; return 0; };/* * Write the calendar time as yyyymmddhhmmss. */ if(fprintf(fp, "%04d%02d%02d%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec) < 0) return 1; return 0;}/*....................................................................... * Read a timestamp from a string. * * Input: * string char * The string to read from. * Input/Output: * endp char ** On output *endp will point to the next unprocessed * character in string[]. * timestamp time_t * The timestamp will be assigned to *t. * Output: * return int 0 - OK. * 1 - Error. */static int _glh_decode_timestamp(char *string, char **endp, time_t *timestamp){ unsigned year,month,day,hour,min,sec; /* Calendar time components */ struct tm t;/* * There are 14 characters in the date format yyyymmddhhmmss. */ enum {TSLEN=14}; char timestr[TSLEN+1]; /* The timestamp part of the string *//* * If the time wasn't available at the time that the line was recorded * it will have been written as "?". Check for this before trying * to read the timestamp. */ if(string[0] == '\?') { *endp = string+1; *timestamp = -1; return 0; };/* * The timestamp is expected to be written in the form yyyymmddhhmmss. */ if(strlen(string) < TSLEN) { *endp = string; return 1; };/* * Copy the timestamp out of the string. */ strncpy(timestr, string, TSLEN); timestr[TSLEN] = '\0';/* * Decode the timestamp. */ if(sscanf(timestr, "%4u%2u%2u%2u%2u%2u", &year, &month, &day, &hour, &min, &sec) != 6) { *endp = string; return 1; };/* * Advance the string pointer over the successfully read timestamp. */ *endp = string + TSLEN;/* * Copy the read values into a struct tm. */ t.tm_sec = sec; t.tm_min = min; t.tm_hour = hour; t.tm_mday = day; t.tm_wday = 0; t.tm_yday = 0; t.tm_mon = month - 1; t.tm_year = year - 1900; t.tm_isdst = -1;/* * Convert the contents of the struct tm to a time_t. */ *timestamp = mktime(&t); return 0;}/*....................................................................... * Display the contents of the history list. * * Input: * glh GlHistory * The input-line history maintenance object. * fp FILE * The stdio stream to write to. * fmt const char * A format string. This can contain arbitrary * characters, which are written verbatim, plus * any of the following format directives: * %D - The date, like 2001-11-20 * %T - The time of day, like 23:59:59 * %N - The sequential entry number of the * line in the history buffer. * %G - The history group number of the line. * %% - A literal % character. * %H - The history line. * all_groups int If true, display history lines from all * history groups. Otherwise only display * those of the current history group. * max_lines int If max_lines is < 0, all available lines * are displayed. Otherwise only the most * recent max_lines lines will be displayed. * Output: * return int 0 - OK. * 1 - Error. */int _glh_show_history(GlHistory *glh, FILE *fp, const char *fmt, int all_groups, int max_lines){ GlLineNode *node; /* The line being displayed */ GlLineNode *oldest; /* The oldest line to display */ enum {TSMAX=32}; /* The maximum length of the date and time string */ char buffer[TSMAX+1]; /* The buffer in which to write the date and time */ int idlen; /* The length of displayed ID strings */ unsigned grpmax; /* The maximum group number in the buffer */ int grplen; /* The number of characters needed to print grpmax *//* * Check the arguments. */ if(!glh || !fp || !fmt) { fprintf(stderr, "_glh_show_history: NULL argument(s).\n"); return 1; };/* * Is history enabled? */ if(!glh->enable || !glh->list.head) return 0;/* * Work out the length to display ID numbers, choosing the length of * the biggest number in the buffer. Smaller numbers will be padded * with leading zeroes if needed. */ sprintf(buffer, "%lu", (unsigned long) glh->list.tail->id); idlen = strlen(buffer);/* * Find the largest group number. */ grpmax = 0; for(node=glh->list.head; node; node=node->next) { if(node->group > grpmax) grpmax = node->group; };/* * Find out how many characters are needed to display the group number. */ sprintf(buffer, "%u", (unsigned) grpmax); grplen = strlen(buffer);/* * Find the node that follows the oldest line to be displayed. */ if(max_lines < 0) { oldest = glh->list.head; } else if(max_lines==0) { return 0; } else { for(oldest=glh->list.tail; oldest; oldest=oldest->prev) { if((all_groups || oldest->group == glh->group) && --max_lines <= 0) break; };/* * If the number of lines in the buffer doesn't exceed the specified * maximum, start from the oldest line in the buffer. */ if(!oldest) oldest = glh->list.head; };/* * List the history lines in increasing time order. */ for(node=oldest; node; node=node->next) {/* * Only display lines from the current history group, unless * told otherwise. */ if(all_groups || node->group == glh->group) { const char *fptr; /* A pointer into the format string */ struct tm *t = NULL; /* The broken time version of the timestamp *//* * Work out the calendar representation of the node timestamp. */ if(node->timestamp != (time_t) -1) t = localtime(&node->timestamp);/* * Parse the format string. */ fptr = fmt; while(*fptr) {/* * Search for the start of the next format directive or the end of the string. */ const char *start = fptr; while(*fptr && *fptr != '%') fptr++;/* * Display any literal characters that precede the located directive. */ if(fptr > start && fprintf(fp, "%.*s", (int) (fptr - start), start) < 0) return 1;/* * Did we hit a new directive before the end of the line? */ if(*fptr) {/* * Obey the directive. Ignore unknown directives. */ switch(*++fptr) { case 'D': /* Display the date */ if(t && strftime(buffer, TSMAX, "%Y-%m-%d", t) != 0 && fprintf(fp, "%s", buffer) < 0) return 1; break; case 'T': /* Display the time of day */ if(t && strftime(buffer, TSMAX, "%H:%M:%S", t) != 0 && fprintf(fp, "%s", buffer) < 0) return 1; break; case 'N': /* Display the sequential entry number */ if(fprintf(fp, "%*lu", idlen, (unsigned long) node->id) < 0) return 1; break; case 'G': if(fprintf(fp, "%*u", grplen, (unsigned) node->group) < 0) return 1; break; case 'H': /* Display the history line */ if(fprintf(fp, "%s", glh->buffer + node->start) < 0) return 1; break; case '%': /* A literal % symbol */ if(fputc('%', fp) == EOF) return 1; break; };/* * Skip the directive. */ if(*fptr) fptr++; }; }; }; }; return 0;}/*....................................................................... * Change the size of the history buffer. * * Input: * glh GlHistory * The input-line history maintenance object. * bufsize size_t The number of bytes in the history buffer, or 0 * to delete the buffer completely. * Output: * return int 0 - OK. * 1 - Insufficient memory (the previous buffer * will have been retained). No error message * will be displayed. */int _glh_resize_history(GlHistory *glh, size_t bufsize){ GlLineNode *node; /* A line location node in the list of lines */ GlLineNode *prev; /* The line location node preceding 'node' *//* * Check the arguments. */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -