📄 ps_impl.c
字号:
private->scratch_position = private->scratch_ops->replace(esh, last_plus_one, count, buf, count_used); private->scratch_length = private->scratch_ops->get_length(esh); } else { first_valid = (SCRATCH_HAS_WRAPPED(private)) ? SCRATCH_FIRST_VALID(private) : 0; *count_used = count; /* * Either scratch stream has wrapped around, or it is about to * wrap around. In either case, the valid "logical" * scratch indices are [first_valid..scratch_length). * Bytes that vanish into hole at start of scratch stream are * treated as used. * Watch for: * a) range of characters that no longer exist, and * b) "split" around physical scratch end. * First, look to see if replace begins at valid position. */ remainder = first_valid - private->scratch_position; if (remainder > 0) { /* Invalid start, but may extend into valid positions. * Move position to start of valid range (which changes * private->scratch_position as a side-effect). */ (void) es_set_position(esh, first_valid); if (last_plus_one < first_valid) { /* Entire range to replace is invalid. */ goto Return; } else if (count > 0) { /* Discard any new bytes replacing invalid bytes. */ if (count > remainder) { count -= remainder; buf += remainder; } else { count = 0; } } } /* Second, look for "split" replace. */ if ((private->scratch_position / private->scratch_max_len) != ((max_lpo-1) / private->scratch_max_len) ) { /* Split => replace at end of scratch, then at start. * NOTE: caller guarantees that count > remainder */ remainder = private->scratch_max_len - private->scratch_ops->get_position(esh); ASSUME(count > remainder); (void) private->scratch_ops->replace( esh, private->scratch_max_len, remainder, buf, &count_replaced); (void) private->scratch_ops->set_position(esh, 0); (void) private->scratch_ops->replace( esh, count - remainder, count - remainder, buf + remainder, &count_replaced); } else { /* If here, then overwrite physical scratch after a wrap. */ (void) private->scratch_ops->replace( esh, (private->scratch_position % private->scratch_max_len) + count, count, buf, &count_replaced); } private->scratch_position += count; if (private->scratch_position > private->scratch_length) { private->scratch_length = private->scratch_position; } }Return: ASSUME(private->scratch_ops->get_position(esh) == (private->scratch_position % private->scratch_max_len)); return(private->scratch_position);}static Piecesplit_piece(pieces, current, delta) ft_handle pieces; register int current; register long int delta;/* Splits the piece_object pieces[current] in two with the second piece, the * new pieces[current+1], starting at pieces[current].pos+delta. * Returns a properly cast sequence, as old cached version may be invalidated * by the call to ft_shift_up. */{ register Piece old, new; register int is_scratch; register Es_index source_pos; ft_shift_up(pieces, current+1, current+2, 10); /* Can invalidate &pieces.seq[i] */ old = ((Piece)(pieces->seq)) + current; new = old + 1; is_scratch = PS_SANDP_SOURCE(old[0]); source_pos = PS_SANDP_POS(old[0]); new->pos = old->pos + delta; source_pos += delta; new->length = old->length - delta; old->length = delta; PS_SET_SANDP(new[0], source_pos, is_scratch); return((Piece)(pieces->seq));}static Es_indexps_read(esh, len, bufp, resultp) Es_handle esh; u_int len, *resultp; register char *bufp;{#ifdef DEBUG_TRACE Es_index next, pos; char temp; pos = (ABS_TO_REP(esh))->position; next = ps_debug_read(esh, len, bufp, resultp); (void) fprintf(stdout, "ps_read at pos %d of %d chars got %d chars; %s %d ...\n", pos, len, *resultp, "next read at", next);#ifdef DEBUG_TRACE_CONTENTS temp = bufp[*resultp]; bufp[*resultp] = '\0'; (void) fprintf(stdout, "%s\n^^^\n", bufp); bufp[*resultp] = temp;#endif return(next);}static Es_indexps_debug_read(esh, len, bufp, resultp) Es_handle esh; u_int len, *resultp; register char *bufp;{#endif/* * "current" must be signed, because it can become -1 when deciding whether * to combine pieces containing invalid physical scratch indices. */ int read_count, save_current; Es_index next_pos, original_len; register int current, to_read; register long int delta; register Es_index current_pos; register Es_handle current_esh; register Piece pieces; register Piece_table private = ABS_TO_REP(esh); if (private->length - private->position < len) { len = private->length - private->position; } pieces = PIECES_IN_TABLE(private); *resultp = 0; if (private->current == CURRENT_NULL) { current = ft_bounding_index(&private->pieces, private->position); } else current = private->current; while (VALID_PIECE_INDEX(private, current) && len > 0) { delta = private->position - pieces[current].pos; ASSERT(*resultp == 0 || delta == 0); current_esh = (PS_SANDP_SOURCE(pieces[current]) ? private->scratch : private->original); current_pos = PS_SANDP_POS(pieces[current]) + delta; next_pos = es_set_position(current_esh, current_pos); ASSERT(next_pos == current_pos); to_read = pieces[current].length - delta; if (to_read > len) to_read = len; next_pos = es_read(current_esh, to_read, bufp, &read_count); /* BUG ALERT! If we ever support entities that are not bytes, * the following addition must have a * "* es_get(current_esh, ES_SIZE_OF_ENTITY)" */ bufp += read_count; len -= read_count; *resultp += read_count; private->position += read_count; /* zaps private->current */ if (read_count < to_read) { if (current_esh == private->original) { /* The original entity stream has holes in it, * and the initialization assumed it was contiguous, * so the pieces and length must be corrected. */ pieces = split_piece( &private->pieces, current, delta+read_count); current++; /* Compute the gap size */ delta = next_pos - (current_pos + read_count); ASSERT(pieces[current].length > delta); pieces[current].length -= delta; private->length -= delta; PS_SET_ORIGINAL_SANDP(pieces[current], next_pos); } else { /* The scratch entity stream has wrapped around, making a * hole from [0..scratch_first_valid). */ ASSUME(SCRATCH_HAS_WRAPPED(private) || (private->parent && SCRATCH_HAS_WRAPPED(ABS_TO_REP(private->parent)) )); /* Caller needs to be told where next successful read * is, so search for piece containing valid scratch * indices (WARNING: there may not be one). */ for (save_current = current, current_pos = private->position; VALID_PIECE_INDEX(private, current); current++) { ASSERT(PS_SANDP_SOURCE(pieces[current])); delta = PS_SANDP_POS(pieces[current]); if (delta >= next_pos) { /* next_pos not referenced by pieces => go to start * this piece, which is first beyond next_pos */ next_pos = delta; } else if (next_pos >= delta+pieces[current].length) { continue; } private->position = (next_pos - delta) + pieces[current].pos; /* Allow uniform handling of current below. */ current++; break; } if (current_pos == private->position) private->position = es_get_length(esh); /* Although the pieces are correct it speeds up later * reads if "runs of now invalid scratch references" * are combined; however, only completely invalid * pieces can be combined (else the record headers will * be incorrectly included as part of the visible text). * -2 backs over terminating and partially valid pieces. */ current -= 2; if (save_current < current) { delta = PS_LAST_PLUS_ONE(pieces[current]); pieces[save_current].length = delta - pieces[save_current].pos; ft_shift_out(&private->pieces, save_current+1, current+1); } /* A read at the beginning of the scratch stream which * tries to read out of the start of the hole should * give the client (an appropriate part of) wrap_msg. * However, don't do this until AFTER finding out where * next valid position is, otherwise can return too * much text. */ for (current = 0, original_len = 0; VALID_PIECE_INDEX(private, current); current++) { if (PS_SANDP_SOURCE(pieces[current])) break; original_len = PS_LAST_PLUS_ONE(pieces[current]); } current = private->pieces.last_plus_one; INVALIDATE_CURRENT(private); ASSUME(original_len <= current_pos); read_count = strlen(wrap_msg); if (*resultp == 0 && current_pos < original_len + read_count) { FILE * console_fd; if (private->position < original_len + read_count) read_count = private->position - original_len; read_count -= current_pos - original_len; if (len < read_count) read_count = len; bcopy(wrap_msg+current_pos, bufp, read_count); *resultp = read_count; /* tell user that they are going to wrap */ /* Use the same flag for console error message */ if (max_transcript_alert_displayed != 1) { console_fd = fopen("/dev/console", "a"); fprintf(console_fd, "The text transcript in a Commands window filled up, and the oldest saved text will be erased from the top as more is typed at the bottom.\n"); fflush(console_fd); max_transcript_alert_displayed = 1; fclose(console_fd); } #ifdef notdef if (max_transcript_alert_displayed != 1) { Event alert_event; (void) alert_prompt( (Frame)0, &alert_event, ALERT_MESSAGE_STRINGS, "Text has been lost in a cmdtool transcript because", "the maximum edit log size has been exceeded.", 0, ALERT_BUTTON_YES, "Continue", ALERT_TRIGGER, ACTION_STOP, /* with trigger, yes or no bring it down */ 0); max_transcript_alert_displayed = 1; }#endif } } /* All of the above code is free and easy with local * variables because it expects to exit the loop here, so * it will need to be rewritten if this break is removed! */ break; } current++; } if (VALID_PIECE_INDEX(private, current)) { private->current = current; if (pieces[current].pos > private->position) private->current--; /* Short read advances current anyway, so undo the advance. */ } else INVALIDATE_CURRENT(private); ASSUME(ps_pieces_are_consistent(private)); return (private->position);}/* The routines ps_replace, ps_insert_pieces, and ps_undo_to_mark all perform * similar functions and a fix to one needs to be reflected in the others. */static Es_indexps_replace(esh, last_plus_one, count, buf, count_used) Es_handle esh; Es_index last_plus_one; long int count, *count_used; char *buf;{#ifdef DEBUG_TRACE Es_index next, pos; char temp; pos = (ABS_TO_REP(esh))->position; next = ps_debug_replace(esh, last_plus_one, count, buf, count_used); (void) fprintf(stdout, "ps_replace [%d..%d) by %d chars (used %d); next pos %d ...\n", pos, last_plus_one, count, *count_used, "next read at", next); if (buf) { temp = buf[count]; buf[count] = '\0'; (void) fprintf(stdout, "%s\n^^^\n", buf); buf[count] = temp; } return(next);}static Es_indexps_debug_replace(esh, last_plus_one, count, buf, count_used) Es_handle esh; Es_index last_plus_one; long int count, *count_used; char *buf;{#endif /* Assume that the piece stream looks like: * O1O S1S O2O S2S S3S O3O O4O S4S * where XnX means n-th chunk in stream X, and X2X may actually * occur earlier in stream X than X1X. * The possible cases are: * 1) Replace an empty region, with subcases: * 1a) Region is at end of previous replace, hence it can be treated * as an extension of the previous replace, and the associated * scratch piece can simply be lengthened. (S4S) * 1b) Otherwise, a new piece must be created, and the piece that * contains the empty region must be split (XnX -> XnX S5S XmX), * unless the empty region is at the beginning of that piece * (XnX -> S5S XnX). * 2) Replace a region completely within one piece: * 2a) If within latest scratch region, (1a) applies. * 2b) If the region exactly matches the piece, re-cycle the piece to * point at the new contents. * 2c) Otherwise, (1b) applies. * 3) Replace a region spanning multiple pieces. * 3a) For partially enclosed pieces, (1) applies. * 3b) For completely enclosed pieces, delete them all, except * possibly one to use as in (2b) if (3a) does not occur. * * WARNING! Changes to the pieces can only be made AFTER calls to * es_replace(scratch, ...) succeed, unless those changes do not * break the assertions about the pieces OR are backed out in case * of es_replace() failing. */ Es_index scratch_length; Es_index es_temp, new_rec_insert; long int long_temp; int delete_pieces_length, replace_used; register int current, end_index; register long int delta; /* Has 2 meanings! */ register Es_handle scratch; register Piece pieces; register Piece_table private = ABS_TO_REP(esh); *count_used = 0; if (buf == NULL && count != 0) { private->status = ES_INVALID_ARGUMENTS; return(ES_CANNOT_SET); } if (private->parent != NULL) { private->status = ES_INVALID_HANDLE; return(ES_CANNOT_SET); } scratch = private->scratch; scratch_length = es_set_position(scratch, ES_INFINITY); new_rec_insert = ES_INFINITY; /* => extending current */ if (last_plus_one > private->length) { last_plus_one = private->length; } ASSUME(last_plus_one >= private->position);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -