tcldot-io.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <assert.h>
  11. #include <cgraph/rdr.h>
  12. #include <limits.h>
  13. #include <stddef.h>
  14. #include "tcldot.h"
  15. /*
  16. * myiodisc_afread - same api as read for libcgraph
  17. *
  18. * gets one line at a time from a Tcl_Channel and places it in a user buffer
  19. * up to a maximum of n characters
  20. *
  21. * returns pointer to obtained line in user buffer, or
  22. * returns NULL when last line read from memory buffer
  23. *
  24. * This is probably innefficient because it introduces
  25. * one more stage of line buffering during reads (at least)
  26. * but it is needed so that we can take full advantage
  27. * of the Tcl_Channel mechanism.
  28. */
  29. int myiodisc_afread(void* channel, char *ubuf, int n)
  30. {
  31. assert(n >= 0);
  32. static Tcl_DString dstr;
  33. static int strpos;
  34. int nput;
  35. if (!n) { /* a call with n==0 (from aglexinit) resets */
  36. *ubuf = '\0';
  37. strpos = 0;
  38. return 0;
  39. }
  40. /*
  41. * the user buffer might not be big enough to hold the line.
  42. */
  43. if (strpos) {
  44. nput = Tcl_DStringLength(&dstr) - strpos;
  45. if (nput > n) {
  46. /* chunk between first and last */
  47. memcpy(ubuf, strpos + Tcl_DStringValue(&dstr), (size_t)n);
  48. strpos += n;
  49. nput = n;
  50. ubuf[n] = '\0';
  51. } else {
  52. /* last chunk */
  53. memcpy(ubuf, strpos + Tcl_DStringValue(&dstr), (size_t)nput);
  54. strpos = 0;
  55. }
  56. } else {
  57. Tcl_DStringFree(&dstr);
  58. Tcl_DStringInit(&dstr);
  59. if (Tcl_Gets((Tcl_Channel) channel, &dstr) < 0) {
  60. /* probably EOF, but could be other read errors */
  61. *ubuf = '\0';
  62. return 0;
  63. }
  64. /* linend char(s) were stripped off by Tcl_Gets,
  65. * append a canonical linenend. */
  66. Tcl_DStringAppend(&dstr, "\n", 1);
  67. if (Tcl_DStringLength(&dstr) > n) {
  68. /* first chunk */
  69. nput = n;
  70. memcpy(ubuf, Tcl_DStringValue(&dstr), (size_t)n);
  71. strpos = n;
  72. } else {
  73. /* single chunk */
  74. nput = Tcl_DStringLength(&dstr);
  75. memcpy(ubuf, Tcl_DStringValue(&dstr), (size_t)nput);
  76. }
  77. }
  78. return nput;
  79. }
  80. /* exact copy from cgraph/io.c - but that one is static */
  81. int myiodisc_memiofread(void *chan, char *buf, int bufsize)
  82. {
  83. const char *ptr;
  84. char *optr;
  85. char c;
  86. rdr_t *s;
  87. if (bufsize == 0) return 0;
  88. s = chan;
  89. if (s->cur >= s->len)
  90. return 0;
  91. size_t l = 0;
  92. ptr = s->data + s->cur;
  93. optr = buf;
  94. do {
  95. *optr++ = c = *ptr++;
  96. l++;
  97. } while (c && c != '\n' && l < INT_MAX && (int)l < bufsize);
  98. s->cur += l;
  99. return (int)l;
  100. }