s_rdinstack.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include "String.h"
  5. struct Sinstack{
  6. int depth;
  7. Biobuf *fp[32]; /* hard limit to avoid infinite recursion */
  8. };
  9. /* initialize */
  10. extern Sinstack *
  11. s_allocinstack(char *file)
  12. {
  13. Sinstack *sp;
  14. Biobuf *fp;
  15. fp = Bopen(file, OREAD);
  16. if(fp == nil)
  17. return nil;
  18. sp = malloc(sizeof *sp);
  19. sp->depth = 0;
  20. sp->fp[0] = fp;
  21. return sp;
  22. }
  23. extern void
  24. s_freeinstack(Sinstack *sp)
  25. {
  26. while(sp->depth >= 0)
  27. Bterm(sp->fp[sp->depth--]);
  28. free(sp);
  29. }
  30. /* Append an input line to a String.
  31. *
  32. * Empty lines and leading whitespace are removed.
  33. */
  34. static char *
  35. rdline(Biobuf *fp, String *to)
  36. {
  37. int c;
  38. int len = 0;
  39. c = Bgetc(fp);
  40. /* eat leading white */
  41. while(c==' ' || c=='\t' || c=='\n' || c=='\r')
  42. c = Bgetc(fp);
  43. if(c < 0)
  44. return 0;
  45. for(;;){
  46. switch(c) {
  47. case -1:
  48. goto out;
  49. case '\\':
  50. c = Bgetc(fp);
  51. if (c != '\n') {
  52. s_putc(to, '\\');
  53. s_putc(to, c);
  54. len += 2;
  55. }
  56. break;
  57. case '\r':
  58. break;
  59. case '\n':
  60. if(len != 0)
  61. goto out;
  62. break;
  63. default:
  64. s_putc(to, c);
  65. len++;
  66. break;
  67. }
  68. c = Bgetc(fp);
  69. }
  70. out:
  71. s_terminate(to);
  72. return to->ptr - len;
  73. }
  74. /* Append an input line to a String.
  75. *
  76. * Returns a pointer to the character string (or 0).
  77. * Leading whitespace and newlines are removed.
  78. * Lines starting with #include cause us to descend into the new file.
  79. * Empty lines and other lines starting with '#' are ignored.
  80. */
  81. extern char *
  82. s_rdinstack(Sinstack *sp, String *to)
  83. {
  84. char *p;
  85. Biobuf *fp, *nfp;
  86. s_terminate(to);
  87. fp = sp->fp[sp->depth];
  88. for(;;){
  89. p = rdline(fp, to);
  90. if(p == nil){
  91. if(sp->depth == 0)
  92. break;
  93. Bterm(fp);
  94. sp->depth--;
  95. return s_rdinstack(sp, to);
  96. }
  97. if(strncmp(p, "#include", 8) == 0 && (p[8] == ' ' || p[8] == '\t')){
  98. to->ptr = p;
  99. p += 8;
  100. /* sanity (and looping) */
  101. if(sp->depth >= nelem(sp->fp))
  102. sysfatal("s_recgetline: includes too deep");
  103. /* skip white */
  104. while(*p == ' ' || *p == '\t')
  105. p++;
  106. nfp = Bopen(p, OREAD);
  107. if(nfp == nil)
  108. continue;
  109. sp->depth++;
  110. sp->fp[sp->depth] = nfp;
  111. return s_rdinstack(sp, to);
  112. }
  113. /* got milk? */
  114. if(*p != '#')
  115. break;
  116. /* take care of comments */
  117. to->ptr = p;
  118. s_terminate(to);
  119. }
  120. return p;
  121. }