diff options
Diffstat (limited to 'lib/vio_fifo.c')
-rw-r--r-- | lib/vio_fifo.c | 206 |
1 files changed, 177 insertions, 29 deletions
diff --git a/lib/vio_fifo.c b/lib/vio_fifo.c index 89e42add..0612c465 100644 --- a/lib/vio_fifo.c +++ b/lib/vio_fifo.c @@ -71,7 +71,7 @@ * The following are expected to be true: * * * p_start == &get_ptr => no hold mark - * &hold_ptr => have hold mark + * &hold_ptr => hold mark is set * * * put_ptr == get_ptr => FIFO empty -- unless *p_start != get_ptr. * @@ -95,8 +95,8 @@ * get_ptr < *p_get_end => data exists in the current get_lump * get_ptr > *p_get_end => broken * - * * p_end == &end_ptr -- when end mark set - * == &put_ptr -- when no end mark + * * p_end == &put_ptr => no end mark + * == &end_ptr => end mark is set * * Note that: * @@ -105,7 +105,7 @@ * * When get_ptr reaches *p_get_end, however, must move to the next lump, * if possible, or collapse the pointers if have hit the put_ptr. Keeping - * the get_ptr honest in this way: (a) ensures that will always put at + * the get_ptr honest in this way: (a) ensures that will always get from * the beginning of a lump if possible; (b) simplifies the handling of * hold_ptr et al (because get_ptr is never in the ambiguous position * at the end of one lump, which is the same as the start of the next). @@ -163,7 +163,7 @@ inline static void vio_fifo_set_get_ptr(vio_fifo vff, vio_fifo_lump lump, char* ptr) ; inline static void vio_fifo_set_get_end(vio_fifo vff) ; -inline static void vio_fifo_release_upto(vio_fifo vff, vio_fifo_lump upto) ; +inline static void vio_fifo_release_up_to(vio_fifo vff, vio_fifo_lump upto) ; static void vio_fifo_release_lump(vio_fifo vff, vio_fifo_lump lump) ; /*------------------------------------------------------------------------------ @@ -189,6 +189,10 @@ vio_fifo_have_end_mark(vio_fifo vff) * * Preserves and hold mark or end mark -- so no need to change p_start or p_end. * + * Resets the hold_ptr and the end_ptr whether there is a hold and/or end mark + * or not -- saves testing for whether to do it or not. These values are + * only significant if p_start or p_end/p_get_end point at them. + * * HOWEVER: does not set p_get_end -- so if get_lump or end_lump or p_end have * changed, then must also call vio_fifo_set_get_end(). * @@ -257,7 +261,7 @@ vio_fifo_sync_get(vio_fifo vff) vio_fifo_set_get_ptr(vff, get_lump, get_lump->data) ; if (!vio_fifo_have_hold_mark(vff)) - vio_fifo_release_upto(vff, get_lump) ; + vio_fifo_release_up_to(vff, get_lump) ; } ; } ; @@ -268,7 +272,7 @@ inline static void vio_fifo_set_get_ptr(vio_fifo vff, vio_fifo_lump lump, char* ptr) { vff->get_lump = lump ; - vff->get_ptr = lump->data ; + vff->get_ptr = ptr ; vio_fifo_set_get_end(vff) ; } ; @@ -287,18 +291,36 @@ vio_fifo_set_get_end(vio_fifo vff) } ; /*------------------------------------------------------------------------------ - * Release all lumps upto (but excluding) the given lump. + * Release all lumps up to (but excluding) the given lump. * * NB: takes no notice of hold_ptr or anything else. */ inline static void -vio_fifo_release_upto(vio_fifo vff, vio_fifo_lump upto) +vio_fifo_release_up_to(vio_fifo vff, vio_fifo_lump to) { vio_fifo_lump lump ; - while (ddl_head(vff->base) != upto) + while (ddl_head(vff->base) != to) vio_fifo_release_lump(vff, ddl_pop(&lump, vff->base, list)) ; } ; +/*------------------------------------------------------------------------------ + * Release all lumps back to (but excluding) the given lump. + * + * Reset vff->put_end to be the end of the to->lump. + * + * NB: takes no notice of hold_ptr or anything else. + */ +inline static void +vio_fifo_release_back_to(vio_fifo vff, vio_fifo_lump to) +{ + vio_fifo_lump lump ; + do + vio_fifo_release_lump(vff, ddl_crop(&lump, vff->base, list)) ; + while (to != ddl_tail(vff->base)) ; + + vff->put_end = to->end ; +} ; + /*============================================================================== * Initialisation, allocation and freeing of FIFO and lumps thereof. */ @@ -445,7 +467,7 @@ vio_fifo_clear(vio_fifo vff, bool clear_marks) vff->get_lump = lump ; /* before releasing */ vff->end_lump = lump ; - vio_fifo_release_upto(vff, lump) ; + vio_fifo_release_up_to(vff, lump) ; vio_fifo_reset_ptrs(vff) ; @@ -726,6 +748,137 @@ vio_fifo_read_nb(vio_fifo vff, int fd, ulen request) return total ; } ; +/*------------------------------------------------------------------------------ + * Strip trailing whitespace and, if required, insert '\n' if result is not + * empty and does not now end in '\n' + * + * Strips anything 0x00..0x20 except for '\n'. + * + * Returns: 0..n -- number of bytes read + * -1 => failed -- see errno + * -2 => EOF met immediately + */ +extern void +vio_fifo_trim(vio_fifo vff, bool term) +{ + vio_fifo_lump lump ; + char* p ; + char* s ; + char* end_ptr ; + bool end_ptr_passed ; + char ch ; + + /* Position at end of fifo, and establish how far back in current lump + * can discard whitespace. + */ + lump = ddl_tail(vff->base) ; + p = vff->put_ptr ; + s = (lump == vff->get_lump) ? vff->get_ptr : lump->data ; + + if (vio_fifo_have_end_mark(vff)) + end_ptr = vff->end_ptr ; + else + end_ptr = NULL ; + end_ptr_passed = false ; + + /* Track backwards, until reach get_ptr or hit '\n' or something which is + * not 0x00..0x20. + */ + ch = '\0' ; + while (1) + { + if (s == p) + { + /* At the start of the current lump and/or at the get_ptr. + * + * If at the get_ptr, then cannot track any further back, but if + * there is a hold mark, there may be something before the get_ptr. + */ + if (lump == vff->get_lump) + { + qassert(p == vff->get_ptr) ; /* hit get_ptr */ + + ch = '\0' ; + if (p == *vff->p_start) + break ; /* hit start of fifo */ + + if (p != lump->data) + qassert(p > lump->data) ; + else + { + qassert(lump != ddl_head(vff->base)) ; + s = ddl_prev(lump, list)->end ; + } ; + + ch = *(s - 1) ; + + if (ch != '\n') + ch = '\xFF' ; /* anything but '\0' */ + + break ; + } ; + + lump = ddl_prev(lump, list) ; + + p = lump->end ; + s = (lump == vff->get_lump) ? vff->get_ptr : lump->data ; + + continue ; + } ; + + qassert(p > s) ; + + ch = *(p-1) ; + + if ((ch > 0x20) || (ch == '\n')) + break ; + + if (p == end_ptr) + end_ptr_passed = true ; /* stepped past the end mark */ + + --p ; + } ; + + /* Decide what to do now. + * + * ch == '\0' <=> p points at end of empty fifo ! + * ch == '\n' <=> p points after a '\n'. + * otherwise <=> p points after non-whitespace, or is at get_ptr and + * something other than '\n' precedes it. + * + * lump points at the lump that 'p' is in. + * + * If stepped back past the end_ptr, now is the time to set the end_ptr + * to the current position. + */ + if (end_ptr_passed) + { + qassert(end_ptr != NULL) ; + + vff->end_lump = lump ; + vff->end_ptr = p ; + } ; + + /* If have stepped back across one or more lumps, trim now excess lumps off + * the end. + * + * Note, it is (just) possible that in inserting a '\n', that this will + * trim off a lump that needs to be re-instated -- but it is more + * straightforward to do this, and the odds are pretty slim. + */ + if (lump != ddl_tail(vff->base)) + vio_fifo_release_back_to(vff, lump) ; + + /* set the (new) put_ptr. + */ + vff->put_ptr = p ; + + /* If we need to add a terminator, do that now. + */ + if (term && (ch != '\n') && (ch != '\0')) + vio_fifo_put_byte(vff, '\n') ; +} ; + /*============================================================================== * Copy operations -- from one FIFO to another. */ @@ -936,14 +1089,7 @@ vio_fifo_back_to_end_mark(vio_fifo vff, bool keep) assert(vio_fifo_have_end_mark(vff)) ; if (vff->end_lump != ddl_tail(vff->base)) - { - vio_fifo_lump lump ; - do - vio_fifo_release_lump(vff, ddl_crop(&lump, vff->base, list)) ; - while (vff->end_lump != ddl_tail(vff->base)) ; - - vff->put_end = vff->end_lump->end ; - } ; + vio_fifo_release_back_to(vff, vff->end_lump) ; if (*vff->p_start == vff->end_ptr) vio_fifo_reset_ptrs(vff) ; @@ -967,6 +1113,8 @@ vio_fifo_back_to_end_mark(vio_fifo vff, bool keep) /*------------------------------------------------------------------------------ * Get upto 'n' bytes -- steps past the bytes fetched. * + * Stops at current end of FIFO (and not before). + * * Returns: number of bytes got -- may be zero. */ extern ulen @@ -1123,7 +1271,7 @@ vio_fifo_skip_to_end(vio_fifo vff) extern void vio_fifo_set_hold_mark(vio_fifo vff) { - vio_fifo_release_upto(vff, vff->get_lump) ; + vio_fifo_release_up_to(vff, vff->get_lump) ; if (vff->get_ptr == vff->put_ptr) vio_fifo_reset_ptrs(vff) ; @@ -1149,7 +1297,7 @@ vio_fifo_set_hold_mark(vio_fifo vff) extern void vio_fifo_clear_hold_mark(vio_fifo vff) { - vio_fifo_release_upto(vff, vff->get_lump) ; + vio_fifo_release_up_to(vff, vff->get_lump) ; if (vff->get_ptr == vff->put_ptr) vio_fifo_reset_ptrs(vff) ; @@ -1346,14 +1494,14 @@ vio_fifo_verify(vio_fifo vff) */ if (*vff->p_start == vff->put_ptr) { - if ( (tail != head) - || (vff->get_lump != head) - || (vff->end_lump != head) - || (vff->get_ptr != head->data) - || (vff->put_ptr != head->data) - || (vff->put_end != head->end) - || !( (vff->hold_ptr == NULL) || (vff->hold_ptr == head->data) ) - || !( (vff->end_ptr == NULL) || (vff->end_ptr == head->data) ) + if ( (tail != head) + || (vff->get_lump != head) + || (vff->end_lump != head) + || (vff->get_ptr != head->data) + || (vff->put_ptr != head->data) + || (vff->put_end != head->end) + || !( (vff->p_start != &vff->hold_ptr) || (vff->hold_ptr == head->data) ) + || !( (vff->p_end != &vff->end_ptr) || (vff->end_ptr == head->data) ) ) zabort("pointers not valid for empty fifo") ; } ; |