📄 ps_impl.c
字号:
pieces = PIECES_IN_TABLE(private); if (private->length == 0) { /* Special case occurring after everything replaced by nothing. */ ASSUME(pieces[0].pos == ES_INFINITY); if (count == 0) { /* Nothing replaced by nothing => leave well enough alone! */ return(private->position); } pieces[current = 0].pos = 0; goto Append_Only; } delta = get_current_offset(private); current = private->current; if (last_plus_one > private->position) { /* Replace a NON-empty region */ if (delta != 0) { /* Split the current piece at the insert point. */ pieces = split_piece(&private->pieces, current, delta); current++; } if (last_plus_one > PS_LAST_PLUS_ONE(pieces[current])) { /* Replace region spanning multiple pieces */ end_index = ft_bounding_index(&private->pieces, last_plus_one-1); /* -1 ensures that pieces[end_index] < last_plus_one, * preventing creation of a 0-length piece below. */ ASSERT(VALID_PIECE_INDEX(private, end_index)); } else { /* Replace region within a single piece */ end_index = current; } if (last_plus_one < PS_LAST_PLUS_ONE(pieces[end_index])) { /* Split the end piece at the last_plus_one point */ pieces = split_piece(&private->pieces, end_index, last_plus_one-pieces[end_index].pos); } /* Replace region now exactly equals [current..end_index] pieces. * Make sure all es_replace(scratch, ...) succeed before * modifying private->... (including pieces) any further. */ new_rec_insert = write_header_etc(scratch, private, last_plus_one, (long)count, buf, count_used, &es_temp, &delete_pieces_length, current, end_index+1); if (new_rec_insert == ES_CANNOT_SET) { goto Error_Return; } if (count == 0) { current--; /* Make ft_shift_out & ft_add_delta work */ } /* Recycle current piece, so don't shift it out */ ft_shift_out(&private->pieces, current+1, end_index+1); /* Meaning 2: total change to length */ delta = count - delete_pieces_length; } else if (count == 0) { /* Empty region replaced by nothing => leave well enough alone! * Not catching this case creates an extra 0-length piece. */ return(private->position); } else { /* Replace an empty region */ int at_end_of_stream = PS_IS_AT_END(private, delta, current); if (private->position == private->last_write_plus_one) { es_temp = es_replace(scratch, ES_INFINITY, count, buf, count_used); if (es_temp == ES_CANNOT_SET) { goto Error_Return; } ASSUME(count == *count_used); if (private->rec_insert_len == 0) { /* Last replace was a delete, so no scratch piece exists */ /* Split the current piece at the insert point */ pieces = split_piece(&private->pieces, current, delta); if (delta != 0) { ASSUME(at_end_of_stream); current++; delta = 0; } PS_SET_SCRATCH_SANDP(pieces[current], private->rec_insert+sizeof(long_temp)); } else if (at_end_of_stream) { /* Last replace was at end of stream => don't back up */ } else { ASSERT(delta == 0 && current > 0); current--; delta = private->position - pieces[current].pos; } ASSERT(delta == pieces[current].length); delta = count; /* Meaning 2: total change to length */ private->rec_insert_len += delta; pieces[current].length += delta; /* Correct the insert length (this is very inefficient) */ long_temp = private->rec_insert_len; es_temp = es_set_position(scratch, private->rec_insert); ASSERT(es_temp == private->rec_insert); es_temp = es_replace(scratch, private->rec_insert+sizeof(long_temp), sizeof(long_temp), (char *)&long_temp, &replace_used); } else { if (delta != 0) { /* Split the current piece at the insert point */ pieces = split_piece(&private->pieces, current, delta); current++; if (at_end_of_stream) { /* Append at the very end of the stream will create * a zero length piece which is unnecessary, so we * detect this case and recycle the piece. */ goto Append_Only; } } /* Handle the delta == 0 case. Create new piece */ pieces = split_piece(&private->pieces, current, 0L);Append_Only: /* Make sure all es_replace(scratch, ...) succeed before * modifying private->... (including pieces) any further. */ new_rec_insert = write_header_etc(scratch, private, last_plus_one, count, buf, count_used, &es_temp, (int *)0, -1, -1); if (new_rec_insert == ES_CANNOT_SET) { /* Reverse all damaging changes to pieces */ if (private->length == 0) { pieces[0].pos = ES_INFINITY; } else if (pieces[current].length == 0) { ft_shift_out(&private->pieces, current, current+1); } goto Error_Return; } delta = count; /* Meaning 2: total change to length */ } } /* Update (if necessary) the fields tracking the insert record. * Also fix up the associated piece fields. */ if (new_rec_insert != ES_INFINITY) { private->rec_insert = new_rec_insert; private->rec_insert_len = count; private->rec_start = scratch_length; if (private->oldest_not_undone_mark == ES_INFINITY) private->oldest_not_undone_mark = scratch_length; ASSUME(count == *count_used); if (count != 0) { pieces[current].length = count; ASSERT(es_temp == private->rec_insert+sizeof(long_temp)); PS_SET_SCRATCH_SANDP(pieces[current], es_temp); } } /* Adjust position, etc. to reflect the overall replace */ ft_add_delta(private->pieces, current+1, delta); private->length += delta; SET_POSITION(private, private->position + count); private->last_write_plus_one = private->position; ASSUME(0 <= private->position && private->position <= MAX_LENGTH); ASSUME(ps_pieces_are_consistent(private)); return(private->position);Error_Return: private->status = (Es_status)es_get(scratch, ES_STATUS); /* Copy scratch status first in case attempt to "back out" * failed es_replace's modify the status. */ (void) es_set_position(scratch, scratch_length); (void) es_replace(scratch, ES_INFINITY, 0, NULL, count_used); INVALIDATE_CURRENT(private); ASSUME(ps_pieces_are_consistent(private)); return(ES_CANNOT_SET);}static Es_indexwrite_record_header(esh, private, last_plus_one, dp_count) Es_handle esh; register Piece_table private; Es_index last_plus_one; int dp_count;{ struct piece_record_header r_header; register Es_index result; int replace_used; r_header.pos_prev_rec = private->rec_start; r_header.flags = 0; r_header.start = private->position; r_header.stop_plus_one = last_plus_one; r_header.dp_count = dp_count; result = es_replace(esh, ES_INFINITY, sizeof(r_header), (char *)&r_header, &replace_used); return(result);}static intrecord_deleted_pieces(esh, private, pieces, first, last_plus_one, next) Es_handle esh; Piece_table private; Piece pieces; int first, last_plus_one; Es_index *next;{ struct deleted_piece d_header; int dummy; register Piece current, stop_plus_one; register int result = 0; register Es_index replace_result; stop_plus_one = &pieces[last_plus_one]; for (current = &pieces[first]; current < stop_plus_one; current++) { d_header.source_and_pos = current->source_and_pos; result += (d_header.length = current->length); replace_result = es_replace(esh, ES_INFINITY, sizeof(d_header), (char *)&d_header, &dummy); if (replace_result == ES_CANNOT_SET) break; } *next = replace_result; return(result);}/* Returns the new value for private->rec_insert */static Es_indexwrite_header_etc(esh, private, last_plus_one, count, buf, count_used, contents_start, deleted_pieces_length, first_deleted, last_plus_one_deleted) register Es_handle esh; register Piece_table private; Es_index last_plus_one; long int count; long int *count_used; char *buf; Es_index *contents_start; int *deleted_pieces_length; int first_deleted, last_plus_one_deleted;{ register Es_index result; Es_index es_temp; int replace_used; /* Write the record header (and possibly) deleted pieces. */ result = write_record_header(esh, private, last_plus_one, last_plus_one_deleted-first_deleted); if (result == ES_CANNOT_SET) return(ES_CANNOT_SET); if (first_deleted < last_plus_one_deleted) { *deleted_pieces_length = record_deleted_pieces(esh, private, PIECES_IN_TABLE(private), first_deleted, last_plus_one_deleted, &es_temp); if (es_temp == ES_CANNOT_SET) return(ES_CANNOT_SET); result = es_temp; } *contents_start = es_replace(esh, ES_INFINITY, sizeof(count), (char *)&count, &replace_used); if (*contents_start == ES_CANNOT_SET) return(ES_CANNOT_SET); /* Do the insert */ if (count != 0) { es_temp = es_replace(esh, ES_INFINITY, count, buf, count_used); if (es_temp == ES_CANNOT_SET) return(ES_CANNOT_SET); } return(result);}static Es_handleps_pieces_for_span(esh, first, last_plus_one, to_recycle) Es_handle esh; Es_index first, last_plus_one; Es_handle to_recycle;{ register Piece_table private = ABS_TO_REP(esh); register Piece result_pieces; register int is_scratch; register Es_index delta, source_pos; int first_index, last_index; Es_handle result = (Es_handle)0; Piece_table r_private; if (last_plus_one > private->length) last_plus_one = private->length; if (first >= last_plus_one) { goto Bad_Args; } ASSUME(allock()); first_index = ft_bounding_index(&private->pieces, first); last_index = ft_bounding_index(&private->pieces, last_plus_one-1); if (to_recycle) { result = to_recycle; r_private = ABS_TO_REP(result); ASSUME(r_private->magic == PS_MAGIC && r_private->parent == esh); if (r_private->pieces.last_plus_one <= (last_index-first_index)) { ft_destroy(&r_private->pieces); /* Zeros .last_plus_one */ } } else { result = ps_NEW(0); if (result == (Es_handle)0) goto Out_Of_Memory; r_private = ABS_TO_REP(result); r_private->parent = esh; r_private->original = private->original; r_private->scratch = private->scratch; r_private->last_write_plus_one = r_private->rec_insert = r_private->rec_start = ES_CANNOT_SET; r_private->rec_insert_len = -1; } if (r_private->pieces.last_plus_one == 0) { r_private->pieces = FT_CLIENT_CREATE(last_index-first_index+1, Piece_object); if (r_private->pieces.seq == (Es_index *)0) goto Out_Of_Memory; } FT_CLEAR_ALL(r_private->pieces); copy_pieces(&r_private->pieces, 0, &private->pieces, first_index, last_index+1); /* * Fix up the end pieces. */ result_pieces = &PIECES_IN_TABLE(r_private)[last_index-first_index]; result_pieces->length = last_plus_one - result_pieces->pos; result_pieces = &PIECES_IN_TABLE(r_private)[0]; delta = first - result_pieces->pos; if (delta != 0) { result_pieces->pos = first; is_scratch = PS_SANDP_SOURCE(*result_pieces); source_pos = PS_SANDP_POS(*result_pieces); source_pos += delta; result_pieces->length -= delta; PS_SET_SANDP(*result_pieces, source_pos, is_scratch); } SET_POSITION(r_private, first); r_private->length = last_plus_one; ASSUME(allock()); return(result);Out_Of_Memory: if (result) { es_destroy(result); result = (Es_handle)0; }Bad_Args: if (to_recycle) es_destroy(to_recycle); return(result);}staticcopy_pieces(to_table, to_index, from_table, first, last_plus_one) register ft_handle to_table, from_table; int to_index, first, last_plus_one;{ register int sizeof_element = from_table->sizeof_element; ASSERT(to_table->sizeof_element == sizeof_element); bcopy((char *)from_table->seq + first*sizeof_element, (char *)to_table->seq + to_index*sizeof_element, (last_plus_one-first)*sizeof_element);}static intget_current_offset(private) register Piece_table private;{ register Piece current; register int result; if (private->current == CURRENT_NULL) private->current = ft_bounding_index(&private->pieces, private->position); ASSERT(VALID_PIECE_INDEX(private, private->current)); current = &PIECES_IN_TABLE(private)[private->current]; result = private->position - current->pos; ASSUME(result < current->length || PS_IS_AT_END(private, result, private->current) ); return(result);}static voidps_insert_pieces(esh, to_insert) Es_handle esh, to_insert;/* * Much of this routine is stolen from ps_replace. * A special convention established by this routine is that if the scratch * stream has a replace record with start == stop_plus_one and a non-zero * deleted piece count, then it is a result of inserting pieces, rather than * characters. */{ ft_handle rep = (ft_handle) &(ABS_TO_REP(to_insert))->pieces; long int long_temp; int at_end_of_stream, replace_used; long int delta; int save_last_plus_one; Es_index scratch_length, es_temp; register Piece pieces; register int current, last_valid; register Piece_table private = ABS_TO_REP(esh); register Es_handle scratch = private->scratch; ASSERT(rep != FT_NULL); last_valid = ft_bounding_index(rep, ES_INFINITY-1); ASSERT(last_valid != rep->last_plus_one); /* Prepare the insertion area. */ pieces = PIECES_IN_TABLE(private); if (private->length == 0 && pieces[0].pos == ES_INFINITY) { /* Special case that occurs if replaced everything by nothing. */ current = 0; delta = 0; at_end_of_stream = 1; pieces[0].pos = 0; pieces[0].length = 0; PS_SET_SCRATCH_SANDP(pieces[0], 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -