void free_chars(buffer *const b, char *const p, const int64_t len) { if (!b || !p || !len) return; char_pool *cp = get_char_pool(b, p); assert_char_pool(cp); assert(*p); assert(p[len - 1]); block_signals(); memset(p, 0, len); b->free_chars += len; if (p == &cp->pool[cp->first_used]) while(cp->first_used <= cp->last_used && !cp->pool[cp->first_used]) cp->first_used++; if (p + len - 1 == &cp->pool[cp->last_used]) while(!cp->pool[cp->last_used] && cp->first_used <= cp->last_used) cp->last_used--; if (cp->last_used < cp->first_used) { rem(&cp->cp_node); b->allocated_chars -= cp->size; b->free_chars -= cp->size; free_char_pool(cp); release_signals(); return; } assert_char_pool(cp); release_signals(); }
QLuaConsole::Private::~Private() { Q_ASSERT(console == this); // console thread command(KillCmd); wait(); // file descriptors redirect(false); if (trueStdout) fclose(trueStdout); if (trueStderr) fclose(trueStderr); ::close(stdoutPipe[0]); ::close(stdoutPipe[1]); ::close(commandPipe[0]); ::close(commandPipe[1]); // signals release_signals(&savedSigSet); set_sigint_handler(SIG_DFL); // done #if HAVE_READLINE rtty_done(); #endif console = 0; }
void free_buffer_contents(buffer * const b) { if (!b) return; block_signals(); free_list(&b->line_desc_pool_list, free_line_desc_pool); free_list(&b->char_pool_list, free_char_pool); new_list(&b->line_desc_list); b->cur_line_desc = b->top_line_desc = NULL; b->allocated_chars = b->free_chars = 0; b->is_CRLF = false; b->encoding = ENC_ASCII; b->bookmark_mask = 0; b->mtime = 0; free_char_stream(b->last_deleted); b->last_deleted = NULL; free(b->filename); b->filename = NULL; reset_undo_buffer(&b->undo); b->is_modified = b->marking = b->recording = b->x_wanted = 0; release_signals(); }
/* * Signal handler for signals that cause program's termination. */ void signal_handler(int sig) { release_signals(); fatal(ERROR_SIGNAL, "killed by signal %d\n", sig); }
line_desc *alloc_line_desc(buffer * const b) { block_signals(); line_desc_pool *ldp; for(ldp = (line_desc_pool *)b->line_desc_pool_list.head; ldp->ldp_node.next; ldp = (line_desc_pool *)ldp->ldp_node.next) { assert_line_desc_pool(ldp); if (ldp->free_list.head->next) { line_desc * const ld = (line_desc *)ldp->free_list.head; rem(&ld->ld_node); if (!ldp->free_list.head->next) { rem(&ldp->ldp_node); add_tail(&b->line_desc_pool_list, &ldp->ldp_node); } ldp->allocated_items++; ld->line = NULL; ld->line_len = 0; if (do_syntax) ld->highlight_state.state = -1; release_signals(); return ld; } } /* No chances, all pools are full. Let's allocate a new one, using the standard pool size, and let's put it at the start of the list, so that it is always scanned first. */ if (ldp = alloc_line_desc_pool(0)) { add_head(&b->line_desc_pool_list, &ldp->ldp_node); line_desc * const ld = (line_desc *)ldp->free_list.head; rem(&ld->ld_node); ldp->allocated_items = 1; if (do_syntax) ld->highlight_state.state = -1; release_signals(); return ld; } release_signals(); return NULL; }
int64_t alloc_chars_around(buffer * const b, line_desc * const ld, const int64_t n, const bool check_first_before) { assert(ld->line != NULL); char_pool *cp = get_char_pool(b, ld->line); assert_char_pool(cp); block_signals(); char *before = ld->line - 1; char *after = ld->line + ld->line_len; if (check_first_before) { while(before >= cp->pool && !*before && (ld->line - 1) - before < n) before--; while(after < cp->pool + cp->size && !*after && (after - (ld->line + ld->line_len)) + ((ld->line - 1) - before)<n) after++; } else { while(after < cp->pool + cp->size && !*after && after - (ld->line + ld->line_len)<n) after++; while(before >= cp->pool && !*before && (after - (ld->line + ld->line_len)) + ((ld->line - 1) - before)<n) before--; } assert(((ld->line - 1) - before) + (after - (ld->line + ld->line_len)) <= n); assert(((ld->line - 1) - before) + (after - (ld->line + ld->line_len)) >= 0); if (((ld->line - 1) - before) + (after - (ld->line + ld->line_len)) == n) { if (cp->pool + cp->first_used == ld->line) cp->first_used = (before + 1) - cp->pool; if (cp->pool + cp->last_used == ld->line + ld->line_len - 1) cp->last_used = (after - 1) - cp->pool; b->free_chars -= n; release_signals(); return after - (ld->line + ld->line_len); } release_signals(); return ERROR; }
void QLuaConsole::Private::run() { // --- This runs from the console thread. // accept signals in this thread. set_sigint_handler(SIG_DFL); release_signals(&savedSigSet); // loop while (! killConsole) { int fds[2]; int nfd = 0; if (! throttleActive) fds[nfd++] = stdoutPipe[0]; fds[nfd++] = commandPipe[0]; int fd = wait_for_input(nfd, fds); mutex.lock(); if (! throttleActive) copyout(); if (fd == commandPipe[0]) { char c = (char)NoCmd; if (::read(commandPipe[0], &c, 1) > 0) switch( (enum Command)c ) { case HandlerCmd: sethandler(); break; case DrainCmd: msleep(10); copyout(throttleActive = false); drain.wakeAll(); break; case BreakCmd: if (lua && breakStopsLua) lua->stop(); emit q->ttyBreak(); break; case ReadlineCmd: readline(); break; case KillCmd: killConsole = true; default: break; } } pulse.wakeAll(); mutex.unlock(); } // reset signals set_sigint_handler(SIG_DFL); }
int delete_one_line(buffer * const b, line_desc * const ld, const int64_t line) { assert_line_desc(ld, b->encoding); assert_buffer(b); block_signals(); if (ld->line_len && (b->last_deleted = reset_stream(b->last_deleted))) add_to_stream(b->last_deleted, ld->line, ld->line_len); /* We delete a line by delete_stream()ing its length plus one. However, if we are on the last line of text, there is no terminating line feed. */ const int error = delete_stream(b, ld, line, 0, ld->line_len + (ld->ld_node.next->next ? 1 : 0)); release_signals(); return error; }
void clear_buffer(buffer * const b) { if (!b) return; block_signals(); free_buffer_contents(b); line_desc * const ld = alloc_line_desc(b); add_head(&b->line_desc_list, &ld->ld_node); if (do_syntax) { ld->highlight_state.state = 0; ld->highlight_state.stack = NULL; ld->highlight_state.saved_s[0] = 0; } b->num_lines = 1; reset_position_to_sof(b); assert_buffer(b); release_signals(); }
void free_line_desc(buffer * const b, line_desc * const ld) { /* We scan the pool list in order to find where the given line descriptor lives. */ line_desc_pool *ldp; for(ldp = (line_desc_pool *)b->line_desc_pool_list.head; ldp->ldp_node.next; ldp = (line_desc_pool *)ldp->ldp_node.next) { assert_line_desc_pool(ldp); if (ld >= ldp->pool && (do_syntax && ld < ldp->pool + ldp->size || !do_syntax && ld < (line_desc*)((no_syntax_line_desc *)ldp->pool + ldp->size))) break; } assert(ldp->ldp_node.next != NULL); block_signals(); add_head(&ldp->free_list, &ld->ld_node); if (--ldp->allocated_items == 0) { rem(&ldp->ldp_node); free_line_desc_pool(ldp); } release_signals(); }
int main(int argc, char *argv[]) { char *env_top; char **preset_argv; int preset_argc = 0; void *mask; int need_mini = 1; struct statics statics; globalstate *gstate; /* get our name */ if (argc > 0) { if ((myname = strrchr(argv[0], '/')) == 0) { myname = argv[0]; } else { myname++; } } /* binary compatibility check */ #ifdef HAVE_UNAME { struct utsname uts; if (uname(&uts) == 0) { if (strcmp(uts.machine, UNAME_HARDWARE) != 0) { fprintf(stderr, "%s: incompatible hardware platform\n", myname); exit(EX_UNAVAILABLE); } } } #endif /* initialization */ gstate = (globalstate *)calloc(1, sizeof(globalstate)); gstate->statics = &statics; time_mark(NULL); /* preset defaults for various options */ gstate->show_usernames = Yes; gstate->topn = DEFAULT_TOPN; gstate->delay = DEFAULT_DELAY; gstate->fulldraw = Yes; gstate->use_color = Yes; gstate->interactive = Maybe; /* preset defaults for process selection */ gstate->pselect.idle = Yes; gstate->pselect.system = No; gstate->pselect.fullcmd = No; gstate->pselect.command = NULL; gstate->pselect.uid = -1; gstate->pselect.mode = 0; /* use a large buffer for stdout */ #ifdef HAVE_SETVBUF setvbuf(stdout, stdoutbuf, _IOFBF, BUFFERSIZE); #else #ifdef HAVE_SETBUFFER setbuffer(stdout, stdoutbuf, BUFFERSIZE); #endif #endif /* get preset options from the environment */ if ((env_top = getenv("TOP")) != NULL) { preset_argv = argparse(env_top, &preset_argc); preset_argv[0] = myname; do_arguments(gstate, preset_argc, preset_argv); } /* process arguments */ do_arguments(gstate, argc, argv); #ifdef ENABLE_COLOR /* If colour has been turned on read in the settings. */ env_top = getenv("TOPCOLOURS"); if (!env_top) { env_top = getenv("TOPCOLORS"); } /* must do something about error messages */ color_env_parse(env_top); color_activate(gstate->use_color); #endif /* in order to support forward compatability, we have to ensure that the entire statics structure is set to a known value before we call machine_init. This way fields that a module does not know about will retain their default values */ memzero((void *)&statics, sizeof(statics)); statics.boottime = -1; /* call the platform-specific init */ if (machine_init(&statics) == -1) { exit(EX_SOFTWARE); } /* create a helper list of sort order names */ gstate->order_namelist = string_list(statics.order_names); /* look up chosen sorting order */ if (gstate->order_name != NULL) { int i; if (statics.order_names == NULL) { message_error(" This platform does not support arbitrary ordering"); } else if ((i = string_index(gstate->order_name, statics.order_names)) == -1) { message_error(" Sort order `%s' not recognized", gstate->order_name); message_error(" Recognized sort orders: %s", gstate->order_namelist); } else { gstate->order_index = i; } } /* initialize extensions */ init_username(); /* initialize termcap */ gstate->smart_terminal = screen_readtermcap(gstate->interactive); /* determine interactive state */ if (gstate->interactive == Maybe) { gstate->interactive = smart_terminal; } /* if displays were not specified, choose an appropriate default */ if (gstate->displays == 0) { gstate->displays = gstate->smart_terminal ? Infinity: 1; } /* we don't need a mini display when delay is less than 2 seconds or when we are not on a smart terminal */ if (gstate->delay <= 1 || !smart_terminal) { need_mini = 0; } /* set constants for username/uid display */ if (gstate->show_usernames) { gstate->header_text = format_header("USERNAME"); gstate->get_userid = username; } else { gstate->header_text = format_header(" UID "); gstate->get_userid = itoa7; } gstate->pselect.usernames = gstate->show_usernames; /* initialize display */ if ((gstate->max_topn = display_init(&statics)) == -1) { fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); exit(EX_OSERR); } /* check for infinity and for overflowed screen */ if (gstate->topn == Infinity) { gstate->topn = INT_MAX; } else if (gstate->topn > gstate->max_topn) { #if 0 message_error(" This terminal can only display %d processes", gstate->max_topn); #endif } #ifdef ENABLE_COLOR /* producing a list of color tags is easy */ if (gstate->show_tags) { color_dump(stdout); exit(EX_OK); } #endif /* hold all signals while we initialize the screen */ mask = hold_signals(); screen_init(); /* set the signal handlers */ set_signals(); /* longjmp re-entry point */ /* set the jump buffer for long jumps out of signal handlers */ if (setjmp(jmp_int) != 0) { /* this is where we end up after processing sigwinch or sigtstp */ /* tell display to resize its buffers, and get the new length */ if ((gstate->max_topn = display_resize()) == -1) { /* thats bad */ quit(EX_OSERR); /*NOTREACHED*/ } /* set up for a full redraw, and get the current line count */ gstate->fulldraw = Yes; /* safe to release the signals now */ release_signals(mask); } else { /* release the signals */ release_signals(mask); /* some systems require a warmup */ /* always do a warmup for batch mode */ if (gstate->interactive == 0 || statics.flags.warmup) { struct system_info system_info; struct timeval timeout; time_mark(&(gstate->now)); get_system_info(&system_info); (void)get_process_info(&system_info, &gstate->pselect, 0); timeout.tv_sec = 1; timeout.tv_usec = 0; select(0, NULL, NULL, NULL, &timeout); /* if we've warmed up, then we can show good states too */ gstate->show_cpustates = Yes; need_mini = 0; } } /* main loop */ while ((gstate->displays == -1) || (--gstate->displays > 0)) { do_display(gstate); if (gstate->interactive) { if (need_mini) { do_minidisplay(gstate); need_mini = 0; } do_command(gstate); } else { do_wait(gstate); } } /* do one last display */ do_display(gstate); quit(EX_OK); /* NOTREACHED */ return 1; /* Keep compiler quiet. */ }
int insert_stream(buffer * const b, line_desc * ld, int64_t line, int64_t pos, const char * const stream, const int64_t stream_len) { if (!b || !ld || !stream || stream_len < 1 || pos > ld->line_len) return ERROR; assert_line_desc(ld, b->encoding); assert_buffer(b); block_signals(); if (b->opt.do_undo && !(b->undoing || b->redoing)) { const int error = add_undo_step(b, line, pos, -stream_len); if (error) { release_signals(); return error; } } const char *s = stream; while(s - stream < stream_len) { int64_t const len = strnlen_ne(s, stream_len - (s - stream)); if (len) { /* First case; there is no character allocated on this line. We have to freshly allocate the line. */ if (!ld->line) { if (ld->line = alloc_chars(b, len)) { memcpy(ld->line, s, len); ld->line_len = len; } else { release_signals(); return OUT_OF_MEMORY; } } /* Second case. There are not enough characters around ld->line. Note that the value of the check_first_before parameter depends on the position at which the insertion will be done, and it is chosen in such a way to minimize the number of characters to move. */ else { const int64_t result = alloc_chars_around(b, ld, len, pos < ld->line_len / 2); if (result < 0) { char * const p = alloc_chars(b, ld->line_len + len); if (p) { memcpy(p, ld->line, pos); memcpy(&p[pos], s, len); memcpy(&p[pos + len], ld->line + pos, ld->line_len - pos); free_chars(b, ld->line, ld->line_len); ld->line = p; ld->line_len += len; } else { release_signals(); return OUT_OF_MEMORY; } } else { /* Third case. There are enough free characters around ld->line. */ if (len - result) memmove(ld->line - (len - result), ld->line, pos); if (result) memmove(ld->line + pos + result, ld->line + pos, ld->line_len - pos); memcpy(ld->line - (len - result) + pos, s, len); ld->line -= (len - result); ld->line_len += len; } } b->is_modified = 1; /* We just inserted len chars at (line,pos); adjust bookmarks and mark accordingly. */ if (b->marking && b->block_start_line == line && b->block_start_pos > pos) b->block_start_pos += len; for (int i = 0, mask = b->bookmark_mask; mask; i++, mask >>= 1) if ((mask & 1) && b->bookmark[i].line == line && b->bookmark[i].pos > pos) b->bookmark[i].pos += len; } /* If the string we have inserted has a NULL at the end, we create a new line under the current one and set ld to point to it. */ if (len + (s - stream) < stream_len) { line_desc *new_ld; if (new_ld = alloc_line_desc(b)) { add(&new_ld->ld_node, &ld->ld_node); b->num_lines++; if (pos + len < ld->line_len) { new_ld->line_len = ld->line_len - pos - len; new_ld->line = &ld->line[pos + len]; ld->line_len = pos + len; if (pos + len == 0) ld->line = NULL; } b->is_modified = 1; ld = new_ld; /* We just inserted a line break at (line,pos); adjust the buffer bookmarks and mark accordingly. */ if (b->marking) { if (b->block_start_line == line && b->block_start_pos > pos) { b->block_start_pos -= pos; b->block_start_line++; } else if (b->block_start_line > line) b->block_start_line++; } for (int i = 0, mask=b->bookmark_mask; mask; i++, mask >>= 1) { if (mask & 1) { if (b->bookmark[i].line == line && b->bookmark[i].pos > pos) { b->bookmark[i].pos -= pos; b->bookmark[i].line++; } else if (b->bookmark[i].line > line) b->bookmark[i].line++; } } pos = 0; line++; } else {
char *alloc_chars(buffer * const b, const int64_t len) { if (!len || !b) return NULL; assert_buffer(b); block_signals(); char_pool *cp; for(cp = (char_pool *)b->char_pool_list.head; cp->cp_node.next; cp = (char_pool *)cp->cp_node.next) { assert_char_pool(cp); /* We try to allocate before the first used character, or after the last used character. If we succeed with a pool which is not the head of the list, we move it to the head in order to optimize the next try. */ if (cp->first_used >= len) { cp->first_used -= len; b->free_chars -= len; if (cp != (char_pool *)b->char_pool_list.head) { rem(&cp->cp_node); add_head(&b->char_pool_list, &cp->cp_node); } release_signals(); return cp->pool + cp->first_used; } else if (cp->size - cp->last_used > len) { cp->last_used += len; b->free_chars -= len; if (cp != (char_pool *)b->char_pool_list.head) { rem(&cp->cp_node); add_head(&b->char_pool_list, &cp->cp_node); } release_signals(); return cp->pool + cp->last_used - len + 1; } } /* If no free space has been found, we allocate a new pool which is guaranteed to contain at least len characters. The pool is added to the head of the list. */ if (cp = alloc_char_pool(len)) { add_head(&b->char_pool_list, &cp->cp_node); cp->last_used = len - 1; b->allocated_chars += cp->size; b->free_chars += cp->size - len; release_signals(); return cp->pool; } release_signals(); return NULL; }