// Does not reset slice->sent, so must be used *only* after Copy(). void RequestQueue::Shuffle(bt_index_t idx) { PIECE *piece; SLICE *slice, *prev, *end = (SLICE *)0, *snext, *temp; SLICE start; int len, shuffle; bt_offset_t firstoff; if( !(piece = FindPiece(idx)) ) return; len = piece->count; if( len == 1 ) return; firstoff = piece->slices->offset; start.next = piece->slices; shuffle = RandBits(3) + 2; if( shuffle > len/2 ) shuffle = len/2; for( ; shuffle; shuffle-- ){ // Undock the list, then randomly re-insert each slice. prev = &start; // the slice before the last insertion slice = start.next->next; // first one is a no-op end = start.next; start.next->next = (SLICE *)0; for( ; slice; slice = snext ){ snext = slice->next; if( RandBits(1) ){ // beginning or end of list if( RandBits(1) ){ prev = end; slice->next = (SLICE *)0; end->next = slice; end = slice; }else{ slice->next = start.next; start.next = slice; prev = &start; } }else{ // before or after previous insertion if( RandBits(1) ){ // put after prev->next if( end == prev->next ) end = slice; temp = prev->next; slice->next = prev->next->next; prev->next->next = slice; prev = temp; }else{ // put after prev (before prev->next) slice->next = prev->next; prev->next = slice; } } } } // shuffle loop piece->slices = start.next; // If first slice is the same as in the original, move it to the end. if( piece->slices->offset == firstoff ){ end->next = piece->slices; piece->slices = piece->slices->next; end = end->next; end->next = (SLICE *)0; } if( rq_send->index == piece->slices->index ) rq_send = piece->slices; }
// Counts only slices from one piece. dt_count_t RequestQueue::Qlen(bt_index_t idx) const { dt_count_t total = 0; const PIECE *piece; if( (piece = FindPiece(idx)) ){ total = piece->count; } return total; }
// This function is a failsafe. SLICE *RequestQueue::FixSend() { PIECE *piece; SLICE *original = rq_send; bool report = true; if( !rq_head ){ rq_send = (SLICE *)0; return rq_send; } if( !rq_send || !(piece = FindPiece(rq_send->index)) ){ if( rq_send ){ CONSOLE.Debug("%p rq_send invalid: %d/%d/%d", this, (int)rq_send->index, (int)rq_send->offset, (int)rq_send->length); } rq_send = rq_head->slices; report = false; } while( rq_send && rq_send->sent ){ // rq_send is wrong, fix it if( report ){ CONSOLE.Debug("%p rq_send wrong: %d/%d/%d", this, (int)rq_send->index, (int)rq_send->offset, (int)rq_send->length); report = false; } if( rq_send->next ) rq_send = rq_send->next; else{ piece = FindPiece(rq_send->index); rq_send = (piece && piece->next) ? piece->next->slices : (SLICE *)0; } } if( rq_send != original ){ if( !original ) CONSOLE.Debug("%p rq_send was null", this); if( !rq_send ) CONSOLE.Debug("%p rq_send corrected to null", this); else{ CONSOLE.Debug("%p rq_send corrected: %d/%d/%d", this, (int)rq_send->index, (int)rq_send->offset, (int)rq_send->length); } } return rq_send; }
bool RequestQueue::PeekPiece(bt_index_t idx, bt_offset_t *poff, bt_length_t *plen, bool *psent) const { const PIECE *piece; if( !(piece = FindPiece(idx)) ) return false; m_peek = piece->slices; if( poff ) *poff = m_peek->offset; if( plen ) *plen = m_peek->length; if( psent ) *psent = m_peek->sent; return true; }
bool RequestQueue::Delete(bt_index_t idx) { PIECE *piece, *prev; if( !(piece = FindPiece(idx, &prev)) ) return false; if( prev ) prev->next = piece->next; else rq_head = piece->next; if( rq_send && rq_send->index == idx ) rq_send = piece->next ? piece->next->slices : (SLICE *)0; piece->next = (PIECE *)0; _empty_slice_list(&piece); return true; }
// If prev is given/non-null, it will point to the slice preceding the target. SLICE *RequestQueue::FindSlice(bt_index_t idx, bt_offset_t off, bt_length_t len, SLICE **prev) const { PIECE *piece; SLICE *slice = (SLICE *)0; if( prev ) *prev = (SLICE *)0; if( (piece = FindPiece(idx)) ){ for( slice = piece->slices; slice; slice = slice->next ){ if( slice->index == idx && slice->offset == off && slice->length == len ) break; if( prev ) *prev = slice; } } return slice; }
bool RequestQueue::Append(PIECE *piece) { PIECE *last; SLICE *slice; if( FindPiece(piece->slices->index, &last) ) return false; if( last ) last->next = piece; else rq_head = piece; for( slice = piece->slices; slice && slice->sent; slice = slice->next ){ slice->sent = false; } if( !rq_send ) rq_send = piece->slices; return true; }
// Note that -1 indicates a failure to copy/add, not in the source (this). int RequestQueue::Copy(RequestQueue &dstq, bt_index_t idx) const { const PIECE *piece; const SLICE *slice; if( dstq.FindPiece(idx) ) return 0; if( !(piece = FindPiece(idx)) ) return 0; for( slice = piece->slices; slice; slice = slice->next ){ if( !dstq.Add(slice->index, slice->offset, slice->length) ){ dstq.Delete(idx); return -1; } } return 1; }
bool RequestQueue::PeekNextPiece(bt_index_t *pidx, bt_offset_t *poff, bt_length_t *plen) const { const PIECE *piece; if( !m_peek ) return PeekNext(pidx, poff, plen); if( !(piece = FindPiece(m_peek->index)) ) return false; piece = piece->next; m_peek = piece ? piece->slices : (SLICE *)0; if( m_peek ){ if( pidx ) *pidx = m_peek->index; if( poff ) *poff = m_peek->offset; if( plen ) *plen = m_peek->length; } return m_peek ? true : false; }
// Move the slice to the end of its piece sequence. void RequestQueue::MoveLast(bt_index_t idx, bt_offset_t off, bt_length_t len) { PIECE *piece; SLICE *slice, *point; if( !(piece = FindPiece(idx)) ) return; slice = FindSlice(idx, off, len, &point); if( !slice || !slice->next ) return; if( rq_send == slice ) rq_send = slice->next; if( point ) point->next = slice->next; else piece->slices = slice->next; slice->sent = false; for( point = slice->next; point->next; point = point->next ); point->next = slice; slice->next = (SLICE *)0; }
void RequestQueue::Sent(time_t timestamp, SLICE *slice) { if( !slice && !(slice = rq_send) && !(slice = FixSend()) ){ CONSOLE.Warning(1, "RequestQueue error: Sent() called but nothing to send"); return; } slice->reqtime = timestamp; slice->sent = true; if( rq_send == slice ){ rq_send = slice->next; if( !rq_send ){ const PIECE *piece = FindPiece(slice->index); if( piece->next ) rq_send = piece->next->slices; } } }
// Returns true if the piece was moved successfully. bool RequestQueue::Transfer(RequestQueue &dstq, bt_index_t idx) { bool result = true; PIECE *piece, *prev; if( !(piece = FindPiece(idx, &prev)) ) return true; if( rq_send && rq_send->index == idx ) rq_send = piece->next ? piece->next->slices : (SLICE *)0; if( prev ) prev->next = piece->next; else rq_head = piece->next; piece->next = (PIECE *)0; if( (&PENDING == &dstq && piece->count >= NSlices(piece->slices->index)) || !dstq.Append(piece) ){ _empty_slice_list(&piece); result = false; } return result; }
bool RequestQueue::Add(bt_index_t idx, bt_offset_t off, bt_length_t len) { PIECE *piece, *last; SLICE *slice, *point = (SLICE *)0; piece = FindPiece(idx, &last); if( !(slice = new SLICE) ){ errno = ENOMEM; return false; } if( piece ){ for( point = piece->slices; point && point->next; point = point->next ); }else{ if( !(piece = new PIECE) ){ delete slice; errno = ENOMEM; return false; } piece->count = 0; piece->slices = (SLICE *)0; piece->next = (PIECE *)0; if( last ) last->next = piece; else rq_head = piece; } slice->next = (SLICE *)0; slice->index = idx; slice->offset = off; slice->length = len; slice->reqtime = (time_t) 0; slice->sent = false; if( point ) point->next = slice; else piece->slices = slice; piece->count++; if( !rq_send && !piece->next ) rq_send = slice; return true; }
/* Peek() or PeekPiece() must be called first, to insure m_peek is initialized to a valid state. The queue must not be changed between calls to PeekNext(). */ bool RequestQueue::PeekNext(bt_index_t *pidx, bt_offset_t *poff, bt_length_t *plen, bool *psent) const { const SLICE *slice = (SLICE *)0; if( m_peek ){ slice = m_peek->next; if( !slice ){ const PIECE *piece; if( (piece = FindPiece(m_peek->index)) ){ piece = piece->next; if( piece ) slice = piece->slices; } } }else if( rq_head ) slice = rq_head->slices; if( slice ){ if( pidx ) *pidx = slice->index; if( poff ) *poff = slice->offset; if( plen ) *plen = slice->length; if( psent ) *psent = slice->sent; } m_peek = slice; return slice ? true : false; }
bool RequestQueue::Remove(bt_index_t idx, bt_offset_t off, bt_length_t len) { PIECE *piece, *prevpiece = (PIECE *)0; SLICE *slice, *prev = (SLICE *)0; if( !(piece = FindPiece(idx, &prevpiece)) ) return false; if( !(slice = FindSlice(idx, off, len, &prev)) ) return false; if( prev ) prev->next = slice->next; else piece->slices = slice->next; if( rq_send == slice ){ rq_send = slice->next; if( !rq_send && piece->next ) rq_send = piece->next->slices; } delete slice; piece->count--; if( !piece->slices ){ if( prevpiece ) prevpiece->next = piece->next; else rq_head = piece->next; delete piece; } return true; }
/* * Function: * Search * * Parameters: * w - AsciiSource object * position - the position to start scanning * dir - direction to scan * text - text block to search for * * Description: * Searchs the text source for the text block passed. * * Returns: * The position of the item found */ static XawTextPosition Search(Widget w, register XawTextPosition position, XawTextScanDirection dir, XawTextBlock *text) { AsciiSrcObject src = (AsciiSrcObject)w; register int count = 0; register char *ptr, c; char *str; Piece *piece; char *buf; XawTextPosition first; int cnt, case_sensitive; if (dir == XawsdLeft) { if (position == 0) return (XawTextSearchError); position--; } buf = XtMalloc((unsigned)sizeof(unsigned char) * text->length); memcpy(buf, text->ptr, (unsigned)text->length); piece = FindPiece(src, position, &first); ptr = (position - first) + piece->text; case_sensitive = text->firstPos; if (dir == XawsdRight) { str = buf; c = *str; /*CONSTCOND*/ while (1) { if (*ptr++ == c || (case_sensitive && isalpha(c) && isalpha(ptr[-1]) && toupper(c) == toupper(ptr[-1]))) { if (++count == text->length) break; c = *++str; } else if (count) { ptr -= count; str -= count; position -= count; count = 0; c = *str; if (ptr < piece->text) { do { cnt = piece->text - ptr; piece = piece->prev; if (piece == NULL) { XtFree(buf); return (XawTextSearchError); } ptr = piece->text + piece->used - cnt; } while (ptr < piece->text); } } position++; if (ptr >= (piece->text + piece->used)) { do { cnt = ptr - (piece->text + piece->used); piece = piece->next; if (piece == NULL) { XtFree(buf); return (XawTextSearchError); } ptr = piece->text + cnt; } while (ptr >= (piece->text + piece->used)); } } position -= text->length - 1; } else { str = buf + text->length - 1; c = *str; /*CONSTCOND*/ while (1) { if (*ptr-- == c || (case_sensitive && isalpha(c) && isalpha(ptr[1]) && toupper(c) == toupper(ptr[1]))) { if (++count == text->length) break; c = *--str; } else if (count) { ptr += count; str += count; position += count; count = 0; c = *str; if (ptr >= (piece->text + piece->used)) { do { cnt = ptr - (piece->text + piece->used); piece = piece->next; if (piece == NULL) { XtFree(buf); return (XawTextSearchError); } ptr = piece->text + cnt; } while (ptr >= (piece->text + piece->used)); } } position--; if (ptr < piece->text) { do { cnt = piece->text - ptr; piece = piece->prev; if (piece == NULL) { XtFree(buf); return (XawTextSearchError); } ptr = piece->text + piece->used - cnt; } while (ptr < piece->text); } } } XtFree(buf); return (position); }
/* * Function: * Scan * * Parameters: * w - AsciiSource object * position - position to start scanning * type - type of thing to scan for * dir - direction to scan * count - which occurance if this thing to search for. * include - whether or not to include the character found in * the position that is returned * * Description: * Scans the text source for the number and type of item specified. * * Returns: * The position of the item found * * Note: * While there are only 'n' characters in the file there are n+1 * possible cursor positions (one before the first character and * one after the last character */ static XawTextPosition Scan(Widget w, register XawTextPosition position, XawTextScanType type, XawTextScanDirection dir, int count, Bool include) { AsciiSrcObject src = (AsciiSrcObject)w; Piece *piece; XawTextPosition first, first_eol_position = 0; register char *ptr, *lim; register int cnt = count; register unsigned char c; if (dir == XawsdLeft) { if (position <= 0) return (0); --position; } else if (position >= src->ascii_src.length) return (src->ascii_src.length); piece = FindPiece(src, position, &first); if (piece->used == 0) return (0); ptr = (position - first) + piece->text; if (dir == XawsdRight) { lim = piece->text + piece->used; switch (type) { case XawstEOL: case XawstParagraph: case XawstWhiteSpace: case XawstAlphaNumeric: for (; cnt > 0; cnt--) { Bool non_space = False, first_eol = True; /*CONSTCOND*/ while (True) { if (ptr >= lim) { piece = piece->next; if (piece == NULL) /* End of text */ return (src->ascii_src.length); ptr = piece->text; lim = piece->text + piece->used; } c = *ptr++; ++position; if (type == XawstEOL) { if (c == '\n') break; } else if (type == XawstAlphaNumeric) { if (!isalnum(c)) { if (non_space) break; } else non_space = True; } else if (type == XawstWhiteSpace) { if (isspace(c)) { if (non_space) break; } else non_space = True; } else { /* XawstParagraph */ if (first_eol) { if (c == '\n') { first_eol_position = position; first_eol = False; } } else if (c == '\n') break; else if (!isspace(c)) first_eol = True; } } } break; case XawstPositions: position += count; return (position < src->ascii_src.length ? position : src->ascii_src.length); case XawstAll: return (src->ascii_src.length); default: break; } if (!include) { if (type == XawstParagraph) position = first_eol_position; if (count) --position; } } else { lim = piece->text; switch (type) { case XawstEOL: case XawstParagraph: case XawstWhiteSpace: case XawstAlphaNumeric: for (; cnt > 0; cnt--) { Bool non_space = False, first_eol = True; /*CONSTCOND*/ while (True) { if (ptr < lim) { piece = piece->prev; if (piece == NULL) /* Begining of text */ return (0); ptr = piece->text + piece->used - 1; lim = piece->text; } c = *ptr--; --position; if (type == XawstEOL) { if (c == '\n') break; } else if (type == XawstAlphaNumeric) { if (!isalnum(c)) { if (non_space) break; } else non_space = True; } else if (type == XawstWhiteSpace) { if (isspace(c)) { if (non_space) break; } else non_space = True; } else { /* XawstParagraph */ if (first_eol) { if (c == '\n') { first_eol_position = position; first_eol = False; } } else if (c == '\n') break; else if (!isspace(c)) first_eol = True; } } } break; case XawstPositions: position -= count - 1; return (position > 0 ? position : 0); case XawstAll: return (0); default: break; } if (!include) { if (type == XawstParagraph) position = first_eol_position; if (count) ++position; } position++; } return (position); }
/*ARGSUSED*/ static int ReplaceText(Widget w, XawTextPosition startPos, XawTextPosition endPos, XawTextBlock *text) { AsciiSrcObject src = (AsciiSrcObject)w; Piece *start_piece, *end_piece, *temp_piece; XawTextPosition start_first, end_first; int length, firstPos; /* * Editing a read only source is not allowed */ if (src->text_src.edit_mode == XawtextRead) return (XawEditError); start_piece = FindPiece(src, startPos, &start_first); end_piece = FindPiece(src, endPos, &end_first); #ifndef OLDXAW /* * This is a big hack, but I can't think about a clever way to know * if the character being moved forward has a negative lbearing. * */ if (start_piece->used) { int i; for (i = 0; i < src->text_src.num_text; i++) { int line; TextWidget ctx = (TextWidget)src->text_src.text[i]; for (line = 0; line < ctx->text.lt.lines; line++) if (startPos < ctx->text.lt.info[line + 1].position) break; if (i < ctx->text.lt.lines && startPos > ctx->text.lt.info[i].position) { AsciiSinkObject sink = (AsciiSinkObject)ctx->text.sink; XawTextAnchor *anchor; XawTextEntity *entity; XawTextProperty *property; XFontStruct *font; if (XawTextSourceAnchorAndEntity(w, startPos, &anchor, &entity) && (property = XawTextSinkGetProperty(ctx->text.sink, entity->property)) != NULL && (property->mask & XAW_TPROP_FONT)) font = property->font; else font = sink->ascii_sink.font; if (font->min_bounds.lbearing < 0) { int lbearing = font->min_bounds.lbearing; unsigned char c = *(unsigned char*) (start_piece->text + (startPos - start_first)); if (c == '\t' || c == '\n') c = ' '; else if ((c & 0177) < XawSP || c == 0177) { if (sink->ascii_sink.display_nonprinting) c = c > 0177 ? '\\' : c + '^'; else c = ' '; } if (font->per_char && (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2)) lbearing = font->per_char[c - font->min_char_or_byte2].lbearing; if (lbearing < 0) _XawTextNeedsUpdating(ctx, startPos - 1, startPos); } } } } #endif /* * Remove Old Stuff */ if (start_piece != end_piece) { temp_piece = start_piece->next; /* * If empty and not the only piece then remove it. */ if (((start_piece->used = startPos - start_first) == 0) && !(start_piece->next == NULL && start_piece->prev == NULL)) RemovePiece(src, start_piece); while (temp_piece != end_piece) { temp_piece = temp_piece->next; RemovePiece(src, temp_piece->prev); } end_piece->used -= endPos - end_first; if (end_piece->used != 0) memmove(end_piece->text, end_piece->text + endPos - end_first, (unsigned)end_piece->used); } else { /* We are fully in one piece */ if ((start_piece->used -= endPos - startPos) == 0) { if (!(start_piece->next == NULL && start_piece->prev == NULL)) RemovePiece(src, start_piece); } else { memmove(start_piece->text + (startPos - start_first), start_piece->text + (endPos - start_first), (unsigned)(start_piece->used - (startPos - start_first))); if (src->ascii_src.use_string_in_place && src->ascii_src.length - (endPos - startPos) < src->ascii_src.piece_size - 1) start_piece->text[src->ascii_src.length - (endPos - startPos)] = '\0'; } } src->ascii_src.length += -(endPos - startPos) + text->length; if ( text->length != 0) { /* * Put in the New Stuff */ start_piece = FindPiece(src, startPos, &start_first); length = text->length; firstPos = text->firstPos; while (length > 0) { char *ptr; int fill; if (src->ascii_src.use_string_in_place) { if (start_piece->used == src->ascii_src.piece_size - 1) { /* * If we are in ascii string emulation mode. Then the * string is not allowed to grow */ start_piece->used = src->ascii_src.length = src->ascii_src.piece_size - 1; start_piece->text[src->ascii_src.length] = '\0'; return (XawEditError); } } if (start_piece->used == src->ascii_src.piece_size) { BreakPiece(src, start_piece); start_piece = FindPiece(src, startPos, &start_first); } fill = Min((int)(src->ascii_src.piece_size - start_piece->used), length); ptr = start_piece->text + (startPos - start_first); memmove(ptr + fill, ptr, (unsigned)(start_piece->used - (startPos - start_first))); memcpy(ptr, text->ptr + firstPos, (unsigned)fill); startPos += fill; firstPos += fill; start_piece->used += fill; length -= fill; } } if (src->ascii_src.use_string_in_place) start_piece->text[start_piece->used] = '\0'; #ifdef OLDXAW src->ascii_src.changes = True; XtCallCallbacks(w, XtNcallback, NULL); #endif return (XawEditDone); }
/* * Function: * ReadText * * Parameters: * w - AsciiSource widget * pos - position of the text to retreive. * text - text block that will contain returned text * length - maximum number of characters to read * * Description: * This function reads the source. * * Returns: * The character position following the retrieved text. */ static XawTextPosition ReadText(Widget w, XawTextPosition pos, XawTextBlock *text, int length) { AsciiSrcObject src = (AsciiSrcObject)w; XawTextPosition count, start; Piece *piece; #ifndef OLDXAW XawTextAnchor *anchor; XawTextEntity *entity; XawTextPosition offset, end = pos + length; Bool state; end = XawMin(end, src->ascii_src.length); while ((state = XawTextSourceAnchorAndEntity(w, pos, &anchor, &entity)) && (entity->flags & XAW_TENTF_HIDE)) pos = anchor->position + entity->offset + entity->length; if (state == False || !(entity->flags & XAW_TENTF_REPLACE)) { while (entity) { offset = anchor->position + entity->offset; if (offset >= end) break; if (offset > pos && (entity->flags & (XAW_TENTF_HIDE | XAW_TENTF_REPLACE))) { end = XawMin(end, offset); break; } if ((entity = entity->next) == NULL && (anchor = XawTextSourceNextAnchor(w, anchor)) != NULL) entity = anchor->entities; } } else if (state && (entity->flags & XAW_TENTF_REPLACE) && pos < end) { XawTextBlock *block = (XawTextBlock*)entity->data; offset = anchor->position + entity->offset; end = XawMin(end, offset + block->length); if ((length = end - pos) < 0) length = 0; text->length = length; text->format = XawFmt8Bit; if (length == 0) { text->firstPos = end = offset + entity->length; text->ptr = ""; } else { text->firstPos = pos; text->ptr = block->ptr + (pos - offset); if (pos + length < offset + block->length) end = pos + length; /* there is data left to be read */ else end = offset + entity->length; } return (end); } if ((length = end - pos) < 0) length = 0; #endif piece = FindPiece(src, pos, &start); text->firstPos = pos; text->ptr = piece->text + (pos - start); count = piece->used - (pos - start); text->length = Max(0, (length > count) ? count : length); text->format = XawFmt8Bit; return (pos + text->length); }