int center(buffer * const b) { line_desc * const ld = b->cur_line_desc; const int right_margin = b->opt.right_margin ? b->opt.right_margin : ne_columns; int64_t len, start_pos = 0, end_pos = ld->line_len; while(start_pos < ld->line_len && isasciispace(ld->line[start_pos])) start_pos = next_pos(ld->line, start_pos, b->encoding); if (start_pos == ld->line_len) return OK; while(isasciispace(ld->line[prev_pos(ld->line, end_pos, b->encoding)])) end_pos = prev_pos(ld->line, end_pos, b->encoding); len = b->encoding == ENC_UTF8 ? utf8strlen(&ld->line[start_pos], end_pos - start_pos) : end_pos - start_pos; if (len >= right_margin) return OK; b->cur_pos = -1; start_undo_chain(b); delete_stream(b, ld, b->cur_line, end_pos, ld->line_len - end_pos); delete_stream(b, ld, b->cur_line, 0, start_pos); insert_spaces(b, ld, b->cur_line, 0, (right_margin - len) / 2); end_undo_chain(b); return OK; }
/** @brief Frees a TCP stream **/ inline static void __tcp_free_stream ( pntoh_tcp_session_t session , pntoh_tcp_stream_t *stream , int reason , int extra ) { flush_peer_queues ( session , *stream , extra ); delete_stream ( session , stream , reason , extra ); return; }
int delete_sel_stream() { int i; for (i = 0; i < nr_cur_stream; i++) { if (g_apt_streams[i]->selected) { delete_stream(i); i--; } } return 0; }
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; }
int replace(buffer * const b, const int n, const char * const string) { int64_t len; assert(string != NULL); last_replace_empty_match = false; len = strlen(string); start_undo_chain(b); delete_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, n); if (len) insert_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, string, len); end_undo_chain(b); if (! b->opt.search_back) goto_pos(b, b->cur_pos + len); return OK; }
int replace_regexp(buffer * const b, const char * const string) { assert(string != NULL); bool reg_used = false; char *p, *q, *t = NULL; if (q = p = str_dup(string)) { int len = strlen(p); while(true) { while(*q && *q != '\\') q++; if (!*q) break; int i = *(q + 1) - '0'; if (*(q + 1) == '\\') { memmove(q, q + 1, strlen(q + 1) + 1); q++; len--; } else if (i >= 0 && i < RE_NREGS && re_reg.start[i] >= 0) { if (b->encoding == ENC_UTF8) { /* In the UTF-8 case, the replacement group index must be mapped through map_group to recover the real group. */ if ((i = map_group[i]) >= RE_NREGS) { free(p); return GROUP_NOT_AVAILABLE; } } *q++ = 0; *q++ = i; reg_used = true; } else { free(p); return WRONG_CHAR_AFTER_BACKSLASH; } } if (reg_used) { if (t = malloc(re_reg.end[0] - re_reg.start[0] + 1)) { memcpy(t, b->cur_line_desc->line + re_reg.start[0], re_reg.end[0] - re_reg.start[0]); t[re_reg.end[0] - re_reg.start[0]] = 0; } else { free(p); return OUT_OF_MEMORY; } } for(int i = re_reg.num_regs; i-- != 0;) { re_reg.end[i] -= re_reg.start[0]; re_reg.start[i] -= re_reg.start[0]; } start_undo_chain(b); delete_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, re_reg.end[0]); q = p; int64_t pos = 0; while(true) { if (strlen(q)) { insert_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos + pos, q, strlen(q)); pos += strlen(q); } q += strlen(q) + 1; if (q - p > len) break; assert(*q < RE_NREGS); if (re_reg.end[*(unsigned char *)q] - re_reg.start[*(unsigned char *)q]) { char c = t[re_reg.end[*(unsigned char *)q]]; t[re_reg.end[*(unsigned char *)q]] = 0; insert_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos + pos, t + re_reg.start[*(unsigned char *)q], re_reg.end[*(unsigned char *)q] - re_reg.start[*(unsigned char *)q]); t[re_reg.end[*(unsigned char *)q]] = c; pos += re_reg.end[*(unsigned char *)q] - re_reg.start[*(unsigned char *)q]; } q++; } end_undo_chain(b); if (! b->opt.search_back) goto_pos(b, b->cur_pos + pos); free(t); free(p); } else return OUT_OF_MEMORY; last_replace_empty_match = re_reg.start[0] == re_reg.end[0]; return OK; }
LRESULT CALLBACK stream_WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rect ; int cxClient, cyClient; static HMENU hMenu ; POINT point ; int ret, idx; TCHAR buf[64]; char file_name[MAX_FILE_PATH_LEN]; static int edit_iItem=-1 ; static int edit_iSubItem; LVITEM lv_item; switch (message) { case WM_CREATE: hwnd_stream= hwnd; hMenu = LoadMenu (g_hInstance, TEXT("my_popup_menu")) ; hMenu = GetSubMenu (hMenu, 0) ; hwnd_dynamic_edit=CreateWindow (TEXT("edit"), TEXT(""), WS_CHILD|ES_AUTOHSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwnd, (HMENU)ID_DYNAMIC_EDIT, g_hInstance, NULL) ; SendMessage(hwnd_dynamic_edit, WM_SETFONT, (WPARAM)char_font_2, 0); hwnd_lv = CreateListView(hwnd); //InitListViewImageLists(hwnd_lv); InitListViewColumns(hwnd_lv); lv_row_color_init(); old_lv_proc = (WNDPROC) SetWindowLong (hwnd_lv, GWL_WNDPROC, (LONG)my_lv_proc) ; ShowWindow(hwnd_lv, 1) ; refresh_window(hwnd_lv) ; add_tip(hwndTip, hwnd_lv, TEXT("点击鼠标右键进行操作")); return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; MoveWindow(hwnd_lv, 0, 0, cxClient, cyClient, TRUE) ; return 0 ; case WM_NOTIFY: { NMHDR *pt_nmhdr=(void *)lParam; switch(LOWORD(wParam)) { case ID_LV: // if code == NM_CLICK - Single click on an item if(pt_nmhdr->code == NM_CLICK || pt_nmhdr->code == NM_DBLCLK) { int iItem = ((LPNMITEMACTIVATE)lParam)->iItem; int iSubItem=((LPNMITEMACTIVATE)lParam)->iSubItem; if (iItem>=0 && ((iSubItem>=3 && iSubItem<=5) || iSubItem==7)) { ListView_GetSubItemRect(hwnd_lv,iItem,iSubItem,LVIR_LABEL,&rect); ListView_GetItemText(hwnd_lv, iItem, iSubItem, buf, sizeof(buf)); MoveWindow (hwnd_dynamic_edit ,rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE); SetWindowText(hwnd_dynamic_edit, buf); ShowWindow (hwnd_dynamic_edit, 1) ; SetFocus(hwnd_dynamic_edit); SendMessage(hwnd_dynamic_edit, EM_SETSEL, (WPARAM)0, (LPARAM)-1); edit_iItem = iItem; edit_iSubItem = iSubItem; } return 0; } else if (pt_nmhdr->code == NM_RCLICK) { point = ((LPNMITEMACTIVATE)lParam)->ptAction; ListView_GetItem(hwnd_lv, &lv_item); ClientToScreen (hwnd_lv, &point) ; TrackPopupMenu (hMenu, TPM_LEFTBUTTON, point.x, point.y, 0, hwnd_stream, NULL) ; return 0; } else if (pt_nmhdr->code == LVN_ITEMCHANGED) { if (!init_over) break; if (lv_in_op) break; //if((((LPNMLISTVIEW)lParam)->uOldState&LVIS_STATEIMAGEMASK) != // (((LPNMLISTVIEW)lParam)->uNewState&LVIS_STATEIMAGEMASK)) { int iItem = ((LPNMITEMACTIVATE)lParam)->iItem; int selected = ListView_GetCheckState(hwnd_lv, iItem); if (g_apt_streams[iItem]->selected!=selected) { doc_modified=1; g_apt_streams[iItem]->selected=selected; update_statusbar(); } } return 0; } break; } break; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_STREAM_NEW: init_stream(>_edit_stream); gt_edit_stream.len=gat_sample_pkts[0].len; memcpy(gt_edit_stream.data, gat_sample_pkts[0].pkt_data, gt_edit_stream.len); ret=DialogBox(g_hInstance, TEXT("STREAM_EDIT_DLG"), hwnd, StreamEditDlgProc); if (IDOK==ret) { add_stream(>_edit_stream); re_populate_items(); } return 0 ; case IDM_STREAM_NEW_HEX: { int len; char buf[MAX_PACKET_LEN]; if (get_open_file_name(file_name, hwnd, ALL_FILE_FILTER)) return 0; len = read_file_to_buf(buf, sizeof(buf)-1, file_name); if (len>0) add_stream_from_hex_text(buf, len); else err_msg_box("读取文件内容失败"); return 0 ; } case IDM_STREAM_NEW_BIN: { int len; char buf[MAX_PACKET_LEN]; if (get_open_file_name(file_name, hwnd, ALL_FILE_FILTER)) return 0; len = read_file_to_buf(buf, sizeof(buf)-1, file_name); if (len>0) add_stream_from_raw_data(buf, len); else err_msg_box("读取文件内容失败"); return 0 ; } case IDM_STREAM_NEW_PCAP: { if (get_open_file_name(file_name, hwnd, PCAP_FILE_FILTER)) return 0; add_stream_from_pcap(file_name); return 0 ; } case IDM_STREAM_DEL: idx=GetIndex(hwnd_lv); //ListView_DeleteItem(hwnd_lv, idx); delete_stream(idx); re_populate_items(); update_statusbar(); return 0 ; case IDM_STREAM_EDIT: cur_strm_idx=GetIndex(hwnd_lv); if (cur_strm_idx<0) return 0; cpy_stream(>_edit_stream, g_apt_streams[cur_strm_idx]); ret=DialogBox(g_hInstance, TEXT("STREAM_EDIT_DLG"), hwnd, StreamEditDlgProc); if (IDOK==ret) { doc_modified=1; cpy_stream(g_apt_streams[cur_strm_idx], >_edit_stream); re_populate_items(); } //ListView_DeleteAllItems(hwnd_lv); return 0 ; case IDM_STREAM_DEL_SEL: //DelSel(hwnd_lv); delete_sel_stream(); re_populate_items(); update_statusbar(); return 0 ; case IDM_STREAM_SEL_ALL: SelAll(hwnd_lv); return 0 ; case IDM_STREAM_SEL_RVS: SelRvs(hwnd_lv); return 0 ; case IDM_STREAM_COPY: copy_idx = GetIndex(hwnd_lv); return 0 ; case IDM_STREAM_PASTE: cpy_stream(>_edit_stream, g_apt_streams[copy_idx]); add_stream(>_edit_stream); re_populate_items(); return 0 ; case IDM_STREAM_MAKE_FRAGS: { ret=DialogBox(g_hInstance, TEXT("FRAG_DLG"), hwnd, FragDlgProc); return 0 ; } case IDM_STREAM_SEL2PCAP: { ret=get_save_file_name(file_name, hwnd, PCAP_FILE_FILTER, PCAP_FILE_SUFFIX); if (ret) return 0 ; stream2dump(file_name); update_pcap_file_history(file_name); return 0 ; } case IDM_STREAM_2_BIN: { ret=get_save_file_name(file_name, hwnd, BIN_FILE_FILTER, BIN_FILE_SUFFIX); if (ret) return 0 ; stream_2_bin(file_name); return 0 ; } case IDM_STREAM_2_TEXT: { ret=get_save_file_name(file_name, hwnd, TEXT_FILE_FILTER, TEXT_FILE_SUFFIX); if (ret) return 0 ; stream_2_text(file_name); return 0 ; } case ID_DYNAMIC_EDIT: if (HIWORD(wParam)==EN_KILLFOCUS) { update_grid_from_edit(edit_iItem, edit_iSubItem); edit_iItem=-1; return 0 ; } } break; case WM_KEYDOWN: if (VK_RETURN==wParam) { SetFocus(hwnd); return 0; } break; case WM_INITMENUPOPUP: { int idx=GetIndex(hwnd_lv); t_stream *pt_stream = g_apt_streams[idx]; int sel_cnt=GetSelCnt(hwnd_lv); int item_cnt=ListView_GetItemCount(hwnd_lv); if (lParam == 0) { UINT add_stream_menu_state = nr_cur_stream<MAX_STREAM_NUM ? MF_ENABLED : MF_GRAYED; EnableMenuItem ((HMENU) wParam, IDM_STREAM_NEW, add_stream_menu_state); EnableMenuItem ((HMENU) wParam, IDM_STREAM_NEW_HEX, add_stream_menu_state); EnableMenuItem ((HMENU) wParam, IDM_STREAM_NEW_BIN, add_stream_menu_state); EnableMenuItem ((HMENU) wParam, IDM_STREAM_NEW_PCAP, add_stream_menu_state); EnableMenuItem ((HMENU) wParam, IDM_STREAM_EDIT, idx>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_DEL, idx>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_COPY, idx>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_PASTE, copy_idx>=0 && item_cnt>copy_idx ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_DEL_SEL, sel_cnt ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_SEL_ALL, item_cnt ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_SEL_RVS, item_cnt ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_MAKE_FRAGS, idx>=0&&stream_fragable(pt_stream) ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_SEL2PCAP, sel_cnt ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_2_BIN, idx>=0 ? MF_ENABLED : MF_GRAYED); EnableMenuItem ((HMENU) wParam, IDM_STREAM_2_TEXT, idx>=0 ? MF_ENABLED : MF_GRAYED); return 0; } break; } } return DefWindowProc (hwnd, message, wParam, lParam) ; }
/** @brief API for add an incoming segment **/ int ntoh_tcp_add_segment ( pntoh_tcp_session_t session , pntoh_tcp_stream_t stream , struct ip *ip , size_t len , void *udata ) { size_t iphdr_len = 0; size_t tcphdr_len = 0; size_t payload_len = 0; struct tcphdr *tcp = 0; pntoh_tcp_peer_t origin = 0; pntoh_tcp_peer_t destination = 0; unsigned int tstamp = 0; int ret = NTOH_OK; pntoh_tcp_segment_t segment = 0; int who; if ( !stream || !session ) return NTOH_ERROR_PARAMS; /* verify IP header */ if ( !ip ) // no ip header return NTOH_INCORRECT_IPHEADER; if ( len <= sizeof(struct ip) ) // no data return NTOH_INCORRECT_LENGTH; if ( ( iphdr_len = 4 * ( ip->ip_hl ) ) < sizeof(struct ip) ) // incorrect ip header length return NTOH_INCORRECT_IP_HEADER_LENGTH; if ( len < ntohs( ip->ip_len ) ) // incorrect capture length return NTOH_NO_ENOUGH_DATA; if ( ip->ip_v != 4 ) // only handle IPv4 return NTOH_NOT_IPV4; /* check IP addresses */ if ( !( ( stream->client.addr == ip->ip_src.s_addr && stream->server.addr == ip->ip_dst.s_addr ) || ( stream->client.addr == ip->ip_dst.s_addr && stream->server.addr == ip->ip_src.s_addr ) )) return NTOH_IP_ADDRESSES_MISMATCH; if ( ip->ip_p != IPPROTO_TCP ) return NTOH_NOT_TCP; tcp = (struct tcphdr*) ( (unsigned char*)ip + iphdr_len ); /* check TCP header */ if ( ( tcphdr_len = tcp->th_off * 4 ) < sizeof(struct tcphdr) ) return NTOH_INCORRECT_TCP_HEADER_LENGTH; if ( !tcp->th_flags || tcp->th_flags == 0xFF ) return NTOH_INVALID_FLAGS; lock_access ( &stream->lock ); /* check TCP ports */ if ( !( ( tcp->th_dport == stream->tuple.dport && tcp->th_sport == stream->tuple.sport ) || ( tcp->th_dport == stream->tuple.sport && tcp->th_sport == stream->tuple.dport ) )) return NTOH_TCP_PORTS_MISMATCH; payload_len = ntohs(ip->ip_len) - iphdr_len - tcphdr_len; /* get origin and destination */ if ( stream->tuple.source == ip->ip_src.s_addr ) { origin = &stream->client; destination = &stream->server; who = NTOH_SENT_BY_CLIENT; }else{ origin = &stream->server; destination = &stream->client; who = NTOH_SENT_BY_SERVER; } get_timestamp ( tcp , tcphdr_len , &tstamp ); /* PAWS check */ if ( tstamp > 0 && origin->lastts > 0 ) { if ( tstamp < origin->lastts ) { ret = NTOH_PAWS_FAILED; goto exitp; } if ( ntohl(tcp->th_seq) <= origin->next_seq ) origin->lastts = tstamp; }else if ( tstamp > 0 && !(origin->lastts) ) origin->lastts = tstamp; if ( origin->next_seq > 0 && (origin->isn - ntohl ( tcp->th_seq ) ) < origin->next_seq ) { ret = NTOH_TOO_LOW_SEQ_NUMBER; goto exitp; } if ( destination->next_seq > 0 && (origin->ian - ntohl(tcp->th_ack) ) < destination->next_seq ) { ret = NTOH_TOO_LOW_ACK_NUMBER; goto exitp; } /* @todo some TCP/IP stacks implementations overloads the MSS on certain segments */ /*if ( origin->mss > 0 && payload_len > origin->mss ) return NTOH_SEGMENT_EXCEEDS_MSS;*/ /* switch between connection status */ switch ( stream->status ) { case NTOH_STATUS_CLOSED: case NTOH_STATUS_SYNSENT: case NTOH_STATUS_SYNRCV: if ( payload_len > 0 ) { ret = NTOH_HANDSHAKE_FAILED; goto exitp; } ret = handle_new_connection ( stream , tcp , origin , destination , udata ); if ( ret == NTOH_OK ) { if ( origin->receive ) { if ( stream->status == NTOH_STATUS_ESTABLISHED ) ((pntoh_tcp_callback_t)stream->function) ( stream , origin , destination , 0 , NTOH_REASON_SYNC , NTOH_REASON_ESTABLISHED ); else ((pntoh_tcp_callback_t)stream->function) ( stream , origin , destination , 0 , NTOH_REASON_SYNC , NTOH_REASON_SYNC ); } }else{ lock_access ( &session->lock ); delete_stream ( session , &stream , NTOH_REASON_SYNC , ret ); unlock_access ( &session->lock ); } break; case NTOH_STATUS_ESTABLISHED: ret = handle_established_connection ( session , stream , tcp , payload_len , origin , destination , udata, who ); break; default: segment = new_segment( ntohl ( tcp->th_seq ) - origin->isn , ntohl ( tcp->th_ack ) - origin->ian , payload_len , tcp->th_flags , udata ); handle_closing_connection ( session , stream , origin , destination , segment, who ); if ( stream->status == NTOH_STATUS_CLOSED ) { lock_access ( &session->lock ); __tcp_free_stream ( session , &stream , NTOH_REASON_SYNC , NTOH_REASON_CLOSED ); unlock_access ( &session->lock ); stream = 0; } break; } if ( ret == NTOH_OK ) { if ( stream != 0 ) gettimeofday ( & (stream->last_activ) , 0 ); if ( payload_len == 0 ) ret = NTOH_SYNCHRONIZING; } exitp: if ( stream != 0 ) unlock_access ( &stream->lock ); return ret; }
void delete_to_eol(buffer * const b, line_desc * const ld, const int64_t line, const int64_t pos) { if (!ld || pos >= ld->line_len) return; delete_stream(b, ld, line, pos, ld->line_len - pos); }
int shift(buffer * const b, char *p, char *msg, int msg_size) { const bool use_tabs = b->opt.tabs && b->opt.shift_tabs; const int64_t init_line = b->cur_line, init_pos = b->cur_pos, init_y = b->cur_y; line_desc *ld = NULL, *start_line_desc = NULL; int64_t shift_size = 1; char dir = '>'; int shift_mag = b->opt.tab_size, rc = 0; /* Parse parm p; looks like [<|>] ### [s|t], but we allow them in any order, once, with optional white space. */ if (p) { int dir_b = 0, size_b = 0, st_b = 0; while (*p) { if (isasciispace(*p)) p++; else if (!dir_b && (dir_b = (*p == '<' || *p == '>'))) dir = *p++; else if (!size_b && (size_b = isdigit((unsigned char)*p))) { errno = 0; shift_size = strtoll(p, &p, 10); if (errno) return INVALID_SHIFT_SPECIFIED; } else if (!st_b && (st_b = (*p == 's' || *p == 'S'))) { shift_mag = 1; p++; } else if (!st_b && (st_b = (*p == 't' || *p == 'T'))) p++; else return INVALID_SHIFT_SPECIFIED; } } shift_size *= max(1, shift_mag); if (shift_size == 0) return INVALID_SHIFT_SPECIFIED; int64_t first_line = b->cur_line, last_line = b->cur_line, left_col = 0; if (b->marking) { if (b->mark_is_vertical) left_col = min(calc_width(b->cur_line_desc, b->block_start_pos, b->opt.tab_size, b->encoding), calc_width(b->cur_line_desc, b->cur_pos, b->opt.tab_size, b->encoding)); first_line = min(b->block_start_line, b->cur_line); last_line = max(b->block_start_line, b->cur_line); } /* If we're shifting left (dir=='<'), verify that we have sufficient white space to remove on all the relevant lines before making any changes, i. */ if (dir == '<') { shift_size = -shift_size; /* signed shift_size now also indicates direction. */ for (int64_t line = first_line; !rc && line <= last_line; line++) { int64_t pos; goto_line(b, line); pos = calc_pos(b->cur_line_desc, left_col, b->opt.tab_size, b->encoding); while (pos < b->cur_line_desc->line_len && left_col - calc_width(b->cur_line_desc, pos, b->opt.tab_size, b->encoding) > shift_size) { if (isasciispace(b->cur_line_desc->line[pos])) pos = next_pos(b->cur_line_desc->line, pos, b->encoding); else { rc = INSUFFICIENT_WHITESPACE; break; } } } } if (!rc) { start_undo_chain(b); for (int64_t line = first_line; line <= last_line; line++) { int64_t pos, c_pos, c_col_orig, offset; b->attr_len = -1; goto_line(b, line); b->cur_pos = -1; ld = b->cur_line_desc; if (line == first_line) start_line_desc = ld; pos = calc_pos(ld, left_col, b->opt.tab_size, b->encoding); /* If left_col is in the middle of a tab, pos will be on that tab. */ /* whitespace adjustment strategy: 1. Starting from left_col, advance to the right to the first non-blank character C. 2. Note C's col. The desired new column is this value +/- shift_size. 3. Move left looking for the first tab or non-whitespace or the left_col, whichever comes first. Whitespace changes all take place at that transition point. 4. While C's col is wrong if C's col is too far to the right, if we're on a space, delete it; else if there's a tab to our left, delete it; else we should not have started, because it's not possible! if C's col is too far to the left, if its needs to be beyond the next tab stop, insert a tab and move right; else insert a space. */ /* 1. */ while (pos < ld->line_len && isasciispace(ld->line[pos])) pos = next_pos(ld->line, pos, b->encoding); if (pos >= ld->line_len) continue; /* We ran off the end of the line. */ /* line[pos] should be the first non-blank character. */ /* 2. */ c_pos = pos; c_col_orig = calc_width(ld, c_pos, b->opt.tab_size, b->encoding); /* 3. */ while (pos && ld->line[pos-1] == ' ') pos = prev_pos(ld->line, pos, b->encoding); /* If pos is non-zero, it should be on a blank, with only blanks between here and c_pos. */ /* 4. */ /* offset = how_far_we_have_moved - how_far_we_want_to_move. */ while (!stop && (offset = calc_width(ld, c_pos, b->opt.tab_size, b->encoding)-c_col_orig - shift_size)) { if (offset > 0) { /* still too far right; remove whitespace */ if (ld->line[pos] == ' ') { delete_stream(b, ld, b->cur_line, pos, 1); c_pos--; } else if (pos) { /* should be a tab just to our left */ pos = prev_pos(ld->line, pos, b->encoding); /* now we're on the tab */ if (ld->line[pos] == '\t') { delete_stream(b, ld, b->cur_line, pos, 1); c_pos--; } else break; /* Should have been a tab. This should never happen! Give up on this line and go mangle the next one. */ } else break; /* This should never happen; give up on this line and go mangle the next one. */ } else if (offset < 0) { /* too far left; insert whitespace */ char c = ' '; if (use_tabs && (b->opt.tab_size - calc_width(ld, pos, b->opt.tab_size, b->encoding) % b->opt.tab_size) <= -offset ) c = '\t'; if (insert_one_char(b, ld, b->cur_line, pos, c)) { break; } pos++; c_pos++; } } } end_undo_chain(b); if (b->syn) { b->attr_len = -1; need_attr_update = true; update_syntax_states(b, -1, start_line_desc, (line_desc *)ld->ld_node.next); } update_window_lines(b, b->top_line_desc, 0, ne_lines - 2, false); } /* put the screen back where way we found it. */ goto_line_pos(b, init_line, init_pos); delay_update(); const int64_t avshift = b->cur_y - init_y; if (avshift) { snprintf(msg, msg_size, "%c%" PRId64, avshift > 0 ? 'T' :'B', avshift > 0 ? avshift : -avshift); adjust_view(b, msg); } return rc; }
int paragraph(buffer * const b) { line_desc *ld = b->cur_line_desc, *start_line_desc = ld; if (!ld->line) return line_down(b); /* Establish appropriate leading space. This will be taken from the line following the current line if it is non-blank. Otherwise it will be taken from the current line. Save a copy of it for later as space[]. **/ if ( !( (ld->ld_node.next->next && save_space((line_desc *)ld->ld_node.next, b->opt.tab_size, b->encoding)) || save_space(ld, b->opt.tab_size, b->encoding) ) ) return line_down(b); int64_t pos = b->cur_pos; b->cur_pos = -1; start_undo_chain(b); /* This insertion and deletion of a single character ensures that the cursor ends up here after an undo. */ int64_t line = b->cur_line; insert_one_char(b, ld, line, 0, ' '); delete_stream(b, ld, line, 0, 1); const int right_margin = b->opt.right_margin ? b->opt.right_margin : ne_columns; bool done; do { done = true; /* set this to false if we do any work in the loop. */ trim_trailing_space(b, ld, line, b->encoding); /* Suck up subsequent lines until this one is long enough to need splitting */ while ((calc_width(ld, ld->line_len, b->opt.tab_size, b->encoding) <= right_margin) && ld->ld_node.next->next && is_part_of_paragraph((line_desc *)ld->ld_node.next, b->opt.tab_size, &pos, b->encoding)) { line_desc *ld_next = (line_desc *)ld->ld_node.next; insert_one_char(b, ld, line, ld->line_len, ' '); if (pos) delete_stream(b, ld_next, line + 1, 0, pos); /* pos was set by is_part_of_paragraph() above. */ delete_stream(b, ld, line, ld->line_len, 1); /* joins next line to this one */ trim_trailing_space(b, ld, line, b->encoding); done = false; } if (calc_width(ld, ld->line_len, b->opt.tab_size, b->encoding) > right_margin) { int64_t spaces; int64_t split_pos; /* Skip past leading spaces... */ pos = 0; while(pos < ld->line_len && isasciispace(ld->line[pos])) pos = next_pos(ld->line, pos, b->encoding); /* Find the split point */ split_pos = spaces = 0; while (pos < ld->line_len && (calc_width(ld, pos, b->opt.tab_size, b->encoding) < right_margin || ! split_pos)) { if (isasciispace(ld->line[pos])) { split_pos = pos; spaces = 0; while (pos < ld->line_len && isasciispace(ld->line[pos])) { pos = next_pos(ld->line, pos, b->encoding); spaces++; } } else pos = next_pos(ld->line, pos, b->encoding); } if (split_pos) { done = false; /* Remove any space at the split point. */ if (spaces) delete_stream(b, ld, line, split_pos, spaces); /* Split the line at the split point. (We are done with this line) */ insert_one_line(b, ld, line, split_pos); /* Make the new next line the current line **/ if (ld->ld_node.next->next) { ld = (line_desc *)ld->ld_node.next; line++; if (pa_space && pa_space_len && pa_space_pos) insert_stream(b, ld, line, 0, pa_space, pa_space_pos); trim_trailing_space(b, ld, line, b->encoding); } } else { /* Line not split; is there a next one in the paragraph? */ if ( ld->ld_node.next->next && is_part_of_paragraph((line_desc *)ld->ld_node.next, b->opt.tab_size, &pos, b->encoding) ) { ld = (line_desc *)ld->ld_node.next; line++; done = false; } } } } while (!stop && !done); end_undo_chain(b); if (pa_space) { free(pa_space); pa_space = NULL; } if (b->syn) { b->attr_len = -1; need_attr_update = true; update_syntax_states(b, -1, start_line_desc, (line_desc *)ld->ld_node.next); } update_window_lines(b, b->cur_line_desc, b->cur_y, ne_lines - 2, false); goto_line_pos(b, line, pos); if (stop || line_down(b) == ERROR) return stop ? STOPPED : ERROR; /* Try to find the first non-blank starting with this line. */ ld = b->cur_line_desc; line = b->cur_line; do { if (ld->line) { for (pos = 0; pos < ld->line_len; pos = next_pos(ld->line, pos, b->encoding)) { if (!isasciispace(ld->line[pos])) { goto_line_pos(b, line, pos); return ld->ld_node.next ? OK : ERROR; } } } ld = (line_desc *)ld->ld_node.next; line++; } while (ld->ld_node.next); return b->cur_line_desc->ld_node.next ? OK : ERROR; }
static void trim_trailing_space(buffer * const b, line_desc *ld, const int64_t line, const encoding_type encoding) { if (!ld->line) return; int64_t pos = ld->line_len; while (pos > 0 && isasciispace(ld->line[pos - 1])) pos = prev_pos(ld->line, pos, encoding); if (pos >= 0 && pos < ld->line_len) delete_stream(b, ld, line, pos, ld->line_len - pos); }
static int to_something(buffer *b, int (to_first)(int), int (to_rest)(int)) { assert_buffer(b); /* If we are after the end of the line, just return ERROR. */ if (b->cur_line == b->num_lines -1 && b->cur_pos >= b->cur_line_desc->line_len) return ERROR; int64_t pos = b->cur_pos; int c; /* First of all, we search for the word start, if we're not over it. */ if (pos >= b->cur_line_desc->line_len || !ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding)) if (search_word(b, 1) != OK) return ERROR; bool changed = false; int64_t new_len = 0; pos = b->cur_pos; const int64_t cur_char = b->cur_char; const int cur_x = b->cur_x; /* Then, we compute the word position extremes, length of the result (which may change because of casing). */ while (pos < b->cur_line_desc->line_len && ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding)) { const int new_c = new_len ? to_rest(c) : to_first(c); changed |= (c != new_c); if (b->encoding == ENC_UTF8) new_len += utf8seqlen(new_c); else new_len++; pos = next_pos(b->cur_line_desc->line, pos, b->encoding); } const int64_t len = pos - b->cur_pos; if (!len) { char_right(b); return OK; } if (changed) { /* We actually perform changes only if some character was case folded. */ char * word = malloc(new_len * sizeof *word); if (!word) return OUT_OF_MEMORY; pos = b->cur_pos; new_len = 0; /* Second pass: we actually build the transformed word. */ while (pos < b->cur_line_desc->line_len && ne_isword(c = get_char(&b->cur_line_desc->line[pos], b->encoding), b->encoding)) { if (b->encoding == ENC_UTF8) new_len += utf8str(new_len ? to_rest(c) : to_first(c), word + new_len); else { word[new_len] = new_len ? to_rest(c) : to_first(c); new_len++; } pos = next_pos(b->cur_line_desc->line, pos, b->encoding); } start_undo_chain(b); delete_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, len); if (new_len) insert_stream(b, b->cur_line_desc, b->cur_line, b->cur_pos, word, new_len); free(word); end_undo_chain(b); if (cur_char < b->attr_len) b->attr_len = cur_char; update_line(b, b->cur_line_desc, b->cur_y, cur_x, false); need_attr_update = true; } return search_word(b, 1); }