static void jtag_readline_loop( chain_t *chain, const char *prompt ) { #ifdef HAVE_LIBREADLINE char *line = NULL; #ifdef HAVE_READLINE_HISTORY HIST_ENTRY *hptr; #endif /* Iterate */ while (jtag_readline_multiple_commands_support( chain, line )) { free( line ); /* Read a line from the terminal */ line = readline( prompt ); /* We got EOF, bail */ if (!line) { line = strdup( "quit\n" ); puts( "quit" ); if (!line) return; } #ifdef HAVE_READLINE_HISTORY /* Check if we actually got something , Don't add duplicate lines*/ if (strlen( line )) { if (history_length == 0) add_history( line ); else { hptr = history_get( history_length ); /* Apple leopard libreadline emulation screws up indexing, try the other one */ if (hptr == NULL) hptr = history_get( history_length-1 ); if (hptr != NULL) { if (strcmp( line, hptr->line )) add_history( line ); } else add_history( line ); } } #endif } free( line ); #else char line[1024]; line[0] = 0; do { if (!jtag_readline_multiple_commands_support( chain, line )) break; printf("%s", prompt); fflush(stdout); } while(fgets(line, 1023, stdin)); #endif }
static PyObject * get_history_item(PyObject *self, PyObject *args) { int idx = 0; HIST_ENTRY *hist_ent; if (!PyArg_ParseTuple(args, "i:index", &idx)) return NULL; #ifdef __APPLE__ if (using_libedit_emulation) { /* Libedit emulation uses 0-based indexes, * the real one uses 1-based indexes, * adjust the index to ensure that Python * code doesn't have to worry about the * difference. */ int length = _py_get_history_length(); idx --; /* * Apple's readline emulation crashes when * the index is out of range, therefore * test for that and fail gracefully. */ if (idx < 0 || idx >= length) { Py_RETURN_NONE; } } #endif /* __APPLE__ */ if ((hist_ent = history_get(idx))) return PyUnicode_FromString(hist_ent->line); else { Py_RETURN_NONE; } }
static PyObject * get_history_item(PyObject *self, PyObject *args) { int idx = 0; HIST_ENTRY *hist_ent; if (!PyArg_ParseTuple(args, "i:get_history_item", &idx)) return NULL; #ifdef __APPLE__ if (using_libedit_emulation) { /* Older versions of libedit's readline emulation * use 0-based indexes, while readline and newer * versions of libedit use 1-based indexes. */ int length = _py_get_history_length(); idx = idx - 1 + libedit_history_start; /* * Apple's readline emulation crashes when * the index is out of range, therefore * test for that and fail gracefully. */ if (idx < (0 + libedit_history_start) || idx >= (length + libedit_history_start)) { Py_RETURN_NONE; } } #endif /* __APPLE__ */ if ((hist_ent = history_get(idx))) return decode(hist_ent->line); else { Py_RETURN_NONE; } }
// Called from scheme to get user input char *gnu_readline_readline(char *prompt, char *prompt2) { char *empty_prompt; int prompt_len; HIST_ENTRY *entry; if (gnu_readline_buf != NULL) { free(gnu_readline_buf); gnu_readline_buf = NULL; } if (!(balance.paren || balance.brace || balance.quote)) // this may seem confusing, but `0 || 0` == 0. gnu_readline_buf = readline(prompt); else gnu_readline_buf = readline(prompt2); if (gnu_readline_buf != NULL && *gnu_readline_buf != '\0') { entry = history_get(history_base + history_length - 1); if (entry == NULL || strcmp(entry->line, gnu_readline_buf) != 0) { add_history(gnu_readline_buf); ++gnu_history_newlines; } } if (strlen(rl_line_buffer) > 0) { check_balance('(') == -1 && (balance.paren = 0); check_balance('[') == -1 && (balance.brace = 0); check_balance('"') == -1 && (balance.quote = 0); } return(gnu_readline_buf); }
static void add_history_dedup(char *cmd) { /* Add history line if it differs from the last one */ HIST_ENTRY *he = history_get(history_length); if (!he || strcmp(he->line, cmd)) add_history(cmd); }
enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats) { history_get(jb); *stats = jb->info; return JB_OK; }
int jb_getinfo(jitterbuf *jb, cw_jb_info *stats) { history_get(jb); *stats = jb->info; return JB_OK; }
void append_to_history() { char *hf = tilde_expand(HISTORY_FILE); #ifdef USE_READLINE append_history(1, hf); #else #if defined(RL_READLINE_VERSION) HIST_ENTRY *he = history_get(history_base+history_length-1); #else // libedit-2 segfaults if we add history_base HIST_ENTRY *he = history_get(history_length-1); #endif FILE *fp = fopen(hf, "a"); if (fp) { fprintf(fp, "%s\n", he->line); fclose(fp); } #endif free(hf); }
JNIEXPORT jstring JNICALL Java_org_gnu_readline_Readline_getHistoryLineImpl (JNIEnv *env, jclass theClass, jint i) { HIST_ENTRY *hist = NULL; if ((hist = history_get ((int) (i + 1))) != NULL) { ucs2utf(hist->line); return (*env)->NewStringUTF(env,buffer); } return NULL; }
void write_history_list(const int num, const char *const filename, const char *mode) { const HIST_ENTRY *list_entry; FILE *out = stdout; int is_pipe = 0; int is_file = 0; int is_quiet = 0; int i, istart; if (filename && filename[0] ) { /* good filename given and not quiet */ #ifdef PIPES if (filename[0]=='|') { restrict_popen(); out = popen(filename+1, "w"); is_pipe = 1; } else { #endif if (! (out = fopen(filename, mode) ) ) { /* Fall back to 'stdout' */ int_warn(NO_CARET, "Cannot open file to save history, using standard output.\n"); out = stdout; } else is_file = 1; #ifdef PIPES } #endif } else if (filename && !filename[0]) is_quiet = 1; /* Determine starting point and output in loop. * For some reason the readline functions append_history() * and write_history() do not work they way I thought they did... */ if (num > 0) { istart = history_length - num; if (istart <= 0 || istart > history_length) istart = 1; } else istart = 1; for (i = istart; (list_entry = history_get(i)); i++) { /* don't add line numbers when writing to file to make file loadable */ if (is_file) fprintf(out, "%s\n", list_entry->line); else { if (!is_quiet) fprintf(out, "%5i", i + history_base - 1); fprintf(out, " %s\n", list_entry->line); } } /* close if something was opened */ #ifdef PIPES if (is_pipe) pclose(out); #endif if (is_file) fclose(out); }
char *gnu_history_get(int ind, int time) { HIST_ENTRY *entry = NULL; entry = history_get(ind); if (entry == NULL) return NULL; return (time == 0 ? entry->line : entry->timestamp); }
static void init_history(void) { using_history(); char *home = getenv("HOME"); if (!home) return; if (disable_history) return; asprintf(&history_file, "%s/.julia_history", home); struct stat stat_info; if (!stat(history_file, &stat_info)) { read_history(history_file); for (;;) { HIST_ENTRY *entry = history_get(history_base); if (entry && isspace(entry->line[0])) free_history_entry(history_rem(history_base)); else break; } int i, j, k; for (i=1 ;; i++) { HIST_ENTRY *first = history_get(i); if (!first) break; int length = strlen(first->line)+1; for (j = i+1 ;; j++) { HIST_ENTRY *child = history_get(j); if (!child || !isspace(child->line[0])) break; length += strlen(child->line)+1; } if (j == i+1) continue; first->line = (char*)realloc(first->line, length); char *p = strchr(first->line, '\0'); for (k = i+1; k < j; k++) { *p = '\n'; p = stpcpy(p+1, history_get(i+1)->line); free_history_entry(history_rem(i+1)); } } } else if (errno == ENOENT) { write_history(history_file); } else { ios_printf(ios_stderr, "history file error: %s\n", strerror(errno)); exit(1); } }
static void mcview_continue_search_cmd (mcview_t * view) { if (view->last_search_string != NULL) mcview_search (view, FALSE); else { /* find last search string in history */ GList *history; history = history_get (MC_HISTORY_SHARED_SEARCH); if (history != NULL && history->data != NULL) { view->last_search_string = (gchar *) g_strdup (history->data); history = g_list_first (history); g_list_free_full (history, g_free); #ifdef HAVE_CHARSET view->search = mc_search_new (view->last_search_string, -1, cp_source); #else view->search = mc_search_new (view->last_search_string, -1, NULL); #endif view->search_nroff_seq = mcview_nroff_seq_new (view); if (view->search == NULL) { /* if not... then ask for an expression */ MC_PTR_FREE (view->last_search_string); mcview_search (view, TRUE); } else { view->search->search_type = mcview_search_options.type; #ifdef HAVE_CHARSET view->search->is_all_charsets = mcview_search_options.all_codepages; #endif view->search->is_case_sensitive = mcview_search_options.case_sens; view->search->whole_words = mcview_search_options.whole_words; view->search->search_fn = mcview_search_cmd_callback; view->search->update_fn = mcview_search_update_cmd_callback; mcview_search (view, FALSE); } } else { /* if not... then ask for an expression */ MC_PTR_FREE (view->last_search_string); mcview_search (view, TRUE); } } }
/** * Add non-repeated command to readline history * and free the given string */ static void DebugUI_FreeCommand(char *input) { if (input && *input) { HIST_ENTRY *hist = history_get(history_length); /* don't store duplicate successive entries */ if (!hist || !hist->line || strcmp(hist->line, input) != 0) { add_history(input); } free(input); } }
static void add_history_permanent(char *input) { if (!input || !*input) return; if (last_hist_is_temp) { history_rem(history_length); last_hist_is_temp = 0; } last_hist_offset = -1; HIST_ENTRY *entry = history_get(history_length); if (entry && !strcmp(input, entry->line)) return; last_hist_offset = where_history(); add_history(input); if (history_file) append_history(1, history_file); }
void reverse_search(int sig) { if(sig == SIGQUIT){ char *line; printf("Enter command to reverse search:"); line = readline(""); int index = history_search(line, 0); printf("%d\n", index); char* guess_line; HIST_ENTRY* hist = history_get(index); guess_line = hist->line; printf("%s\n", guess_line); } }
static PyObject * get_history_item(PyObject *self, PyObject *args) { int idx = 0; HIST_ENTRY *hist_ent; if (!PyArg_ParseTuple(args, "i:index", &idx)) return NULL; if ((hist_ent = history_get(idx))) return PyString_FromString(hist_ent->line); else { Py_RETURN_NONE; } }
static void cli_complete(char *line) { const HIST_ENTRY *hist; const char *c; LIST_HEAD(msgs); int len; char *s; if (line == NULL) { printf("\n"); cli_exit(); exit(0); } line = cli_append_multiline(line); if (line == NULL) return; for (c = line; *c != '\0'; c++) if (!isspace(*c)) break; if (*c == '\0') return; if (!strcmp(line, "quit")) { cli_exit(); exit(0); } /* avoid duplicate history entries */ hist = history_get(history_length); if (hist == NULL || strcmp(hist->line, line)) add_history(line); len = strlen(line); s = xmalloc(len + 2); snprintf(s, len + 2, "%s\n", line); xfree(line); line = s; parser_init(state, &msgs); scanner_push_buffer(scanner, &indesc_cli, line); nft_run(scanner, state, &msgs); erec_print_list(stdout, &msgs); xfree(line); cache_release(); iface_cache_release(); }
// Displays history. void exec_hist(char **tokens) { int length = history_length; int i; if (tokens[1]) { if (tokens[2]) { fprintf(stderr, "history failed: only one argument accepted.\n"); return; } length = atoi(tokens[1]); } for (i = length - 1; i >= 0; i--) { printf("%6d %s\n", history_length - i, history_get( history_length - i - 1)->line); } return; }
long jb_next(jitterbuf *jb) { if (jb->info.silence_begin_ts) { long next = queue_next(jb); if (next >= 0) { history_get(jb); /* shrink during silence */ if (jb->info.target - jb->info.current < -JB_TARGET_EXTRA) return jb->info.last_adjustment + 10; return next + jb->info.target; } else return JB_LONGMAX; } else { return jb->info.next_voice_ts; } }
long jb_next(jitterbuf *jb) { if (jb->info.silence_begin_ts) { if (jb->frames) { long next = queue_next(jb); history_get(jb); /* shrink during silence */ if (jb->info.target - jb->info.current < -jb->info.conf.target_extra) return jb->info.last_adjustment + 10; return next + jb->info.target; } else return JB_LONGMAX; } else { return jb->info.next_voice_ts; } }
readline_constructor_impl::impl::impl( readline* parent, boost::asio::io_service& io_service, boost::function<void(std::string const&, readline&)> const& command_handler, boost::function<void(readline&)> const& eof_handler, std::string const& prompt, boost::filesystem::path const& history_file, boost::function<bool(std::string const&)> const& history_filter ) : parent_(parent), io_service_(io_service), command_handler_(command_handler), eof_handler_(eof_handler), prompt_(prompt), history_file_(history_file), history_filter_(history_filter), stdin_reader_(io_service, 0), // Bind to stdin redisplay_timer_(io_service) { if (current_readline) { throw std::logic_error("Can't create multiple relasio::readline objects"); } current_readline = this; if (!history_file_.empty() && boost::filesystem::exists(history_file_)) { if (!boost::filesystem::is_directory(history_file_)) { if (0 == read_history(history_file_.c_str())) { if (0 == history_set_pos(history_length)) { throw relasio_error("error setting history position\n"); } if (history_length > 0) { // Set up last_line_ HIST_ENTRY* last = history_get(history_length); if (last) last_line_ = last->line; } } else { throw relasio_error("error reading history\n"); } } } rl_callback_handler_install( prompt_.c_str(), relasio_line_callback_handler ); wait_for_chars(); }
char *x_readline(const char *prompt) { static char buffer[1024]; char *cp; int count; if (!readline_init) { rl_readline_name = "GS+"; rl_attempted_completion_function = rl_acf; using_history(); stifle_history(HISTORY_SIZE); readline_init = 1; } cp = readline(prompt); if (!cp) { if (prompt) fputc('\n', stdout); return NULL; } count = strlen(cp); if (count > sizeof(buffer) - 1) { free(cp); return ""; } memcpy(buffer, cp, count); cleanup_buffer(buffer, count); free(cp); /* append to history, but only if unique from prev. entry */ if (*buffer) { HIST_ENTRY *h = history_get(history_length); if (h == NULL || strcmp(buffer, h->line)) add_history(buffer); } return buffer; }
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 }
/* format line and add it to history list, avoiding duplicates if necessary */ static void my_add_history(char *line) { int lookback, count, here; char *new_entry, *filtered_line; filtered_line = pass_through_filter(TAG_HISTORY, line); switch (history_duplicate_avoidance_policy) { case KEEP_ALL_DOUBLES: lookback = 0; break; case ELIMINATE_SUCCESIVE_DOUBLES: lookback = 1; break; case ELIMINATE_ALL_DOUBLES: lookback = history_length; break; } new_entry = filtered_line; lookback = min(history_length, lookback); for (count = 0, here = history_length + history_base - 1; count < lookback ; count++, here--) { /* DPRINTF3(DEBUG_READLINE, "strcmping <%s> and <%s> (count = %d)", line, history_get(here)->line ,count); */ if (strncmp(new_entry, history_get(here) -> line, 10000) == 0) { HIST_ENTRY *entry = remove_history (here - history_base); /* according to the history library doc this should be remove_history(here) @@@?*/ DPRINTF2(DEBUG_READLINE, "removing duplicate entry #%d (%s)", here, entry->line); free_foreign(entry->line); free_foreign(entry); } } add_history(new_entry); free(new_entry); }
/* format line and add it to history list, avoiding duplicates if necessary */ static void my_add_history(char *line) { int lookback, count, here; char *new_entry, *filtered_line; filtered_line = pass_through_filter(TAG_HISTORY, line); switch (history_duplicate_avoidance_policy) { case KEEP_ALL_DOUBLES: lookback = 0; break; case ELIMINATE_SUCCESIVE_DOUBLES: lookback = 1; break; case ELIMINATE_ALL_DOUBLES: lookback = history_length; break; } new_entry = filtered_line; lookback = min(history_length, lookback); for (count = 0, here = history_length - 1; count < lookback ; count++, here--) { DPRINTF4(DEBUG_READLINE, "strcmping <%s> and <%s> (count = %d, here = %d)", line, history_get(history_base + here)->line ,count, here); if (strncmp(new_entry, history_get(history_base + here) -> line, 10000) == 0) { /* history_get uses the logical offset history_base .. */ HIST_ENTRY *entry = remove_history (here); /* .. but remove_history doesn't! */ DPRINTF2(DEBUG_READLINE, "removing duplicate entry #%d (%s)", here, entry->line); free_foreign(entry->line); free_foreign(entry); } } add_history(new_entry); free(new_entry); }
static void init_history(void) { using_history(); if (disable_history) return; struct stat stat_info; if (!stat(".julia_history", &stat_info)) { // history file in current dir history_file = ".julia_history"; } else { char *histenv = getenv("JULIA_HISTORY"); if (histenv) { history_file = histenv; } else { #ifndef __WIN32__ char *home = getenv("HOME"); if (!home) return; asprintf(&history_file, "%s/.julia_history", home); #else char *home = getenv("AppData"); if (!home) return; asprintf(&history_file, "%s/julia/history", home); #endif } } if (!stat(history_file, &stat_info)) { read_history(history_file); for (;;) { HIST_ENTRY *entry = history_get(history_base); if (entry && isspace(entry->line[0])) free_history_entry(history_rem(history_base)); else break; } int i, j, k; for (i=1 ;; i++) { HIST_ENTRY *first = history_get(i); if (!first) break; int length = strlen(first->line)+1; for (j = i+1 ;; j++) { HIST_ENTRY *child = history_get(j); if (!child || !isspace(child->line[0])) break; length += strlen(child->line)+1; } if (j == i+1) continue; first->line = (char*)realloc(first->line, length); char *p = strchr(first->line, '\0'); for (k = i+1; k < j; k++) { *p = '\n'; #ifndef __WIN32__ p = stpcpy(p+1, history_get(i+1)->line); #else p = strcpy(p+1, history_get(i+1)->line); #endif free_history_entry(history_rem(i+1)); } } } else if (errno == ENOENT) { write_history(history_file); } else { jl_printf(jl_uv_stderr, "history file error: %s\n", strerror(errno)); exit(1); } }
static void setup_readline(readlinestate *mod_state) { #ifdef SAVE_LOCALE char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); if (!saved_locale) Py_FatalError("not enough memory to save locale"); #endif #ifdef __APPLE__ /* the libedit readline emulation resets key bindings etc * when calling rl_initialize. So call it upfront */ if (using_libedit_emulation) rl_initialize(); /* Detect if libedit's readline emulation uses 0-based * indexing or 1-based indexing. */ add_history("1"); if (history_get(1) == NULL) { libedit_history_start = 0; } else { libedit_history_start = 1; } clear_history(); #endif /* __APPLE__ */ using_history(); rl_readline_name = "python"; /* Force rebind of TAB to insert-tab */ rl_bind_key('\t', rl_insert); /* Bind both ESC-TAB and ESC-ESC to the completion function */ rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); #ifdef HAVE_RL_RESIZE_TERMINAL /* Set up signal handler for window resize */ sigwinch_ohandler = PyOS_setsig(SIGWINCH, readline_sigwinch_handler); #endif /* Set our hook functions */ rl_startup_hook = on_startup_hook; #ifdef HAVE_RL_PRE_INPUT_HOOK rl_pre_input_hook = on_pre_input_hook; #endif /* Set our completion function */ rl_attempted_completion_function = flex_complete; /* Set Python word break characters */ completer_word_break_characters = rl_completer_word_break_characters = strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); /* All nonalphanums except '.' */ mod_state->begidx = PyLong_FromLong(0L); mod_state->endidx = PyLong_FromLong(0L); #ifdef __APPLE__ if (!using_libedit_emulation) #endif { if (!isatty(STDOUT_FILENO)) { /* Issue #19884: stdout is not a terminal. Disable meta modifier keys to not write the ANSI sequence "\033[1034h" into stdout. On terminals supporting 8 bit characters like TERM=xterm-256color (which is now the default Fedora since Fedora 18), the meta key is used to enable support of 8 bit characters (ANSI sequence "\033[1034h"). With libedit, this call makes readline() crash. */ rl_variable_bind ("enable-meta-key", "off"); } } /* Initialize (allows .inputrc to override) * * XXX: A bug in the readline-2.2 library causes a memory leak * inside this function. Nothing we can do about it. */ #ifdef __APPLE__ if (using_libedit_emulation) rl_read_init_file(NULL); else #endif /* __APPLE__ */ rl_initialize(); RESTORE_LOCALE(saved_locale) }
char * getConsoleInput(Client c, const char *prompt, int linemode, int exit_on_error) { char *line = NULL; char *buf = NULL; size_t length; (void) exit_on_error; (void) linemode; do { #ifdef HAVE_LIBREADLINE if (prompt) { if (buf) free(buf); buf = readline(prompt); /* add a newline to the end since that makes further processing easier */ if (buf) { add_history(buf); length = strlen(buf); buf = realloc(buf, length + 2); if( buf == NULL){ GDKerror("getConsoleInput: " MAL_MALLOC_FAIL); return NULL; } buf[length++] = '\n'; buf[length] = 0; } line = buf; } else #endif { #ifndef HAVE_LIBREADLINE if (prompt) { fputs(prompt, stdout); fflush(stdout); } #endif if (buf == NULL) { buf= malloc(BUFSIZ); if( buf == NULL){ GDKerror("getConsoleInput: " MAL_MALLOC_FAIL); return NULL; } } line = fgets(buf, BUFSIZ, stdin); } if (line == NULL) { /* end of file */ if (buf) free(buf); return NULL; } else length = strlen(line); if (length > 0 ) { /* test for special commands */ while (length > 0 && (*line & ~0x7F) == 0 && isspace((int) *line)) { line++; length--; } /* in the switch, use continue if the line was processed, use break to send to parser */ switch (*line) { case '\0': /* empty line */ break; case '\\': switch (line[1]) { case 'q': free(buf); return NULL; default: break; } line= NULL; break; case '<': /* read commands from file */ if (line[length - 1] == '\n') line[--length] = 0; if (line[length - 1] == '\r') line[--length] = 0; /* doFile(mid, line + 1, 0);*/ line= NULL; continue; case '>': /* redirect output to file */ line++; length--; if (line[length - 1] == '\n') line[--length] = 0; if (line[length - 1] == '\r') line[--length] = 0; if (c->fdout && c->fdout != GDKout && c->fdout != GDKerr){ close_stream(c->fdout); c->fdout= 0; } if (length == 0 || strcmp(line, "stdout") == 0) c->fdout = GDKout; else if (strcmp(line, "stderr") == 0) c->fdout = GDKerr; else if ((c->fdout = open_wastream(line)) == NULL) { c->fdout = GDKout; mnstr_printf(GDKerr, "Cannot open %s\n", line); } line = NULL; continue; #ifdef HAVE_LIBREADLINE case '!': { char *nl; int i; if(line[1]=='\n') { for(i=0; i< history_length; i++){ nl= history_get(i)? history_get(i)->line:0; if( nl) mnstr_printf(c->fdout, "%d %s\n", i, nl); } line = NULL; } else if( history_expand(line,&nl) ==1 ) { mnstr_printf(c->fdout,"#%s",nl); line= nl; } else line= NULL; } continue; #endif case '?': if( line[1] && line[1]!='\n'){ showHelp( c->nspace,line+1, c->fdout); } else showCommands(); line= NULL; continue; } /* make sure we return a pointer that can (and should) be freed by the caller */ if (line) line = buf; } } while (line == NULL); return line; }
static int _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl) { jb_frame *frame; long diff; static int dbg_cnt = 0; /*if ((now - jb_next(jb)) > 2 * jb->info.last_voice_ms) jb_warn("SCHED: %ld", (now - jb_next(jb))); */ /* get jitter info */ history_get(jb); if (dbg_cnt && dbg_cnt % 50 == 0) { jb_dbg("\n"); } dbg_cnt++; /* target */ jb->info.target = jb->info.jitter + jb->info.min + JB_TARGET_EXTRA; /* if a hard clamp was requested, use it */ if ((jb->conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->conf.max_jitterbuf)) { jb_dbg("clamping target from %d to %d\n", (jb->info.target - jb->info.min), jb->conf.max_jitterbuf); jb->info.target = jb->info.min + jb->conf.max_jitterbuf; } diff = jb->info.target - jb->info.current; /* jb_warn("diff = %d lms=%d last = %d now = %d\n", diff, */ /* jb->info.last_voice_ms, jb->info.last_adjustment, now); */ /* let's work on non-silent case first */ if (!jb->info.silence_begin_ts) { /* we want to grow */ if ((diff > 0) && /* we haven't grown in the delay length */ (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) || /* we need to grow more than the "length" we have left */ (diff > queue_last(jb) - queue_next(jb)) ) ) { /* grow by interp frame length */ jb->info.current += interpl; jb->info.next_voice_ts += interpl; jb->info.last_voice_ms = interpl; jb->info.last_adjustment = now; jb->info.cnt_contig_interp++; if (jb->conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->conf.max_contig_interp) { jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; } jb_dbg("G"); return JB_INTERP; } frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current); /* not a voice frame; just return it. */ if (frame && frame->type != JB_TYPE_VOICE) { if (frame->type == JB_TYPE_SILENCE) { jb->info.silence_begin_ts = frame->ts; jb->info.cnt_contig_interp = 0; } *frameout = *frame; jb->info.frames_out++; jb_dbg("o"); return JB_OK; } /* voice frame is later than expected */ if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) { if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) { /* either we interpolated past this frame in the last jb_get */ /* or the frame is still in order, but came a little too quick */ *frameout = *frame; /* reset expectation for next frame */ jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.cnt_contig_interp = 0; jb_dbg("v"); return JB_OK; } else { /* voice frame is late */ *frameout = *frame; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_late++; jb->info.frames_lost--; jb_dbg("l"); /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_warninfo(jb); */ return JB_DROP; } } /* keep track of frame sizes, to allow for variable sized-frames */ if (frame && frame->ms > 0) { jb->info.last_voice_ms = frame->ms; } /* we want to shrink; shrink at 1 frame / 500ms */ /* unless we don't have a frame, then shrink 1 frame */ /* every 80ms (though perhaps we can shrink even faster */ /* in this case) */ if (diff < -JB_TARGET_EXTRA && ((!frame && jb->info.last_adjustment + 80 < now) || (jb->info.last_adjustment + 500 < now))) { jb->info.last_adjustment = now; jb->info.cnt_contig_interp = 0; if (frame) { *frameout = *frame; /* shrink by frame size we're throwing out */ jb->info.current -= frame->ms; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_dropped++; jb_dbg("s"); return JB_DROP; } else { /* shrink by last_voice_ms */ jb->info.current -= jb->info.last_voice_ms; jb->info.frames_lost++; increment_losspct(jb); jb_dbg("S"); return JB_NOFRAME; } } /* lost frame */ if (!frame) { /* this is a bit of a hack for now, but if we're close to * target, and we find a missing frame, it makes sense to * grow, because the frame might just be a bit late; * otherwise, we presently get into a pattern where we return * INTERP for the lost frame, then it shows up next, and we * throw it away because it's late */ /* I've recently only been able to replicate this using * iaxclient talking to app_echo on callweaver. In this case, * my outgoing packets go through callweaver's (old) * jitterbuffer, and then might get an unusual increasing delay * there if it decides to grow?? */ /* Update: that might have been a different bug, that has been fixed.. * But, this still seemed like a good idea, except that it ended up making a single actual * lost frame get interpolated two or more times, when there was "room" to grow, so it might * be a bit of a bad idea overall */ /*if (diff > -1 * jb->info.last_voice_ms) { jb->info.current += jb->info.last_voice_ms; jb->info.last_adjustment = now; jb_warn("g"); return JB_INTERP; } */ jb->info.frames_lost++; increment_losspct(jb); jb->info.next_voice_ts += interpl; jb->info.last_voice_ms = interpl; jb->info.cnt_contig_interp++; if (jb->conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->conf.max_contig_interp) { jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current; } jb_dbg("L"); return JB_INTERP; } /* normal case; return the frame, increment stuff */ *frameout = *frame; jb->info.next_voice_ts += frame->ms; jb->info.frames_out++; jb->info.cnt_contig_interp = 0; decrement_losspct(jb); jb_dbg("v"); return JB_OK; } else { /* TODO: after we get the non-silent case down, we'll make the * silent case -- basically, we'll just grow and shrink faster * here, plus handle next_voice_ts a bit differently */ /* to disable silent special case altogether, just uncomment this: */ /* jb->info.silence_begin_ts = 0; */ /* shrink interpl len every 10ms during silence */ if (diff < -JB_TARGET_EXTRA && jb->info.last_adjustment + 10 <= now) { jb->info.current -= interpl; jb->info.last_adjustment = now; } frame = queue_get(jb, now - jb->info.current); if (!frame) { jb_dbg("Didn't get a frame from queue\n"); return JB_NOFRAME; } else if (frame->type != JB_TYPE_VOICE) { /* normal case; in silent mode, got a non-voice frame */ *frameout = *frame; jb->info.frames_out++; return JB_OK; } if (frame->ts < jb->info.silence_begin_ts) { /* voice frame is late */ *frameout = *frame; jb->info.frames_out++; decrement_losspct(jb); jb->info.frames_late++; jb->info.frames_lost--; jb_dbg("l"); /*jb_warn("\nlate: wanted=%ld, this=%ld, next=%ld\n", jb->info.next_voice_ts - jb->info.current, frame->ts, queue_next(jb)); jb_warninfo(jb); */ return JB_DROP; } else { /* voice frame */ /* try setting current to target right away here */ jb->info.current = jb->info.target; jb->info.silence_begin_ts = 0; jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms; jb->info.last_voice_ms = frame->ms; jb->info.frames_out++; decrement_losspct(jb); *frameout = *frame; jb_dbg("V"); return JB_OK; } } }