int sh_loop(t_info *info) { int ret; int multi; ret = 1; sh_get_path(info); ft_printf("\033[31m%s\033[39m $> ", info->cursdir); while ((ret = get_next_line(0, &info->line)) > 0) { UNSET(info->sig, BIT_A); UNSET(info->opt, OPT_A); if (!(multi = sh_multi(info))) { sh_parse(info); info->status = sh_exec(info, info->env, &info->args[1]); } sh_get_path(info); ft_printf("\033[31m%s\033[39m $> ", info->cursdir); ft_tabdel(&info->args); free(info->line); } if (ret == -1) return (EXIT_FAILURE); return (EXIT_SUCCESS); }
/******************************* Main Program Code *************************/ int main(void) { // enable motor#1 DDRA = 0b00001100; // initialize the LCD controller as determined by the defines (LCD instructions) lcd_init_4d(); // initialize the LCD display for a 4-bit interface // endless loop while(1) { lcd_clear_line_4d(lcd_LineOne); _delay_ms(500); // display the first line of information lcd_write_string_line_4d("Motor Clockwise", lcd_LineOne); // rotate motor UNSET(PORTA, PIN(2)); SET(PORTA, PIN(3)); // clear LCD lcd_clear_line_4d(lcd_LineTwo); _delay_ms(500); // display the first line of information lcd_write_string_line_4d("Counter Clockwiz", lcd_LineTwo); // rotate motor SET(PORTA, PIN(2)); UNSET(PORTA, PIN(3)); } return 0; }
// The daemon_init function provides an interface to the main thread // to start the daemon. It should only be called once and will run // in the main thread. void daemon_init(DaemonComm *dc) { // Initialize the Daemon Communication Struct. // This struct is used to pass information from the // main thread to the daemon thread. UNSET(dc->new_code); UNSET(dc->in_hw); dc->new_code_address = NULL; dc->new_code_size = 0; // Create the daemon thread. hthread_create(&dc->tid, NULL, daemon_thread, (void *)dc); }
int sh_env(t_info *info) { int i; t_info context; sh_context(info, &context); UNSET(context.opt, OPT_A); i = 1; while (env_opt(context.args[i], &context)) i++; if (GET(context.opt, OPT_I)) env_i(&context, i); else if (!context.args[1]) { sh_printenv(&context); return (EXIT_SUCCESS); } else env_set(&context); if (ft_strequ(context.args[0], "cd")) return (EXIT_SUCCESS); else if (context.args[0]) sh_exec(&context); else sh_printenv(&context); sh_clear_context(&context); return (EXIT_SUCCESS); }
int sc_chmod(thread_t *t, syscall_result_t *r, chmod_args_t *args) { int res=0; proc_t *p = t->thr_proc; vnode_t *node; char pname[PATH_MAX]; if((res = copyinstr(pname, args->fname, PATH_MAX))) return res; res = vfs_lookup(p->p_curdir, &node, pname, t, LKP_NORMAL); if(res) return res; vattr_t va; va.va_mask=VATTR_ALL; if((res = VOP_GETATTR(node, &va))) goto err; res = -EPERM; if(p->p_cred->p_euid != 0 && p->p_cred->p_euid != va.va_uid) goto err; mode_t mode = args->mode & 07777; if(ISSET(mode, S_ISGID) && p->p_cred->p_euid!=0 && va.va_gid!=p->p_cred->p_egid) UNSET(mode, S_ISGID); //mamy prawo kasować bit suid/sgid? va.va_mask = VATTR_MODE; va.va_mode = mode; if((res = VOP_SETATTR(node, &va))) goto err; vrele(node); return 0; err: vrele(node); return res; }
// The daemon_create_thread is used by the main thread to create user // threads. This will run in the main thread. void daemon_create_thread(DaemonComm *dc, byte *code, unsigned int code_size) { // Change the state of dc to reflect the presence of new bytecode to execute. SET(dc->new_code); UNSET(dc->in_hw); // (HW/SW is unspecified) dc->new_code_address = code; dc->new_code_size = code_size; // Yield to allow the daemon thread to process this create. hthread_yield(); }
__interrupt void USCI0RX_ISR(void) { while (!(IFG2 & UCA0TXIFG)); if(~IS_SET(RECEIVED)){ if(RX == START_BYTE && ~IS_SET(RECEIVING)){ SET(RECEIVING); } else if(RX != END_BYTE && IS_SET(RECEIVING)){ buffer[bufferCursor] = RX; if(++bufferCursor == BUF_SIZE){ UNSET(RECEIVING); SET(RECEIVED); } } else if(RX == END_BYTE && IS_SET(RECEIVING)){ UNSET(RECEIVING); SET(RECEIVED); } } }
/* Display a message on the statusbar, and set disable_cursorpos to * true, so that the message won't be immediately overwritten if * constant cursor position display is on. */ void statusbar(const char *msg, ...) { va_list ap; char *bar, *foo; size_t start_x; bool old_whitespace; va_start(ap, msg); /* Curses mode is turned off. If we use wmove() now, it will muck * up the terminal settings. So we just use vfprintf(). */ if (isendwin()) { vfprintf(stderr, msg, ap); va_end(ap); return; } blank_statusbar(); old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); bar = charalloc(mb_cur_max() * (COLS - 3)); vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap); va_end(ap); foo = display_string(bar, 0, COLS - 4, false); free(bar); if (old_whitespace) { SET(WHITESPACE_DISPLAY); } start_x = (COLS - strlenpt(foo) - 4) / 2; wmove(bottomwin, 0, start_x); set_color(bottomwin, interface_colors[STATUS_BAR]); waddstr(bottomwin, "[ "); waddstr(bottomwin, foo); free(foo); waddstr(bottomwin, " ]"); clear_color(bottomwin, interface_colors[STATUS_BAR]); wnoutrefresh(bottomwin); reset_cursor(); wnoutrefresh(edit); /* Leave the cursor at its position in the edit window, not in * the statusbar. */ disable_cursorpos = true; /* If we're doing quick statusbar blanking, and constant cursor * position display is off, blank the statusbar after only one * keystroke. Otherwise, blank it after twenty-six keystrokes, as * Pico does. */ statusblank = ISSET(QUICK_BLANK) && !ISSET(CONST_UPDATE) ? 1 : 26; }
void process_modifier(t_mod *m) { if (ft_strchr("DOCU", m->convers)) { UNSET(m->modif, MOD_ALL); SET(m->modif, MOD_L); m->convers = ft_tolower(m->convers); } if (m->convers == 's' && GET(m->modif, MOD_L)) { TOGGLE(m->modif, MOD_L); m->convers = 'S'; } }
int print_sign(t_mod *m, va_list ap) { size_t cnt; t_ll arg; char buf[128]; arg = get_arg_sign(m, ap); if (arg < 0) { UNSET(m->flag, F_SPACE); m->length--; } if (GET(m->flag, F_PLUS)) m->length--; get_buf(m, arg, buf); cnt = display_ui(m, buf); return (cnt); }
/* Load the histories for Search and Replace and Execute Command. */ void load_history(void) { char *histname = concatenate(statedir, SEARCH_HISTORY); FILE *hisfile = fopen(histname, "rb"); if (hisfile == NULL) { if (errno != ENOENT) { /* When reading failed, don't save history when we quit. */ UNSET(HISTORYLOG); history_error(N_("Error reading %s: %s"), histname, strerror(errno)); } } else { /* Load the three history lists -- first search, then replace, * then execute -- from oldest entry to newest. Between two * lists there is an empty line. */ linestruct **history = &search_history; char *line = NULL; size_t buf_len = 0; ssize_t read; while ((read = getline(&line, &buf_len, hisfile)) > 0) { line[--read] = '\0'; if (read > 0) { /* Encode any embedded NUL as 0x0A. */ unsunder(line, read); update_history(history, line); } else if (history == &search_history) history = &replace_history; else history = &execute_history; } fclose(hisfile); free(line); } /* After reading them in, set the status of the lists to "unchanged". */ history_changed = FALSE; free(histname); }
int sc_chown(thread_t *t, syscall_result_t *r, chown_args_t *args) { int res=0; proc_t *p = t->thr_proc; vnode_t *node; char pname[PATH_MAX]; if((res = copyinstr(pname, args->fname, PATH_MAX))) return res; res = vfs_lookup(p->p_curdir, &node, pname, t, LKP_NORMAL); if(res) return res; vattr_t va; va.va_mask=VATTR_ALL; if((res = VOP_GETATTR(node, &va))) goto err; res = -EPERM; if(p->p_cred->p_euid != 0 && p->p_cred->p_euid != va.va_uid) goto err; if(p->p_cred->p_euid != 0) //tak... póki co nie ma zmian dla nie roota goto err; va.va_mask = VATTR_UID | VATTR_GID | VATTR_MODE; if(args->uid!=-1) va.va_uid = args->uid; if(args->gid!=-1) va.va_gid = args->gid; if(p->p_cred->p_euid!=0) //tymczasowo niemożliwe UNSET(va.va_mode, S_ISUID | S_ISGID); if((res = VOP_SETATTR(node, &va))) goto err; vrele(node); return 0; err: vrele(node); return res; }
void *daemon_thread(void *arg) { TID_t next_tid = 0; TID_t hw_tid = 0; int rv, hw_ret_val, regCount; hthread_t junk_tid; flag hw_available, hw_done; sched_param_t my_priority; Hint my_policy; // Display the daemon's priority hthread_getschedparam(hthread_self(),&my_policy,&my_priority); //printf("Daemon priority = %d\n", my_priority.sched_priority); // Create a pointer to the Daemon's communication struct with main. DaemonComm *dc = (DaemonComm *)arg; // Create a buffer for software interpreters to export/import their state to. ExportBuffer export_buffer; ImportBuffer import_buffer; // The software_interpreter_list holds active threads that are being interpreted by // the software interpreter. TCBNode software_interpreter_list[MAX_SW_THREAD]; // The cur_tcb and the tcb_index are used to reference TCBs in the software interpreter list. TCBNode *cur_tcb; TCB *new_tcb; int tcb_index; // Initialize TCB List for (cur_tcb = software_interpreter_list; cur_tcb < software_interpreter_list + MAX_SW_THREAD; cur_tcb++) { UNSET(cur_tcb->valid); } // Initialize hardware flags SET(hw_available); SET(hw_done); printf(" ...DAEMON running.\n"); // The daemon will run forever. Currently we have no clean shutdown mechanism. while(1) { // Process each TCB in the software interpreter list. for (cur_tcb = software_interpreter_list; cur_tcb < software_interpreter_list + MAX_SW_THREAD; cur_tcb++) { // If the TCB is invalid, then skip it. if (! ISSET(cur_tcb->valid)) continue; // If a thread is done interpreting, then print its return value and invalidate the TCB. if (ISSET(cur_tcb->entry.communication.control.done_interpreting)) { printf("DAEMON: Thread id %u (running in SW) returned %d\n", cur_tcb->entry.tid, cur_tcb->entry.communication.data.return_value); UNSET(cur_tcb->valid); continue; } // If the thread is done exporting to hardware, then invalidate the TCB and start // the hardware interpretation process. if (ISSET(cur_tcb->entry.communication.control.done_exporting)) { // TODO: If a software thread has finished exporting, but in the meantime a // a new "run this thread only in hardware" request has come in, we need to copy // the thread state from the export buffer *back* into a software thread to make // room for the hw->sw migration we're about to do. // If there is new bytecode available to execute, then process it. if (ISSET(dc->new_code) & ISSET(dc->in_hw)) { // Kick thread back into SW // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = cur_tcb->entry.tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); // Copy program/state to interpreter memory space for (regCount = 0; regCount < NUMBER_REGISTERS ; regCount++) { import_buffer.register_file[regCount] = export_buffer.register_file[regCount]; } memcpy(software_interpreter_list[tcb_index].memory, cur_tcb->memory, export_buffer.register_file[SP]); //start_software_interpreter(); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point_import, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } } else { // Move the thread into HW // Grab the SW thread's TID hw_tid = cur_tcb->entry.tid; // Migrate state from export buffer into HW interpreter reset_HVM(); printf("DAEMON: Migrating thread id %u from SW to HW...",hw_tid); import_state_HVM(&export_buffer, cur_tcb->memory); printf("COMPLETE\n"); // Start HW interpreter execution light_LED(hw_tid); UNSET(hw_done); run_HVM(); // Invalidate TCB UNSET(cur_tcb->valid); } } } // Is the hardware done interpreting if (is_HVM_done()) { // Export HVM state and grab return value light_LED(0); SET(hw_done); export_state_HVM(); wait_export_complete_HVM(); hw_ret_val = get_HVM_return_value(); // Display return value printf("DAEMON: Thread id %u (running in HW) returned %d\n", hw_tid, hw_ret_val); // Check to see if any SW threads exist that can now be run in HW for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (software_interpreter_list[tcb_index].valid) break; } // If a valid SW thread exists, begin it's export process so that it can be migrated (otherwise, make the HW available again) if (tcb_index < MAX_SW_THREAD) { SET(software_interpreter_list[tcb_index].entry.communication.control.start_exporting); } else { printf("DAEMON: HW is available for the taking!\n"); SET(hw_available); } } // If there is new bytecode available to execute, then process it. if (ISSET(dc->new_code)) { // Increment the TID counter next_tid++; // If told to run this thread in HW, check to see if we need to force the HW to be available (migrating a thread from HW to SW) if (ISSET(dc->in_hw)) { // Check to see if HW is even available if (!ISSET(hw_available) & !ISSET(hw_done)) { // It's not, so we must make it available // export hardware to software, if needed printf("DAEMON: Migrating thread id %u from HW to SW...", hw_tid); // Stop HVM and export its state light_LED(0); export_state_HVM(); //wait_export_complete_HVM(); // This function waits for exported PC to be all F's and this won't be the case in a pre-empted program delay(99999999); // Use a delay instead to wait for export process to finish printf("COMPLETE\n"); // migrate HW state to import buffer (registers now, and program/stack later - just below) migrate_HVM_registers_to_buffer(&import_buffer); // create new SW based on import buffer // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = hw_tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); // Copy program/state to interpreter memory space //memcpy(software_interpreter_list[tcb_index].memory, dc->new_code_address, dc->new_code_size); memcpy(software_interpreter_list[tcb_index].memory, hvm_prog_mem, get_current_SP_HVM()); //start_software_interpreter(); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point_import, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } // Set HW available flag, so the new thread falls through and is created by the code below SET(hw_available); } else if (!ISSET(hw_available) & ISSET(hw_done)) { // If its not available, but the thread in HW is complete, then there is no need to migrate the thread... // Just change the availalbility flag for the code below to take care of SET(hw_available); } } // TODO: I don't think we need this else, now. The dc->in_hw flag just forces a // hw -> sw migration, making the hw available to the new thread. // If HW available, run the thread in HW if ISSET(hw_available) { // De-asser ready flag UNSET(hw_available); // Download fresh code hw_tid = next_tid; printf("DAEMON: Started thread id %u in HW\n", hw_tid); load_memory(hvm_prog_mem, dc->new_code_size, dc->new_code_address); // Reset and run the interpreter reset_HVM(); light_LED(hw_tid); UNSET(hw_done); run_HVM(); } // Otherwise run the thread in SW else { // This bytecode will run in software. Therefore it needs // to given a TCB in the software interpreter list. // Find an invalid TCB. for (tcb_index = 0; tcb_index < MAX_SW_THREAD; tcb_index++) { if (! ISSET(software_interpreter_list[tcb_index].valid)) break; } // If an available TCB is found, then tcb_index must be less // then MAX_SW_THREAD. if (tcb_index < MAX_SW_THREAD) { // If an invalid TCB exists, initialize it and start // the software interpreter. // Initialize software_interpreter_list[tcb_index] new_tcb = &software_interpreter_list[tcb_index].entry; new_tcb->tid = next_tid; new_tcb->virtualization.base_addr = software_interpreter_list[tcb_index].memory; new_tcb->communication.data.export_buffer_addr = & export_buffer; new_tcb->communication.data.import_buffer_addr = & import_buffer; UNSET(new_tcb->communication.control.done_interpreting); UNSET(new_tcb->communication.control.start_exporting); UNSET(new_tcb->communication.control.done_exporting); SET(software_interpreter_list[tcb_index].valid); memcpy(software_interpreter_list[tcb_index].memory, dc->new_code_address, dc->new_code_size); //start_software_interpreter(); printf("DAEMON: Started thread id %u in SW\n", next_tid); rv = hthread_create(&junk_tid, NULL, interpreter_entry_point, (void *)&(software_interpreter_list[tcb_index].entry)); } else { // If the software_interpreter_list is full, issue an error message. fprintf(stderr, "Preallocated TCB list is full.\n"); } } // Unset the new_code flag UNSET(dc->new_code); }
void setup() { serial_buffer_head = serial_buffer; serial_buffer_tail = serial_buffer; serial_overflow = false; debug_value = 0x1337; arch_setup_start(); enabled_pins = NUM_DIGITAL_PINS; for (uint8_t p = 0; p < NUM_DIGITAL_PINS; ++p) { pin[p].duty = 255; // Reset state is unset, then unset the pin. pin[p].state = CTRL_UNSET << 2 | CTRL_RESET; UNSET(p); } pin_events = 0; notified_current_fragment = 0; current_fragment = notified_current_fragment; last_fragment = current_fragment; filling = 0; // Disable all adcs. for (uint8_t a = 0; a < NUM_ANALOG_INPUTS; ++a) { for (uint8_t i = 0; i < 2; ++i) { adc[a].linked[i] = ~0; adc[a].value[i] = 1 << 15; adc[a].is_on = false; } } adc_phase = INACTIVE; adc_current = ~0; adc_next = ~0; // Set up communication state. command_end = 0; had_data = false; ping = 0; out_busy = 0; ff_in = 0; ff_out = 0; reply_ready = 0; adcreply_ready = 0; timeout = false; timeout_time = 0; // Set up homing state. homers = 0; home_step_time = 0; // Set up movement state. last_len = 0; stopping = -1; arch_set_speed(0); current_len = 0; active_motors = 0; move_phase = 0; full_phase = 1; // Set up led state. led_fast = 0; led_last = millis(); led_phase = 0; led_pin = ~0; stop_pin = ~0; probe_pin = ~0; spiss_pin = ~0; audio = 0; audio_motor = 0; // Do arch-specific things. This fills printerid and uuid. arch_setup_end(); // Inform host of reset. send_id(CMD_STARTUP); }
/* Move text from the current linestruct into the cutbuffer. If * copy_text is TRUE, copy the text back into the linestruct afterward. * If cut_till_eof is TRUE, move all text from the current cursor * position to the end of the file into the cutbuffer. */ void do_cut_text( #ifndef NANO_TINY bool copy_text, bool cut_till_eof, bool undoing #else void #endif ) { #ifndef NANO_TINY linestruct *cb_save = NULL; /* The current end of the cutbuffer, before we add text to * it. */ size_t cb_save_len = 0; /* The length of the string at the current end of the cutbuffer, * before we add text to it. */ bool old_no_newlines = ISSET(NO_NEWLINES); #endif assert(openfile->current != NULL && openfile->current->data != NULL); /* If keep_cutbuffer is FALSE and the cutbuffer isn't empty, blow * away the text in the cutbuffer. */ if (!keep_cutbuffer && cutbuffer != NULL) { free_filestruct(cutbuffer); cutbuffer = NULL; #ifdef DEBUG fprintf(stderr, "Blew away cutbuffer =)\n"); #endif } #ifndef NANO_TINY if (copy_text) { if (cutbuffer != NULL) { /* If the cutbuffer isn't empty, save where it currently * ends. This is where we'll add the new text. */ cb_save = cutbottom; cb_save_len = strlen(cutbottom->data); } /* Set NO_NEWLINES to TRUE, so that we don't disturb the last * line of the file when moving text to the cutbuffer. */ SET(NO_NEWLINES); } #endif /* Set keep_cutbuffer to TRUE, so that the text we're going to move * into the cutbuffer will be added to the text already in the * cutbuffer instead of replacing it. */ keep_cutbuffer = TRUE; #ifndef NANO_TINY if (cut_till_eof) { /* If cut_till_eof is TRUE, move all text up to the end of the * file into the cutbuffer. */ cut_to_eof(); } else if (openfile->mark_set) { /* If the mark is on, move the marked text to the cutbuffer, and * turn the mark off. */ cut_marked(); openfile->mark_set = FALSE; } else if (ISSET(CUT_TO_END)) /* If the CUT_TO_END flag is set, move all text up to the end of * the line into the cutbuffer. */ cut_to_eol(); else #endif /* Move the entire line into the cutbuffer. */ cut_line(); #ifndef NANO_TINY if (copy_text) { /* Copy the text in the cutbuffer, starting at its saved end if * there is one, back into the linestruct. This effectively * uncuts the text we just cut without marking the file as * modified. */ if (cutbuffer != NULL) { if (cb_save != NULL) { cb_save->data += cb_save_len; copy_from_filestruct(cb_save); cb_save->data -= cb_save_len; } else copy_from_filestruct(cutbuffer); /* Set the current place we want to where the text from the * cutbuffer ends. */ openfile->placewewant = xplustabs(); } /* Set NO_NEWLINES back to what it was before, since we're done * disturbing the text. */ if (!old_no_newlines) UNSET(NO_NEWLINES); } else if (!undoing) update_undo(cut_till_eof ? CUT_EOF : CUT); /* Leave the text in the cutbuffer, and mark the file as * modified. */ if (!copy_text) #endif /* !NANO_TINY */ set_modified(); /* Update the screen. */ edit_refresh_needed = TRUE; #ifndef DISABLE_COLOR reset_multis(openfile->current, FALSE); #endif #ifdef DEBUG dump_filestruct(cutbuffer); #endif }
/* Parse the rcfile, once it has been opened successfully at rcstream, * and close it afterwards. If syntax_only is TRUE, only allow the file * to contain color syntax commands: syntax, color, and icolor. */ void parse_rcfile(FILE *rcstream #ifdef ENABLE_COLOR , bool syntax_only #endif ) { char *buf = NULL; ssize_t len; size_t n; while ((len = getline(&buf, &n, rcstream)) > 0) { char *ptr, *keyword, *option; int set = 0; size_t i; /* Ignore the newline. */ if (buf[len - 1] == '\n') buf[len - 1] = '\0'; lineno++; ptr = buf; while (isblank(*ptr)) ptr++; /* If we have a blank line or a comment, skip to the next * line. */ if (*ptr == '\0' || *ptr == '#') continue; /* Otherwise, skip to the next space. */ keyword = ptr; ptr = parse_next_word(ptr); /* Try to parse the keyword. */ if (strcasecmp(keyword, "set") == 0) { #ifdef ENABLE_COLOR if (syntax_only) rcfile_error( N_("Command \"%s\" not allowed in included file"), keyword); else #endif set = 1; } else if (strcasecmp(keyword, "unset") == 0) { #ifdef ENABLE_COLOR if (syntax_only) rcfile_error( N_("Command \"%s\" not allowed in included file"), keyword); else #endif set = -1; } #ifdef ENABLE_COLOR else if (strcasecmp(keyword, "include") == 0) { if (syntax_only) rcfile_error( N_("Command \"%s\" not allowed in included file"), keyword); else parse_include(ptr); } else if (strcasecmp(keyword, "syntax") == 0) { if (endsyntax != NULL && endcolor == NULL) rcfile_error(N_("Syntax \"%s\" has no color commands"), endsyntax->desc); parse_syntax(ptr); } else if (strcasecmp(keyword, "header") == 0) parse_headers(ptr); else if (strcasecmp(keyword, "color") == 0) parse_colors(ptr, FALSE); else if (strcasecmp(keyword, "icolor") == 0) parse_colors(ptr, TRUE); else if (strcasecmp(keyword, "bind") == 0) parse_keybinding(ptr); #endif /* ENABLE_COLOR */ else rcfile_error(N_("Command \"%s\" not understood"), keyword); if (set == 0) continue; if (*ptr == '\0') { rcfile_error(N_("Missing flag")); continue; } option = ptr; ptr = parse_next_word(ptr); for (i = 0; rcopts[i].name != NULL; i++) { if (strcasecmp(option, rcopts[i].name) == 0) { #ifdef DEBUG fprintf(stderr, "parse_rcfile(): name = \"%s\"\n", rcopts[i].name); #endif if (set == 1) { if (rcopts[i].flag != 0) /* This option has a flag, so it doesn't take an * argument. */ SET(rcopts[i].flag); else { /* This option doesn't have a flag, so it takes * an argument. */ if (*ptr == '\0') { rcfile_error( N_("Option \"%s\" requires an argument"), rcopts[i].name); break; } option = ptr; if (*option == '"') option++; ptr = parse_argument(ptr); option = mallocstrcpy(NULL, option); #ifdef DEBUG fprintf(stderr, "option = \"%s\"\n", option); #endif /* Make sure option is a valid multibyte * string. */ if (!is_valid_mbstring(option)) { rcfile_error( N_("Option is not a valid multibyte string")); break; } #ifndef DISABLE_OPERATINGDIR if (strcasecmp(rcopts[i].name, "operatingdir") == 0) operating_dir = option; else #endif #ifndef DISABLE_WRAPJUSTIFY if (strcasecmp(rcopts[i].name, "fill") == 0) { if (!parse_num(option, &wrap_at)) { rcfile_error( N_("Requested fill size \"%s\" is invalid"), option); wrap_at = -CHARS_FROM_EOL; } else free(option); } else #endif #ifndef NANO_TINY if (strcasecmp(rcopts[i].name, "matchbrackets") == 0) { matchbrackets = option; if (has_blank_mbchars(matchbrackets)) { rcfile_error( N_("Non-blank characters required")); free(matchbrackets); matchbrackets = NULL; } } else if (strcasecmp(rcopts[i].name, "whitespace") == 0) { whitespace = option; if (mbstrlen(whitespace) != 2 || strlenpt(whitespace) != 2) { rcfile_error( N_("Two single-column characters required")); free(whitespace); whitespace = NULL; } else { whitespace_len[0] = parse_mbchar(whitespace, NULL, NULL); whitespace_len[1] = parse_mbchar(whitespace + whitespace_len[0], NULL, NULL); } } else #endif #ifndef DISABLE_JUSTIFY if (strcasecmp(rcopts[i].name, "punct") == 0) { punct = option; if (has_blank_mbchars(punct)) { rcfile_error( N_("Non-blank characters required")); free(punct); punct = NULL; } } else if (strcasecmp(rcopts[i].name, "brackets") == 0) { brackets = option; if (has_blank_mbchars(brackets)) { rcfile_error( N_("Non-blank characters required")); free(brackets); brackets = NULL; } } else if (strcasecmp(rcopts[i].name, "quotestr") == 0) quotestr = option; else #endif #ifndef NANO_TINY if (strcasecmp(rcopts[i].name, "backupdir") == 0) backup_dir = option; else #endif #ifndef DISABLE_SPELLER if (strcasecmp(rcopts[i].name, "speller") == 0) alt_speller = option; else #endif if (strcasecmp(rcopts[i].name, "tabsize") == 0) { if (!parse_num(option, &tabsize) || tabsize <= 0) { rcfile_error( N_("Requested tab size \"%s\" is invalid"), option); tabsize = -1; } else free(option); } else assert(FALSE); } #ifdef DEBUG fprintf(stderr, "flag = %ld\n", rcopts[i].flag); #endif } else if (rcopts[i].flag != 0) UNSET(rcopts[i].flag); else rcfile_error(N_("Cannot unset flag \"%s\""), rcopts[i].name); break; } } if (rcopts[i].name == NULL) rcfile_error(N_("Unknown flag \"%s\""), option); } #ifdef ENABLE_COLOR if (endsyntax != NULL && endcolor == NULL) rcfile_error(N_("Syntax \"%s\" has no color commands"), endsyntax->desc); #endif free(buf); fclose(rcstream); lineno = 0; check_vitals_mapped(); return; }
/* Our main file browser function. path is the tilde-expanded path we * start browsing from. */ char *do_browser(char *path, DIR *dir) { char *retval = NULL; int kbinput; bool old_const_update = ISSET(CONST_UPDATE); char *prev_dir = NULL; /* The directory we were in before backing up to "..". */ char *ans = NULL; /* The last answer the user typed at the statusbar prompt. */ size_t old_selected; /* The selected file we had before the current selected file. */ functionptrtype func; /* The function of the key the user typed in. */ curs_set(0); blank_statusbar(); bottombars(MBROWSER); wnoutrefresh(bottomwin); UNSET(CONST_UPDATE); ans = mallocstrcpy(NULL, ""); change_browser_directory: /* We go here after we select a new directory. */ /* Start with no key pressed. */ kbinput = ERR; path = mallocstrassn(path, get_full_path(path)); /* Save the current path in order to be used later. */ path_save = path; assert(path != NULL && path[strlen(path) - 1] == '/'); /* Get the file list, and set longest and width in the process. */ browser_init(path, dir); assert(filelist != NULL); /* Sort the file list. */ qsort(filelist, filelist_len, sizeof(char *), diralphasort); /* If prev_dir isn't NULL, select the directory saved in it, and * then blow it away. */ if (prev_dir != NULL) { browser_select_dirname(prev_dir); free(prev_dir); prev_dir = NULL; /* Otherwise, select the first file or directory in the list. */ } else selected = 0; old_selected = (size_t)-1; titlebar(path); while (TRUE) { struct stat st; int i; size_t fileline = selected / width; /* The line number the selected file is on. */ char *new_path; /* The path we switch to at the "Go to Directory" * prompt. */ /* Display the file list if we don't have a key, or if the * selected file has changed, and set width in the process. */ if (kbinput == ERR || old_selected != selected) browser_refresh(); old_selected = selected; kbinput = get_kbinput(edit); #ifndef NANO_TINY if (kbinput == KEY_WINCH) { kbinput = ERR; curs_set(0); continue; } #endif #ifndef DISABLE_MOUSE if (kbinput == KEY_MOUSE) { int mouse_x, mouse_y; /* We can click on the edit window to select a * filename. */ if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == 0 && wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) { /* longest is the width of each column. There * are two spaces between each column. */ selected = (fileline / editwinrows) * (editwinrows * width) + (mouse_y * width) + (mouse_x / (longest + 2)); /* If they clicked beyond the end of a row, * select the last filename in that row. */ if (mouse_x > width * (longest + 2)) selected--; /* If we're off the screen, select the last filename. */ if (selected > filelist_len - 1) selected = filelist_len - 1; /* If we selected the same filename as last time, * put back the Enter key so that it's read in. */ if (old_selected == selected) unget_kbinput(sc_seq_or(do_enter_void, 0), FALSE, FALSE); } } #endif /* !DISABLE_MOUSE */ func = parse_browser_input(&kbinput); if (func == total_refresh) { total_redraw(); } else if (func == do_help_void) { #ifndef DISABLE_HELP do_help_void(); /* Perhaps the window dimensions have changed. */ browser_refresh(); curs_set(0); #else nano_disabled_msg(); #endif } else if (func == do_search) { /* Search for a filename. */ curs_set(1); do_filesearch(); curs_set(0); } else if (func == do_research) { /* Search for another filename. */ do_fileresearch(); } else if (func == do_page_up) { if (selected >= (editwinrows + fileline % editwinrows) * width) selected -= (editwinrows + fileline % editwinrows) * width; else selected = 0; } else if (func == do_page_down) { selected += (editwinrows - fileline % editwinrows) * width; if (selected > filelist_len - 1) selected = filelist_len - 1; } else if (func == do_first_file) { selected = 0; } else if (func == do_last_file) { selected = filelist_len - 1; } else if (func == goto_dir_void) { /* Go to a specific directory. */ curs_set(1); i = do_prompt(TRUE, #ifndef DISABLE_TABCOMP FALSE, #endif MGOTODIR, ans, #ifndef DISABLE_HISTORIES NULL, #endif /* TRANSLATORS: This is a prompt. */ browser_refresh, _("Go To Directory")); curs_set(0); bottombars(MBROWSER); /* If the directory begins with a newline (i.e. an * encoded null), treat it as though it's blank. */ if (i < 0 || *answer == '\n') { /* We canceled. Indicate that on the statusbar, and * blank out ans, since we're done with it. */ statusbar(_("Cancelled")); ans = mallocstrcpy(ans, ""); continue; } else if (i != 0) { /* Put back the "Go to Directory" key and save * answer in ans, so that the file list is displayed * again, the prompt is displayed again, and what we * typed before at the prompt is displayed again. */ unget_kbinput(sc_seq_or(do_gotolinecolumn_void, 0), FALSE, FALSE); ans = mallocstrcpy(ans, answer); continue; } /* We have a directory. Blank out ans, since we're done * with it. */ ans = mallocstrcpy(ans, ""); /* Convert newlines to nulls, just before we go to the * directory. */ sunder(answer); align(&answer); new_path = real_dir_from_tilde(answer); if (new_path[0] != '/') { new_path = charealloc(new_path, strlen(path) + strlen(answer) + 1); sprintf(new_path, "%s%s", path, answer); } #ifndef DISABLE_OPERATINGDIR if (check_operating_dir(new_path, FALSE)) { statusbar(_("Can't go outside of %s in restricted mode"), operating_dir); free(new_path); continue; } #endif dir = opendir(new_path); if (dir == NULL) { /* We can't open this directory for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), answer, strerror(errno)); beep(); free(new_path); continue; } /* Start over again with the new path value. */ free(path); path = new_path; goto change_browser_directory; } else if (func == do_up_void) { if (selected >= width) selected -= width; } else if (func == do_down_void) { if (selected + width <= filelist_len - 1) selected += width; } else if (func == do_left) { if (selected > 0) selected--; } else if (func == do_right) { if (selected < filelist_len - 1) selected++; } else if (func == do_enter_void) { /* We can't move up from "/". */ if (strcmp(filelist[selected], "/..") == 0) { statusbar(_("Can't move up a directory")); beep(); continue; } #ifndef DISABLE_OPERATINGDIR /* Note: The selected file can be outside the operating * directory if it's ".." or if it's a symlink to a * directory outside the operating directory. */ if (check_operating_dir(filelist[selected], FALSE)) { statusbar(_("Can't go outside of %s in restricted mode"), operating_dir); beep(); continue; } #endif if (stat(filelist[selected], &st) == -1) { /* We can't open this file for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected], strerror(errno)); beep(); continue; } if (!S_ISDIR(st.st_mode)) { /* We've successfully opened a file, we're done, so * get out. */ retval = mallocstrcpy(NULL, filelist[selected]); break; } else if (strcmp(tail(filelist[selected]), "..") == 0) /* We've successfully opened the parent directory, * save the current directory in prev_dir, so that * we can easily return to it by hitting Enter. */ prev_dir = mallocstrcpy(NULL, striponedir(filelist[selected])); dir = opendir(filelist[selected]); if (dir == NULL) { /* We can't open this directory for some reason. * Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected], strerror(errno)); beep(); continue; } path = mallocstrcpy(path, filelist[selected]); /* Start over again with the new path value. */ goto change_browser_directory; } else if (func == do_exit) { /* Exit from the file browser. */ break; } } titlebar(NULL); edit_refresh(); curs_set(1); if (old_const_update) SET(CONST_UPDATE); free(path); free(ans); free_chararray(filelist, filelist_len); filelist = NULL; filelist_len = 0; return retval; }
/* Our main help-viewer function. */ void do_help(void) { int kbinput = ERR; bool old_no_help = ISSET(NO_HELP); size_t line = 0; /* The line number in help_text of the first displayed help * line. This variable is zero-based. */ size_t last_line = 0; /* The line number in help_text of the last help line. This * variable is zero-based. */ int oldmenu = currmenu; /* The menu we were called from. */ const char *ptr; /* The current line of the help text. */ size_t old_line = (size_t)-1; /* The line we were on before the current line. */ functionptrtype func; /* The function of the key the user typed in. */ /* Don't show a cursor in the help screen. */ curs_set(0); blank_edit(); blank_statusbar(); /* Set help_text as the string to display. */ help_init(); assert(help_text != NULL); if (ISSET(NO_HELP)) { /* Make sure that the help screen's shortcut list will actually * be displayed. */ UNSET(NO_HELP); window_init(); } bottombars(MHELP); wnoutrefresh(bottomwin); while (TRUE) { size_t i; ptr = help_text; /* Find the line number of the last line of the help text. */ for (last_line = 0; *ptr != '\0'; last_line++) { ptr += help_line_len(ptr); if (*ptr == '\n') ptr++; } if (last_line > 0) last_line--; /* Redisplay if the text was scrolled or an invalid key was pressed. */ if (line != old_line || kbinput == ERR) { blank_edit(); ptr = help_text; /* Advance in the text to the first line to be displayed. */ for (i = 0; i < line; i++) { ptr += help_line_len(ptr); if (*ptr == '\n') ptr++; } /* Now display as many lines as the window will hold. */ for (i = 0; i < editwinrows && *ptr != '\0'; i++) { size_t j = help_line_len(ptr); mvwaddnstr(edit, i, 0, ptr, j); ptr += j; if (*ptr == '\n') ptr++; } } wnoutrefresh(edit); old_line = line; lastmessage = HUSH; kbinput = get_kbinput(edit); #ifndef NANO_TINY if (kbinput == KEY_WINCH) { kbinput = ERR; continue; /* Redraw the screen. */ } #endif #ifndef DISABLE_MOUSE if (kbinput == KEY_MOUSE) { int mouse_x, mouse_y; get_mouseinput(&mouse_x, &mouse_y, TRUE); continue; /* Redraw the screen. */ } #endif func = parse_help_input(&kbinput); if (func == total_refresh) { total_redraw(); } else if (func == do_up_void) { if (line > 0) line--; } else if (func == do_down_void) { if (line + (editwinrows - 1) < last_line) line++; } else if (func == do_page_up) { if (line > editwinrows - 2) line -= editwinrows - 2; else line = 0; } else if (func == do_page_down) { if (line + (editwinrows - 1) < last_line) line += editwinrows - 2; } else if (func == do_first_line) { line = 0; } else if (func == do_last_line) { if (line + (editwinrows - 1) < last_line) line = last_line - (editwinrows - 1); } else if (func == do_exit) { /* Exit from the help viewer. */ break; } else unbound_key(kbinput); } if (old_no_help) { blank_bottombars(); wnoutrefresh(bottomwin); currmenu = oldmenu; SET(NO_HELP); window_init(); } else bottombars(oldmenu); #ifndef DISABLE_BROWSER if (oldmenu == MBROWSER || oldmenu == MWHEREISFILE || oldmenu == MGOTODIR) browser_refresh(); else #endif edit_refresh(); /* We're exiting from the help screen. */ free(help_text); }
/* Allocate space for the help text for the current menu, and concatenate * the different pieces of text into it. */ void help_init(void) { size_t allocsize = 0; /* Space needed for help_text. */ const char *htx[3]; /* Untranslated help introduction. We break it up into three chunks * in case the full string is too long for the compiler to handle. */ char *ptr; const subnfunc *f; const sc *s; #ifndef NANO_TINY bool old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); #endif /* First, set up the initial help text for the current function. */ if (currmenu == MWHEREIS || currmenu == MREPLACE || currmenu == MREPLACEWITH) { htx[0] = N_("Search Command Help Text\n\n " "Enter the words or characters you would like to " "search for, and then press Enter. If there is a " "match for the text you entered, the screen will be " "updated to the location of the nearest match for the " "search string.\n\n The previous search string will be " "shown in brackets after the search prompt. Hitting " "Enter without entering any text will perform the " "previous search. "); htx[1] = N_("If you have selected text with the mark and then " "search to replace, only matches in the selected text " "will be replaced.\n\n The following function keys are " "available in Search mode:\n\n"); htx[2] = NULL; } else if (currmenu == MGOTOLINE) { htx[0] = N_("Go To Line Help Text\n\n " "Enter the line number that you wish to go to and hit " "Enter. If there are fewer lines of text than the " "number you entered, you will be brought to the last " "line of the file.\n\n The following function keys are " "available in Go To Line mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } else if (currmenu == MINSERTFILE) { htx[0] = N_("Insert File Help Text\n\n " "Type in the name of a file to be inserted into the " "current file buffer at the current cursor " "location.\n\n If you have compiled nano with multiple " "file buffer support, and enable multiple file buffers " "with the -F or --multibuffer command line flags, the " "Meta-F toggle, or a nanorc file, inserting a file " "will cause it to be loaded into a separate buffer " "(use Meta-< and > to switch between file buffers). "); htx[1] = N_("If you need another blank buffer, do not enter " "any filename, or type in a nonexistent filename at " "the prompt and press Enter.\n\n The following " "function keys are available in Insert File mode:\n\n"); htx[2] = NULL; } else if (currmenu == MWRITEFILE) { htx[0] = N_("Write File Help Text\n\n " "Type the name that you wish to save the current file " "as and press Enter to save the file.\n\n If you have " "selected text with the mark, you will be prompted to " "save only the selected portion to a separate file. To " "reduce the chance of overwriting the current file with " "just a portion of it, the current filename is not the " "default in this mode.\n\n The following function keys " "are available in Write File mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #ifndef DISABLE_BROWSER else if (currmenu == MBROWSER) { htx[0] = N_("File Browser Help Text\n\n " "The file browser is used to visually browse the " "directory structure to select a file for reading " "or writing. You may use the arrow keys or Page Up/" "Down to browse through the files, and S or Enter to " "choose the selected file or enter the selected " "directory. To move up one level, select the " "directory called \"..\" at the top of the file " "list.\n\n The following function keys are available " "in the file browser:\n\n"); htx[1] = NULL; htx[2] = NULL; } else if (currmenu == MWHEREISFILE) { htx[0] = N_("Browser Search Command Help Text\n\n " "Enter the words or characters you would like to " "search for, and then press Enter. If there is a " "match for the text you entered, the screen will be " "updated to the location of the nearest match for the " "search string.\n\n The previous search string will be " "shown in brackets after the search prompt. Hitting " "Enter without entering any text will perform the " "previous search.\n\n"); htx[1] = N_(" The following function keys are available in " "Browser Search mode:\n\n"); htx[2] = NULL; } else if (currmenu == MGOTODIR) { htx[0] = N_("Browser Go To Directory Help Text\n\n " "Enter the name of the directory you would like to " "browse to.\n\n If tab completion has not been " "disabled, you can use the Tab key to (attempt to) " "automatically complete the directory name.\n\n The " "following function keys are available in Browser Go " "To Directory mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !DISABLE_BROWSER */ #ifndef DISABLE_SPELLER else if (currmenu == MSPELL) { htx[0] = N_("Spell Check Help Text\n\n " "The spell checker checks the spelling of all text in " "the current file. When an unknown word is " "encountered, it is highlighted and a replacement can " "be edited. It will then prompt to replace every " "instance of the given misspelled word in the current " "file, or, if you have selected text with the mark, in " "the selected text.\n\n The following function keys " "are available in Spell Check mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !DISABLE_SPELLER */ #ifndef NANO_TINY else if (currmenu == MEXTCMD) { htx[0] = N_("Execute Command Help Text\n\n " "This mode allows you to insert the output of a " "command run by the shell into the current buffer (or " "a new buffer in multiple file buffer mode). If you " "need another blank buffer, do not enter any " "command.\n\n The following function keys are " "available in Execute Command mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !NANO_TINY */ else { /* Default to the main help list. */ htx[0] = N_("Main nano help text\n\n " "The nano editor is designed to emulate the " "functionality and ease-of-use of the UW Pico text " "editor. There are four main sections of the editor. " "The top line shows the program version, the current " "filename being edited, and whether or not the file " "has been modified. Next is the main editor window " "showing the file being edited. The status line is " "the third line from the bottom and shows important " "messages. "); htx[1] = N_("The bottom two lines show the most commonly used " "shortcuts in the editor.\n\n Shortcuts are written as " "follows: Control-key sequences are notated with a '^' " "and can be entered either by using the Ctrl key or " "pressing the Esc key twice. Meta-key sequences are " "notated with 'M-' and can be entered using either the " "Alt, Cmd, or Esc key, depending on your keyboard setup. "); htx[2] = N_("Also, pressing Esc twice and then typing a " "three-digit decimal number from 000 to 255 will enter " "the character with the corresponding value. The " "following keystrokes are available in the main editor " "window. Alternative keys are shown in " "parentheses:\n\n"); } htx[0] = _(htx[0]); if (htx[1] != NULL) htx[1] = _(htx[1]); if (htx[2] != NULL) htx[2] = _(htx[2]); allocsize += strlen(htx[0]); if (htx[1] != NULL) allocsize += strlen(htx[1]); if (htx[2] != NULL) allocsize += strlen(htx[2]); /* Calculate the length of the shortcut help text. Each entry has * one or two keys, which fill 16 columns, plus translated text, * plus one or two \n's. */ for (f = allfuncs; f != NULL; f = f->next) if (f->menus & currmenu) allocsize += (16 * mb_cur_max()) + strlen(f->help) + 2; #ifndef NANO_TINY /* If we're on the main list, we also count the toggle help text. * Each entry has "M-%c\t\t", five chars which fill 16 columns, * plus a space, plus translated text, plus one or two '\n's. */ if (currmenu == MMAIN) { size_t endis_len = strlen(_("enable/disable")); for (s = sclist; s != NULL; s = s->next) if (s->scfunc == do_toggle_void) allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 8; } #endif /* Allocate space for the help text. */ help_text = charalloc(allocsize + 1); /* Now add the text we want. */ strcpy(help_text, htx[0]); if (htx[1] != NULL) strcat(help_text, htx[1]); if (htx[2] != NULL) strcat(help_text, htx[2]); ptr = help_text + strlen(help_text); /* Remember this end-of-introduction, start-of-shortcuts. */ end_of_intro = ptr; /* Now add our shortcut info. */ for (f = allfuncs; f != NULL; f = f->next) { int scsfound = 0; if ((f->menus & currmenu) == 0) continue; /* Let's simply show the first two shortcuts from the list. */ for (s = sclist; s != NULL; s = s->next) { if ((s->menus & currmenu) == 0) continue; if (s->scfunc == f->scfunc) { scsfound++; /* Make the first column narrower (6) than the second (10), * but allow it to spill into the second, for "M-Space". */ if (scsfound == 1) { sprintf(ptr, "%s ", s->keystr); /* Unicode arrows take three bytes instead of one. */ if (s->keystr[1] == '\xE2') ptr += 8; else ptr += 6; } else { ptr += sprintf(ptr, "(%s)\t", s->keystr); break; } } } if (scsfound == 0) ptr += sprintf(ptr, "\t\t"); else if (scsfound == 1) ptr += 10; /* The shortcut's help text. */ ptr += sprintf(ptr, "%s\n", _(f->help)); if (f->blank_after) ptr += sprintf(ptr, "\n"); } #ifndef NANO_TINY /* And the toggles... */ if (currmenu == MMAIN) { int maximum = 0, counter = 0; /* First see how many toggles there are. */ for (s = sclist; s != NULL; s = s->next) maximum = (s->toggle && s->ordinal > maximum) ? s->ordinal : maximum; /* Now show them in the original order. */ while (counter < maximum) { counter++; for (s = sclist; s != NULL; s = s->next) if (s->toggle && s->ordinal == counter) { ptr += sprintf(ptr, "%s\t\t%s %s\n", (s->menus == MMAIN ? s->keystr : ""), _(flagtostr(s->toggle)), _("enable/disable")); if (s->toggle == NO_COLOR_SYNTAX || s->toggle == TABS_TO_SPACES) ptr += sprintf(ptr, "\n"); break; } } } if (old_whitespace) SET(WHITESPACE_DISPLAY); #endif /* !NANO_TINY */ /* If all went well, we didn't overwrite the allocated space. */ assert(strlen(help_text) <= allocsize + 1); }
void received(){ UNSET(RECEIVED); bufferCursor = 0; }
/* Our main file browser function. path is the tilde-expanded path we * start browsing from. */ std::string do_browser(std::string path, DIR *dir) { std::string retval; bool old_const_update = ISSET(CONST_UPDATE); std::string prev_dir; /* The directory we were in before backing up to "..". */ std::string ans; /* The last answer the user typed at the statusbar prompt. */ size_t old_selected; /* The selected file we had before the current selected file. */ curs_set(0); blank_statusbar(); bottombars(MBROWSER); wnoutrefresh(bottomwin); UNSET(CONST_UPDATE); change_browser_directory: /* We go here after we select a new directory. */ path = get_full_path(path); assert(path.length() > 0 && path.back() == '/'); /* Get the file list, and set longest and width in the process. */ browser_init(path, dir); /* Sort the file list. */ std::sort(filelist.begin(), filelist.end(), sort_directories); /* If prev_dir isn't empty, select the directory saved in it, and then blow it away. */ if (prev_dir != "") { browser_select_filename(prev_dir); prev_dir = ""; /* Otherwise, select the first file or directory in the list. */ } else { selected = 0; } old_selected = (size_t)-1; titlebar(path); Key *kbinput = nullptr; while (true) { struct stat st; size_t fileline = selected / width; /* The line number the selected file is on. */ std::string new_path; /* The path we switch to at the "Go to Directory" prompt. */ if (kbinput) { delete kbinput; kbinput = nullptr; } /* Display the file list if we don't have a key, or if the * selected file has changed, and set width in the process. */ if (old_selected != selected) { browser_refresh(); } old_selected = selected; // Deal with the keyboard input kbinput = new Key(get_kbinput(edit)); auto func = func_from_key(*kbinput); if (func == total_refresh) { total_redraw(); } else if (func == do_help_void) { do_help_void(); curs_set(0); /* Search for a filename. */ } else if (func == do_search) { curs_set(1); do_filesearch(); curs_set(0); /* Search for another filename. */ } else if (func == do_research) { do_fileresearch(); } else if (func == do_page_up) { if (selected >= (editwinrows + fileline % editwinrows) * width) { selected -= (editwinrows + fileline % editwinrows) * width; } else { selected = 0; } } else if (func == do_page_down) { selected += (editwinrows - fileline % editwinrows) * width; if (selected > filelist.size() - 1) { selected = filelist.size() - 1; } } else if (func == do_first_file) { selected = 0; } else if (func == do_last_file) { selected = filelist.size() - 1; } else if (func == goto_dir_void) { /* Go to a specific directory. */ curs_set(1); std::shared_ptr<Key> key; PromptResult i = do_prompt(true, false, MGOTODIR, key, ans.c_str(), NULL, browser_refresh, _("Go To Directory")); curs_set(0); bottombars(MBROWSER); /* If the directory begins with a newline (i.e. an * encoded null), treat it as though it's blank. */ if (i == PROMPT_ABORTED || i == PROMPT_BLANK_STRING || answer.front() == '\n') { /* We canceled. Indicate that on the statusbar, and * blank out ans, since we're done with it. */ statusbar(_("Cancelled")); ans = ""; func = nullptr; continue; } else if (i != PROMPT_ENTER_PRESSED) { /* Put back the "Go to Directory" key and save * answer in ans, so that the file list is displayed * again, the prompt is displayed again, and what we * typed before at the prompt is displayed again. */ ans = answer; func = goto_dir_void; continue; } /* We have a directory. Blank out ans, since we're done with it. */ ans = ""; /* Convert newlines to nulls, just before we go to the directory. */ sunder(answer); new_path = real_dir_from_tilde(answer); if (new_path == "") { new_path = path + answer; } dir = opendir(new_path); if (dir == NULL) { /* We can't open this directory for some reason. Complain. */ statusbar(_("Error reading %s: %s"), answer.c_str(), strerror(errno)); beep(); func = nullptr; continue; } /* Start over again with the new path value. */ path = new_path; goto change_browser_directory; } else if (func == do_up_void) { if (selected >= width) { selected -= width; } } else if (func == do_left) { if (selected > 0) { selected--; } } else if (func == do_down_void) { if (selected + width <= filelist.size() - 1) { selected += width; } } else if (func == do_right) { if (selected < filelist.size() - 1) { selected++; } } else if (func == do_enter_void) { /* We can't move up from "/". */ if (filelist[selected] == "/..") { statusbar(_("Can't move up a directory")); beep(); func = nullptr; continue; } if (stat(filelist[selected], &st) == -1) { /* We can't open this file for some reason. Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected].c_str(), strerror(errno)); beep(); func = nullptr; continue; } if (!S_ISDIR(st.st_mode)) { /* We've successfully opened a file, we're done, so get out. */ retval = filelist[selected]; func = nullptr; break; } else if (tail(filelist[selected]) == "..") { /* We've successfully opened the parent directory, * save the current directory in prev_dir, so that * we can easily return to it by hitting Enter. */ prev_dir = striponedir(filelist[selected]); } dir = opendir(filelist[selected].c_str()); if (dir == NULL) { /* We can't open this directory for some reason. Complain. */ statusbar(_("Error reading %s: %s"), filelist[selected].c_str(), strerror(errno)); beep(); func = nullptr; continue; } path = filelist[selected]; /* Start over again with the new path value. */ goto change_browser_directory; } else if (func == do_exit) { /* Exit from the file browser. */ break; } func = nullptr; } if (kbinput) { delete kbinput; } titlebar(NULL); edit_refresh(); curs_set(1); if (old_const_update) { SET(CONST_UPDATE); } filelist.clear(); return retval; }
/* Load the recorded cursor positions for files that were edited. */ void load_poshistory(void) { FILE *hisfile = fopen(poshistname, "rb"); if (hisfile == NULL) { if (errno != ENOENT) { /* When reading failed, don't save history when we quit. */ UNSET(POSITIONLOG); history_error(N_("Error reading %s: %s"), poshistname, strerror(errno)); } } else { char *line = NULL, *lineptr, *xptr; size_t buf_len = 0; ssize_t read, count = 0; poshiststruct *record_ptr = NULL, *newrecord; /* Read and parse each line, and store the extracted data. */ while ((read = getline(&line, &buf_len, hisfile)) > 5) { /* Decode nulls as embedded newlines. */ unsunder(line, read); /* Find where the x index and line number are in the line. */ xptr = revstrstr(line, " ", line + read - 3); if (xptr == NULL) continue; lineptr = revstrstr(line, " ", xptr - 2); if (lineptr == NULL) continue; /* Now separate the three elements of the line. */ *(xptr++) = '\0'; *(lineptr++) = '\0'; /* Create a new position record. */ newrecord = (poshiststruct *)nmalloc(sizeof(poshiststruct)); newrecord->filename = mallocstrcpy(NULL, line); newrecord->lineno = atoi(lineptr); newrecord->xno = atoi(xptr); newrecord->next = NULL; /* Add the record to the list. */ if (position_history == NULL) position_history = newrecord; else record_ptr->next = newrecord; record_ptr = newrecord; /* Impose a limit, so the file will not grow indefinitely. */ if (++count > 200) { poshiststruct *drop_record = position_history; position_history = position_history->next; free(drop_record->filename); free(drop_record); } } fclose(hisfile); free(line); stat(poshistname, &stat_of_positions_file); } }