/* Free the history list, including private readline data and take care of pointer aliases to history data. Resets rl_undo_list if it points to an UNDO_LIST * saved as some history entry's data member. This should not be called while editing is active. */ void rl_clear_history (void) { HIST_ENTRY **hlist, *hent; register int i; UNDO_LIST *ul, *saved_undo_list; saved_undo_list = rl_undo_list; hlist = history_list (); /* direct pointer, not copy */ for (i = 0; i < history_length; i++) { hent = hlist[i]; if (ul = (UNDO_LIST *)hent->data) { if (ul == saved_undo_list) saved_undo_list = 0; _rl_free_undo_list (ul); hent->data = 0; } _rl_free_history_entry (hent); } history_offset = history_length = 0; rl_undo_list = saved_undo_list; /* should be NULL */ }
// open a file, and read chunks of data until we reach EOF, // printing the data found to stdout int shell::c_history (std::vector <std::string> & args, props & p) { if ( ! args.empty () ) { carp ("format: history", p); return FAILURE; } #ifndef SAGA_HAVE_HISTORY_LIST carp ("Sorry, your libreadline does not support history listing", p); return FAILURE; #else // SAGA_HAVE_HISTORY_LIST HIST_ENTRY ** hist = history_list (); if ( hist ) { for ( int i = 0; hist[i]; i++ ) { p.out += (i + history_base); p.out += ":"; p.out += hist[i]->line; p.out += "\n"; } } return SUCCESS; #endif // SAGA_HAVE_HISTORY_LIST }
int sh_history(char **args) { HIST_ENTRY **list; list = history_list(); int max = 20; int j=0; int i = history_length; if(args[1] != NULL) { max = atoi(args[1]); if(i > max) { for(j = 0; j < max; j++){ printf("%s\n", list[i-j-1]->line); } } } else{ while(list[j] != NULL){ printf("history %d: %s\n", j, list[j]->line); j++; } } return 1; }
/* safely concatenates the history_list's entry strings and returns them via a pointer */ char *gnu_history_list() /* may look a bit messy, but it seems to work great ;D */ { HIST_ENTRY **hist_list = history_list(); char result_buf[BUFSIZ]; char *result_buf_ptr = result_buf; int idx; #if _HAVE_LIBBSD #else *result_buf = '\0'; #endif if (hist_list == NULL) return NULL; _CHK_READLINE_EGG_DEBUG("_CHK_READLINE_EGG_STRCPY: %s\n", _CHK_READLINE_EGG_STRCPY_FN_USED); _CHK_READLINE_EGG_DEBUG("_CHK_READLINE_EGG_STRCAT: %s\n", _CHK_READLINE_EGG_STRCAT_FN_USED); _CHK_READLINE_EGG_STRCPY(result_buf, hist_list[0]->line); _CHK_READLINE_EGG_STRCAT(result_buf, "\n"); for (idx = 1; idx < history_length; ++idx) { _CHK_READLINE_EGG_STRCAT(result_buf, hist_list[idx]->line); _CHK_READLINE_EGG_STRCAT(result_buf, "\n"); } return result_buf_ptr; }
/* Affiche l'historique des commande entrées dans le Shell lors de la session*/ int cmdHistory(char** c) { HIST_ENTRY **history = history_list(); for(int i = 0; history[i] != NULL; i++) { printf("%d : %s \n",i,history[i]->line); } return EXIT_SUCCESS; }
/* Prints command history, to be used before aborting */ static void _dump_history () { int i = 0; HIST_ENTRY** all_entries = history_list (); fputs (_("\nCommand History:\n"), stdout); while (all_entries[i]) { puts(all_entries[i++]->line); } }
static int cli_history (void *c_sys, int argc, cli_args_t *args) { HIST_ENTRY **hlist; int i; hlist = history_list(); if (hlist) for (i = 0; hlist[i]; i++) fprintf(rl_outstream, " %4d %s\n", i + 1, hlist[i]->line); return M_EXECUTE_OK; }
static int _c_c_save_history (void *c_sys, int argc, cli_args_t *args) { HIST_ENTRY **hlist; int i; FILE *fd = fopen("/etc/configure.conf", "a+"); hlist = history_list(); if (hlist) for (i = 0; hlist[i]; i++) fprintf(fd, "%s\n", hlist[i]->line); fclose(fd); return M_EXECUTE_OK; }
static void _history_list (void) { HIST_ENTRY **list; int i; if (!(list = history_list ())) return; for (i = 0; list[i]; i++) { out ("%p: %d: %s\n", i + history_base, list[i]->line); } return; }
// history // bool cmd_history(void){ HIST_ENTRY **histlist; int i = 0; histlist = history_list(); if(histlist) { for(i = 0; histlist[i]; i++) printf("%d: %s\n", i, histlist[i]->line); return TRUE; } printf("lsh: history: impossible de charger l'historique\n"); return FALSE; }
/** * @function rerun_cmd_n * * @abstract Runs the n-th command in history. * @discussion Given a command of the form !n [args], it runs the n-th * command in history. If n is positive, it runs as normal. * If it is negative, it counts its offset from the newest * command in history. If the absolute value of n is 0 or greater * than the total number of commands, nothing happens. If n is * non-integer, nothing happens. If nothing happens, a message is * printed to explain why. Any arguments included are appended to * the n-th command. * * @param command The command that starts with a '!' character and * contains which line to rerun. * @result Runs the n-th command. */ void rerun_cmd_n(Command* command) { // Get the history so we can rerun a line. HIST_ENTRY **cmd_history = history_list(); // Find the number of commands. int num_commands = 0; HIST_ENTRY **temp = cmd_history; while (*temp != NULL) { num_commands++; temp++; } // Figure out which line we are supposed to run from. This is the arg // after the '!', or the argument starting at the first index. char* argument = command->args->arg + 1; int iarg = atoi(argument); // Check that the argument is in range. if ((iarg == 0) || (iarg > num_commands) || (-1 * iarg > num_commands)) { printf("%s: event not found.\n", command->args->arg); return; } // If a negative number given, we rerun counting from the end. If positive // we rerun counting from the beginning. In any case, if the absolute // value is more than the number of commands we have or is 0, nothing can // be done. int run_offset = iarg - 1; if (iarg < 0) { // The offset should be subtracted from the end (remember iarg < 0). run_offset = num_commands + iarg - 1; } // Create a command string from this and any arguments given to !n. char next_cmd[MAX_COMMAND_SIZE]; strcpy(next_cmd, (*(cmd_history + run_offset))->line); // Put the rest of the arguments from !n onto the command string. argList *iter = command->args->nextArg; while (iter != NULL) { strcat(next_cmd, " "); strcat(next_cmd, iter->arg); iter = iter->nextArg; } // Run this new command. runCommand(next_cmd); return; }
/* Get the previous item out of our interactive history, making it the current line. If there is no previous history, just ding. */ int rl_get_previous_history (int count, int key) { HIST_ENTRY *old_temp, *temp; if (count < 0) return (rl_get_next_history (-count, key)); if (count == 0 || history_list () == 0) return 0; /* either not saved by rl_newline or at end of line, so set appropriately. */ if (_rl_history_saved_point == -1 && (rl_point || rl_end)) _rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point; /* If we don't have a line saved, then save this one. */ rl_maybe_save_line (); /* If the current line has changed, save the changes. */ rl_maybe_replace_line (); temp = old_temp = (HIST_ENTRY *)NULL; while (count) { temp = previous_history (); if (temp == 0) break; old_temp = temp; --count; } /* If there was a large argument, and we moved back to the start of the history, that is not an error. So use the last value found. */ if (!temp && old_temp) temp = old_temp; if (temp == 0) { rl_maybe_unsave_line (); rl_ding (); } else { rl_replace_from_history (temp, 0); _rl_history_set_point (); } return 0; }
/**************************************************************************** history ****************************************************************************/ void cmd_history(void) { #if defined(HAVE_LIBREADLINE) HIST_ENTRY **hlist; int i; hlist = history_list(); for (i = 0; hlist && hlist[i]; i++) { DEBUG(0, ("%d: %s\n", i, hlist[i]->line)); } #else DEBUG(0,("no history without readline support\n")); #endif }
static char* entire_history_as_one_string(void) { HIST_ENTRY **the_list = history_list(), **entryp; if (!the_list) /* i.e. if there is no history */ return mysavestring(""); char *big_string = mymalloc(history_total_bytes() + history_length + 1); char * stringp = big_string; for (entryp = the_list; *entryp; entryp++) { int length = strlen((*entryp)->line); strncpy(stringp, (*entryp)->line, length); /* copy line, without closing NULL byte; */ stringp +=length; *stringp++ = '\n'; } *stringp = '\0'; DPRINTF1(DEBUG_READLINE, "stringified %d bytes of history", (int) strlen(big_string)); return big_string; }
main () { char *temp, *prompt; int done; temp = (char *)NULL; prompt = "readline$ "; done = 0; while (!done) { temp = readline (prompt); /* Test for EOF. */ if (!temp) exit (1); /* If there is anything on the line, print it and remember it. */ if (*temp) { fprintf (stderr, "%s\r\n", temp); add_history (temp); } /* Check for `command' that we handle. */ if (strcmp (temp, "quit") == 0) done = 1; if (strcmp (temp, "list") == 0) { HIST_ENTRY **list; register int i; list = history_list (); if (list) { for (i = 0; list[i]; i++) fprintf (stderr, "%d: %s\r\n", i, list[i]->line); } } free (temp); } exit (0); }
/* Show history. */ debug_return_t dbg_cmd_show_command (const char *psz_args) { /* if (!psz_arg || *psz_arg) { ; } */ #ifdef HAVE_HISTORY_LIST HIST_ENTRY **hist_list = history_list(); unsigned int i; UNUSED_ARGUMENT(psz_args); if (!hist_list) return debug_readloop; for (i=0; hist_list[i]; i++) { dbg_msg("%5d %s", i, hist_list[i]->line); } #endif return debug_readloop; }
JNIEXPORT void JNICALL Java_org_gnu_readline_Readline_getHistoryImpl (JNIEnv *env, jclass theClass, jobject jcoll) { jclass cls; jmethodID mid; jstring jline; #if defined JavaReadline && !defined MAC_OS HIST_ENTRY **hist; #endif #if defined JavaEditline || defined MAC_OS HIST_ENTRY *histSingle; int pos; #endif cls = (*env)->GetObjectClass(env,jcoll); mid = (*env)->GetMethodID(env,cls,"add","(Ljava/lang/Object;)Z"); #if defined JavaReadline && !defined MAC_OS hist = history_list(); if (hist != NULL) { while (*hist != NULL) { jline = (*env)->NewStringUTF(env,(*hist)->line); (*env)->CallBooleanMethod(env,jcoll,mid,jline); hist++; } } #endif #if defined JavaEditline || defined MAC_OS for (pos = 0; pos < history_length; pos++) { histSingle = history_get(pos + 1); if (histSingle) { ucs2utf(histSingle->line); jline = (*env)->NewStringUTF(env,buffer); (*env)->CallBooleanMethod(env,jcoll,mid,jline); } } #endif }
/** * @function print_sh_history * * @abstract Handles history command. * @discussion If no arguments given, entire history is printed. If an * argument is given and it is >=0, then the last [argument] * commands are printed. Any other argument will result in an * error message. * * @param command The command being parsed. * @result Nothing is returned, but the history/error message is printed * to the terminal. */ void print_sh_history(Command* command) { // Get a NULL terminated array of commands where index 0 is the first // chronological entry. HIST_ENTRY **cmd_history = history_list(); // Start printing history from this one-indexed place. int history_start = 1; // First, check if there are any arguments. Only positive numbers are // acceptable. if (command->args->nextArg != NULL) { // There is an argument. Check if we can convert it to an integer. // atoi returning zero implies either failure or "0" argument. // Convert the argument to an integer (or get an error code). int nextArgVal = atoi(command->args->nextArg->arg); if ((nextArgVal == 0) && strcmp(command->args->nextArg->arg, "0")) { // Failure value and atoi was not given "0" printf("history: %s: Requires numeric argument.\n", \ command->args->nextArg->arg); // Not printing any history. return; } else if (nextArgVal < 0) { // We need a positive value so we know how many lines to print. printf("history: %s: invalid option\n", \ command->args->nextArg->arg); printf("history: usage: history [n]\n"); // Not printing any history. return; } else { // atoi was successful, even if it returned 0 in which case the // argument was the '0' character. Print the last n commands by // finding a pointer to the end of the list, decrementing it n // times, then printing until NULL // Find offset to end of list. HIST_ENTRY **last_cmd = cmd_history; while (*last_cmd != NULL) { history_start++; last_cmd++; } // Decrement n times. If there are fewer than n entries, start at // the first entry and show entire history. nextArgVal is n. // Otherwise, history_start should be 1 for the start. if (nextArgVal < history_start) history_start = history_start - nextArgVal; else history_start = 1; } } // Iterate over all of the history starting at the value we decided to // start at, either by default or from an argument. The start value is // one-indexed, so we must decrement it before altering the pointer start. cmd_history += history_start - 1; char out_line[MAX_COMMAND_SIZE]; FILE *out_file = NULL; if (command->output) out_file = fopen(command->output, "w"); while (*cmd_history != NULL) { snprintf(out_line, MAX_COMMAND_SIZE, "\t%d", history_start); strcat(out_line, "\t"); strcat(out_line, (*cmd_history)->line); strcat(out_line, "\n"); // Print the string to the appropriate location if (out_file == NULL) printf(out_line); else { fprintf(out_file, out_line); } // Increment everything cmd_history++; history_start++; } // If we opened a file, close it. if (out_file) fclose(out_file); return; }
main () { char line[1024], *t; int len, done = 0; line[0] = 0; using_history (); while (!done) { printf ("history$ "); fflush (stdout); t = fgets (line, sizeof (line) - 1, stdin); if (t && *t) { len = strlen (t); if (t[len - 1] == '\n') t[len - 1] = '\0'; } if (!t) strcpy (line, "quit"); if (line[0]) { char *expansion; int result; using_history (); result = history_expand (line, &expansion); if (result) fprintf (stderr, "%s\n", expansion); if (result < 0 || result == 2) { free (expansion); continue; } add_history (expansion); strncpy (line, expansion, sizeof (line) - 1); free (expansion); } if (strcmp (line, "quit") == 0) done = 1; else if (strcmp (line, "save") == 0) write_history ("history_file"); else if (strcmp (line, "read") == 0) read_history ("history_file"); else if (strcmp (line, "list") == 0) { register HIST_ENTRY **the_list; register int i; the_list = history_list (); if (the_list) for (i = 0; the_list[i]; i++) printf ("%d: %s\n", i + history_base, the_list[i]->line); } else if (strncmp (line, "delete", 6) == 0) { int which; if ((sscanf (line + 6, "%d", &which)) == 1) { HIST_ENTRY *entry = remove_history (which); if (!entry) fprintf (stderr, "No such entry %d\n", which); else { free (entry->line); free (entry); } } else { fprintf (stderr, "non-numeric arg given to `delete'\n"); } } } }
////=========================================================================================== // executer une commande simple void execute(char* elem[]) { sigset_t sigset; pid_t pid; if (!elem[0]) exit; if (!en_fond) { /* bloque child_signal jusqu'à ce que le père ait placé le pid du fils dans fg_pid sinon on risque de manquer la notification de fin du fils (race condition) */ sigemptyset(&sigset); sigaddset(&sigset,child_signal); sigprocmask(SIG_BLOCK,&sigset,NULL); } if (!elem[0]) return; /* ligne vide */ if (((strncmp(elem[0],"exit", 4))==0)||((strncmp(elem[0],"quit", 4))==0)) { Exit = 1; } // traite la commande interne : cd if ((strncmp(elem[0],"cd", 2))==0) { //strncmp returns 0 if equal if (strncmp(elem[1] , "~" ,1) == 0) dir = getenv("HOME"); else dir = elem[1]; if (chdir(dir) == 0) { dir = getcwd(NULL, 0); } else printf("MiniShell: directory change failed.\n"); return; } // traite la commande interne : history if ((strncmp(elem[0],"history", 7))==0) { //strncmp returns 0 if equal HIST_ENTRY **histlist; int i; histlist = history_list(); if (histlist) for (i = 0; histlist[i]; i++) printf ("%d: %s\n", i , histlist[i]->line); return; } // traite la commande interne : set if ((strncmp(elem[0],"set", 3))==0) { //strncmp returns 0 if equal char env[100]; sprintf(env ,"%s=%s",elem[1],elem[2]) ; if (putenv(env)!=0) printf("set %s as %s (%s): %s\n",elem[1],elems[2],env,strerror(errno)); printf("\n[%s]",env); return; } // traite la commande interne : help if ((strncmp(elem[0],"help", 4))==0) { //strncmp returns 0 if equal printf("MiniShell, version 0.2 (Tp systeme d'exploitation)\n"); printf("Ces commandes de shell sont définies de manière interne.Tapez « help » pour voir cette liste.\n"); printf("Utilisez « man » ou « info » pour en savoir plus sur les commandes qui\n"); printf("ne font pas partie de cette liste.\n"); printf("\n"); printf("history Affiche l'historique des commandes \n"); printf("set var val Definire des variables d'environnement\n"); printf("quit,exit Sortir du shell\n"); printf("cd dossier Changer le repertoire courant\n"); printf("help Afficher cette liste d'aide\n"); fflush(stdout); return; } if (!Exit) { pid = fork(); if (pid < 0) { printf("fork a échoué (%s)\n",strerror(errno)); return; } if (pid==0) { /* fils */ if (en_fond) { /* redirection de l'entrée standard sur /dev/null */ printf("redirection de l'entrée standard sur /dev/null \n %s [%d]",elem[0],getpid()); fflush(stdout); int devnull = open("/dev/null",O_RDONLY); if (devnull != -1) { close(0); dup2(devnull,0); } } else { /* réactivation de SIGINT & débloque SIGCLHD Contrôle+C */ struct sigaction sig; sig.sa_flags = 0; sig.sa_handler = SIG_DFL; sigemptyset(&sig.sa_mask); sigaction(SIGINT,&sig,NULL); sigprocmask(SIG_UNBLOCK,&sigset,NULL); } // gerer les motifs (les meta caracteres) if (use_glob) { glob_t globbuf; int i; int num=0; for (i = 1 ; elem[i] !=NULL ; i++) { if (strchr(elem[i] , '*')!=NULL) { num++; } } globbuf.gl_offs = num; printf("\nTraduction des meta-caracteres avec off = %d ,%d\n",globbuf.gl_offs,num); fflush(stdout); int cptm =0; for (i = 1 ; elem[i] !=NULL ; i++) if (strchr(elem[i] , '*')) { cptm++; if (cptm==1) glob(elem[i], GLOB_DOOFFS, NULL, &globbuf); else glob(elem[i], GLOB_DOOFFS|GLOB_APPEND, NULL, &globbuf); printf("%d...traduction de [%s] \n",cptm,elem[i]); } int cptg = 1; globbuf.gl_pathv[0] = elem[0]; for (i = 1 ; elem[i] !=NULL ; i++) if (strchr(elem[i] , '*')==NULL) { globbuf.gl_pathv[cptg] = elem[i]; cptg++; } execvp(elem[0], &globbuf.gl_pathv[0]); } else execvp(elem[0], /* programme à exécuter */ elem /* argv du programme à exécuter */ ); printf("impossible d'éxecuter \"%s\" (%s)\n",elem[0],strerror(errno)); exit(1); } else { if (!en_fond) { /* attent la fin du processus au premier plan */ fflush(stdout); printf("attent la fin du processus au premier plan \n"); fflush(stdout); waitpid(pid, NULL, 0); /*printf("pid %i\n",pid); fg_pid = pid; sigprocmask(SIG_UNBLOCK,&sigset,NULL); /* attente bloquante jusqu'à ce que child_signal signale que fg_pid s'est terminé */ while (fg_pid!=-1) { // pause(); fg_pid = pid; } } } } }
int run_internal(simple_command_t *s) { char *dir_str, *verb_str; verb_str = strdup(env_arg(s->verb)); if (strlen(verb_str) == 0) return 0; /* exit internal cmd */ if (!strcmp(verb_str, EXIT) || !strcmp(verb_str, QUIT)){ /* write the command history to disk */ write_history(NULL); /* exit gracefully */ exit(0); } /* cd internal cmd */ if (!strcmp(verb_str, CHDIR)) { if (s->params == NULL) { // if cd has no parameters, change to $HOME directory chdir(getenv("HOME")); return 0; } /* change dir */ dir_str = strdup(env_arg(s->params)); if (chdir(dir_str) != 0) { perror("Error when changing directory\n"); return 1; } } /* push directory onto the stack */ if(!strcmp(verb_str, PUSHD)) { if (s->params == NULL){ printf("Must insert directory name\n"); return 1; } /* insert the current directory onto the stack */ push(&ds, getcwd(NULL, 256)); if(chdir(env_arg(s->params)) != 0){ printf("Directory does not exist\n"); pop(&ds); } } /* show directories in the stack */ if(!strcmp(verb_str, DIRS)) { if (!print(&ds)){ printf("Stack is empty.\n"); return 1; } } /* pop directory off the stack */ if(!strcmp(verb_str, POPD)) { dir_str = pop(&ds); if(dir_str) { chdir(dir_str); }else{ printf("Stack is empty.\n"); return 1; } } /* echo [params ...] just echoes the parameters back to the user */ if(!strcmp(verb_str, ECHO)) { int argc, i; char **argv; get_args(s, &argc, &argv); for(i=1; i<=argc; i++) { printf("%s ", argv[i]); } printf("\n"); } /* prints working directory */ if(!strcmp(verb_str, PWD)) { printf("%s \n", getcwd(NULL, 256)); } /* prints the command history */ if(!strcmp(verb_str, HIST)){ /* * HIST_ENTRY is a structure defined by the History library which holds the line and timestamp of * a history entry. * define in readline/history.h */ HIST_ENTRY **history; int i; if (history = history_list()) for (i=0; history[i] != NULL; i++) printf ("%d %s\n", i, history[i]->line); } return 0; }
HistoryItems *get_prioritized_history() { using_history(); char *historyFile = get_history_file_name(); if(read_history(historyFile)!=0) { fprintf(stderr, "\nUnable to read history file from '%s'!\n",historyFile); exit(EXIT_FAILURE); } HISTORY_STATE *historyState=history_get_history_state(); if(historyState->length > 0) { HashSet rankmap; hashset_init(&rankmap); HashSet blacklist; int i; hashset_init(&blacklist); for(i=0; i<4; i++) { hashset_add(&blacklist, commandBlacklist[i]); } RadixSorter rs; radixsort_init(&rs, 100000); RankedHistoryItem *r; RadixItem *radixItem; HIST_ENTRY **historyList=history_list(); char **rawHistory=malloc(sizeof(char*) * historyState->length); int rawOffset=historyState->length-1; char *line; for(i=0; i<historyState->length; i++, rawOffset--) { line=historyList[i]->line; rawHistory[rawOffset]=line; if(hashset_contains(&blacklist, line)) { continue; } if((r=hashset_get(&rankmap, line))==NULL) { r=malloc(sizeof(RankedHistoryItem)); r->rank=HISTORY_RANKING_FUNCTION(0, i, strlen(line)); r->item=historyList[i]->line; hashset_put(&rankmap, line, r); radixItem=malloc(sizeof(RadixItem)); radixItem->key=r->rank; radixItem->data=r; radixItem->next=NULL; radixsort_add(&rs, radixItem); } else { radixItem=radix_cut(&rs, r->rank, r); assert(radixItem); if(radixItem) { r->rank=HISTORY_RANKING_FUNCTION(r->rank, i, strlen(line)); radixItem->key=r->rank; radixsort_add(&rs, radixItem); } } } DEBUG_RADIXSORT(); RadixItem **prioritizedRadix=radixsort_dump(&rs); prioritizedHistory=malloc(sizeof(HistoryItems)); prioritizedHistory->count=rs.size; prioritizedHistory->items=malloc(rs.size * sizeof(char*)); prioritizedHistory->raw=rawHistory; for(i=0; i<rs.size; i++) { if(prioritizedRadix[i]->data) { prioritizedHistory->items[i]=((RankedHistoryItem *)(prioritizedRadix[i]->data))->item; } free(prioritizedRadix[i]->data); free(prioritizedRadix[i]); } radixsort_destroy(&rs); return prioritizedHistory; } else { return NULL; } }
/* Workhorse function for writing history. Writes NELEMENT entries from the history list to FILENAME. OVERWRITE is non-zero if you wish to replace FILENAME with the entries. */ static int history_do_write ( const char *filename, int nelements, int overwrite ) { register int i; char *output; int file, mode, rv; mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC : O_WRONLY|O_APPEND; output = history_filename; file = output ? open (output, mode, 0600) : -1; rv = 0; if (file == -1) { rv = errno; return (rv); } if (nelements > history_length) nelements = history_length; /* Build a buffer of all the lines to write, and write them in one syscall. Suggested by Peter Ho ([email protected]). */ { HIST_ENTRY **the_history; /* local */ register int j; int buffer_size; char *buffer; the_history = history_list (); /* Calculate the total number of bytes to write. */ for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) { buffer_size += strlen (the_history[i]->line) + 1; } /* Allocate the buffer, and fill it. */ buffer = (char *)malloc (buffer_size); if (buffer == 0) { rv = errno; close (file); return rv; } for (j = 0, i = history_length - nelements; i < history_length; i++) { strcpy (buffer + j, the_history[i]->line); j += strlen (the_history[i]->line); buffer[j++] = '\n'; } if (write (file, buffer, buffer_size) < 0) rv = errno; FREE (buffer); } if (close (file) < 0 && rv == 0) rv = errno; return (rv); }