_adjust_pos.c 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
  2. *
  3. * GNU Library General Public License (LGPL) version 2 or later.
  4. *
  5. * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
  6. */
  7. #include "_stdio.h"
  8. /* Both ftell() and fseek() (for SEEK_CUR) need to correct the stream's
  9. * position to take into account buffered data and ungotten chars.
  10. *
  11. * If successful, store corrected position in *pos and return >= 0.
  12. * Otherwise return < 0.
  13. *
  14. * If position is unrepresentable, set errno to EOVERFLOW.
  15. */
  16. int attribute_hidden __stdio_adjust_position(register FILE * __restrict stream,
  17. register __offmax_t *pos)
  18. {
  19. __offmax_t oldpos;
  20. int corr;
  21. if ((corr = stream->__modeflags & __MASK_READING) != 0) {
  22. --corr; /* Correct for ungots. Assume narrow, and fix below. */
  23. }
  24. #ifdef __UCLIBC_HAS_WCHAR__
  25. if (corr && __STDIO_STREAM_IS_WIDE(stream)) {
  26. /* A wide stream and we have at least one ungotten wchar.
  27. * If it is a user ungot, we need to fail since position
  28. * is unspecified as per C99. */
  29. if ((corr > 1) || stream->__ungot[1]) { /* User ungetwc, */
  30. return -1; /* so position is undefined. */
  31. }
  32. corr -= (1 + stream->__ungot_width[1]);
  33. if (stream->__state.__mask > 0) { /* Incomplete (bad?) mb char. */
  34. corr -= stream->__ungot_width[0];
  35. }
  36. }
  37. #endif
  38. #ifdef __STDIO_BUFFERS
  39. corr += (((__STDIO_STREAM_IS_WRITING(stream))
  40. ? stream->__bufstart : stream->__bufread)
  41. - stream->__bufpos);
  42. #endif
  43. oldpos = *pos;
  44. /* Range checking cases:
  45. * (pos - corr > pos) && (corr > 0) : underflow? return -corr < 0
  46. * (pos - corr > pos) && (corr < 0) : ok .. return -corr > 0
  47. * (pos - corr <= pos) && (corr >= 0) : ok .. return corr > 0
  48. * (pos - corr <= pos) && (corr < 0) : overflow .. return corr < 0
  49. */
  50. if ((*pos -= corr) > oldpos) {
  51. corr = -corr;
  52. }
  53. if (corr < 0) {
  54. __set_errno(EOVERFLOW);
  55. }
  56. return corr;
  57. }