dynar-simple-lex.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2015-2016 Red Hat, Inc.
  3. *
  4. * All rights reserved.
  5. *
  6. * Author: Jan Friesse (jfriesse@redhat.com)
  7. *
  8. * This software licensed under BSD license, the text of which follows:
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions are met:
  12. *
  13. * - Redistributions of source code must retain the above copyright notice,
  14. * this list of conditions and the following disclaimer.
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. * - Neither the name of the Red Hat, Inc. nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  26. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  31. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  32. * THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include <string.h>
  35. #include "dynar-simple-lex.h"
  36. /*
  37. * Simple_lex is going to be used in protocol and it's not good idea to depend on locale
  38. */
  39. static int
  40. dynar_simple_lex_is_space(char ch)
  41. {
  42. return (ch == ' ' || ch == '\f' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\v');
  43. }
  44. void
  45. dynar_simple_lex_init(struct dynar_simple_lex *lex, struct dynar *input,
  46. enum dynar_simple_lex_type lex_type)
  47. {
  48. memset(lex, 0, sizeof(*lex));
  49. lex->input = input;
  50. lex->lex_type = lex_type;
  51. dynar_init(&lex->token, dynar_max_size(input));
  52. }
  53. void
  54. dynar_simple_lex_destroy(struct dynar_simple_lex *lex)
  55. {
  56. dynar_destroy(&lex->token);
  57. memset(lex, 0, sizeof(*lex));
  58. }
  59. struct dynar *
  60. dynar_simple_lex_token_next(struct dynar_simple_lex *lex)
  61. {
  62. size_t pos;
  63. size_t size;
  64. char *str;
  65. char ch, ch2;
  66. int add_char;
  67. int state;
  68. dynar_clean(&lex->token);
  69. size = dynar_size(lex->input);
  70. str = dynar_data(lex->input);
  71. state = 1;
  72. pos = lex->pos;
  73. while (state != 0) {
  74. if (pos < size) {
  75. ch = str[pos];
  76. } else {
  77. ch = '\0';
  78. }
  79. add_char = 0;
  80. switch (state) {
  81. case 1:
  82. /*
  83. * Skip spaces. Newline is special and means end of processing
  84. */
  85. if (pos >= size || ch == '\n' || ch == '\r') {
  86. state = 0;
  87. } else if (dynar_simple_lex_is_space(ch)) {
  88. pos++;
  89. } else {
  90. state = 2;
  91. }
  92. break;
  93. case 2:
  94. /*
  95. * Read word
  96. */
  97. if (pos >= size) {
  98. state = 0;
  99. } else if ((lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_BACKSLASH ||
  100. lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_QUOTE) && ch == '\\') {
  101. pos++;
  102. state = 3;
  103. } else if (lex->lex_type == DYNAR_SIMPLE_LEX_TYPE_QUOTE &&
  104. ch == '"') {
  105. pos++;
  106. state = 4;
  107. } else if (dynar_simple_lex_is_space(ch)) {
  108. state = 0;
  109. } else {
  110. pos++;
  111. add_char = 1;
  112. }
  113. break;
  114. case 3:
  115. /*
  116. * Process backslash
  117. */
  118. if (pos >= size || ch == '\n' || ch == '\r') {
  119. /*
  120. * End of string. Do not include backslash (it's just ignored)
  121. */
  122. state = 0;
  123. } else {
  124. add_char = 1;
  125. state = 2;
  126. pos++;
  127. }
  128. break;
  129. case 4:
  130. /*
  131. * Quote word
  132. */
  133. if (pos >= size) {
  134. state = 0;
  135. } else if (ch == '\\') {
  136. state = 5;
  137. pos++;
  138. } else if (ch == '"') {
  139. state = 2;
  140. pos++;
  141. } else if (ch == '\n' || ch == '\r') {
  142. state = 0;
  143. } else {
  144. pos++;
  145. add_char = 1;
  146. }
  147. break;
  148. case 5:
  149. /*
  150. * Quote word backslash
  151. */
  152. if (pos >= size || ch == '\n' || ch == '\r') {
  153. /*
  154. * End of string. Do not include backslash (it's just ignored)
  155. */
  156. state = 0;
  157. } else if (ch == '\\' || ch == '"') {
  158. add_char = 1;
  159. state = 4;
  160. pos++;
  161. } else {
  162. ch2 = '\\';
  163. if (dynar_cat(&lex->token, &ch2, sizeof(ch2)) != 0) {
  164. return (NULL);
  165. }
  166. add_char = 1;
  167. state = 4;
  168. pos++;
  169. }
  170. break;
  171. }
  172. if (add_char) {
  173. if (dynar_cat(&lex->token, &ch, sizeof(ch)) != 0) {
  174. return (NULL);
  175. }
  176. }
  177. }
  178. ch = '\0';
  179. if (dynar_cat(&lex->token, &ch, sizeof(ch)) != 0) {
  180. return (NULL);
  181. }
  182. lex->pos = pos;
  183. return (&lex->token);
  184. }