!ENDDEFINE in a string or comment doesn't count.
[pspp] / src / language / lexer / segment.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011, 2013, 2016 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/segment.h"
20
21 #include <limits.h>
22 #include <unistr.h>
23
24 #include "data/identifier.h"
25 #include "language/lexer/command-name.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/cast.h"
28
29 #include "gl/c-ctype.h"
30 #include "gl/c-strcase.h"
31 #include "gl/verify.h"
32
33 enum segmenter_state
34   {
35     S_SHBANG,
36     S_GENERAL,
37     S_COMMENT_1,
38     S_COMMENT_2,
39     S_DOCUMENT_1,
40     S_DOCUMENT_2,
41     S_DOCUMENT_3,
42     S_FILE_LABEL_1,
43     S_FILE_LABEL_2,
44     S_FILE_LABEL_3,
45     S_DO_REPEAT_1,
46     S_DO_REPEAT_2,
47     S_DO_REPEAT_3,
48     S_DEFINE_1,
49     S_DEFINE_2,
50     S_DEFINE_3,
51     S_DEFINE_4,
52     S_BEGIN_DATA_1,
53     S_BEGIN_DATA_2,
54     S_BEGIN_DATA_3,
55     S_BEGIN_DATA_4,
56   };
57
58 #define SS_START_OF_LINE (1u << 0)
59 #define SS_START_OF_COMMAND (1u << 1)
60
61 static int segmenter_detect_command_name__ (const char *input,
62                                             size_t n, bool eof, int ofs);
63
64 static int
65 segmenter_u8_to_uc__ (ucs4_t *puc, const char *input_, size_t n, bool eof,
66                       size_t ofs)
67 {
68   const uint8_t *input = CHAR_CAST (const uint8_t *, input_);
69   int mblen;
70
71   assert (n > ofs);
72
73   input += ofs;
74   n -= ofs;
75
76   mblen = u8_mbtoucr (puc, input, n);
77   if (mblen >= 0)
78     return mblen;
79   else if (mblen != -2)
80     return u8_mbtouc (puc, input, n);
81   else if (eof)
82     {
83       *puc = 0xfffd;
84       return n;
85     }
86   else
87     return -1;
88 }
89
90 static int
91 segmenter_parse_shbang__ (struct segmenter *s, const char *input, size_t n,
92                           bool eof, enum segment_type *type)
93 {
94   if (input[0] == '#')
95     {
96       if (n >= 2)
97         {
98           if (input[1] == '!')
99             {
100               for (int ofs = 2; ; ofs++)
101                 {
102                   if (ofs >= n)
103                     {
104                       if (!eof)
105                         return -1;
106                     }
107                   else if (input[ofs] == '\n')
108                     {
109                       if (input[ofs - 1] == '\r')
110                         ofs--;
111                     }
112                   else
113                     continue;
114
115                   s->state = S_GENERAL;
116                   s->substate = SS_START_OF_COMMAND;
117                   *type = SEG_SHBANG;
118                   return ofs;
119                 }
120             }
121         }
122       else if (!eof)
123         return -1;
124     }
125
126   s->state = S_GENERAL;
127   s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
128   return segmenter_push (s, input, n, eof, type);
129 }
130
131 static int
132 segmenter_parse_digraph__ (const char *seconds, struct segmenter *s,
133                            const char *input, size_t n, bool eof,
134                            enum segment_type *type)
135 {
136   assert (s->state == S_GENERAL);
137
138   *type = SEG_PUNCT;
139   s->substate = 0;
140   return (n < 2
141           ? (eof ? 1 : -1)
142           : (strchr (seconds, input[1]) != NULL ? 2 : 1));
143 }
144
145 static int
146 skip_comment (const char *input, size_t n, bool eof, size_t ofs)
147 {
148   for (; ofs < n; ofs++)
149     {
150       if (input[ofs] == '\n')
151         return ofs;
152       else if (input[ofs] == '*')
153         {
154           if (ofs + 1 >= n)
155             return eof ? ofs + 1 : -1;
156           else if (input[ofs + 1] == '/')
157             return ofs + 2;
158         }
159     }
160   return eof ? ofs : -1;
161 }
162
163 static int
164 skip_spaces_and_comments (const char *input, size_t n, bool eof, int ofs)
165 {
166   while (ofs < n)
167     {
168       ucs4_t uc;
169       int mblen;
170
171       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
172       if (mblen < 0)
173         return -1;
174
175       if (uc == '/')
176         {
177           if (ofs + 1 >= n)
178             return eof ? ofs : -1;
179           else if (input[ofs + 1] != '*')
180             return ofs;
181
182           ofs = skip_comment (input, n, eof, ofs + 2);
183           if (ofs < 0)
184             return -1;
185         }
186       else if (lex_uc_is_space (uc) && uc != '\n')
187         ofs += mblen;
188       else
189         return ofs;
190     }
191
192   return eof ? ofs : -1;
193 }
194
195 static int
196 is_end_of_line (const char *input, size_t n, bool eof, int ofs)
197 {
198   if (ofs >= n)
199     return eof ? 1 : -1;
200   else if (input[ofs] == '\n')
201     return 1;
202   else if (input[ofs] == '\r')
203     {
204       if (ofs + 1 >= n)
205         return eof ? 1 : -1;
206       return input[ofs + 1] == '\n';
207     }
208   else
209     return 0;
210 }
211
212 static int
213 at_end_of_line (const char *input, size_t n, bool eof, int ofs)
214 {
215   ofs = skip_spaces_and_comments (input, n, eof, ofs);
216   if (ofs < 0)
217     return -1;
218
219   return is_end_of_line (input, n, eof, ofs);
220 }
221
222 static bool
223 is_all_spaces (const char *input_, size_t n)
224 {
225   const uint8_t *input = CHAR_CAST (const uint8_t *, input_);
226
227   int mblen;
228   for (int ofs = 0; ofs < n; ofs += mblen)
229     {
230       ucs4_t uc;
231       mblen = u8_mbtouc (&uc, input + ofs, n - ofs);
232       if (!lex_uc_is_space (uc))
233         return false;
234     }
235   return true;
236 }
237
238 static int
239 segmenter_parse_newline__ (const char *input, size_t n, bool eof,
240                            enum segment_type *type)
241 {
242   int ofs;
243
244   if (input[0] == '\n')
245     ofs = 1;
246   else
247     {
248       if (n < 2)
249         {
250           assert (!eof);
251           return -1;
252         }
253
254       assert (input[0] == '\r');
255       assert (input[1] == '\n');
256       ofs = 2;
257     }
258
259   *type = SEG_NEWLINE;
260   return ofs;
261 }
262
263 static int
264 skip_spaces (const char *input, size_t n, bool eof, size_t ofs)
265 {
266   while (ofs < n)
267     {
268       ucs4_t uc;
269       int mblen;
270
271       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
272       if (mblen < 0)
273         return -1;
274
275       if (!lex_uc_is_space (uc) || uc == '\n')
276         return ofs;
277
278       ofs += mblen;
279     }
280
281   return eof ? ofs : -1;
282 }
283
284 static int
285 skip_digits (const char *input, size_t n, bool eof, int ofs)
286 {
287   for (; ofs < n; ofs++)
288     if (!c_isdigit (input[ofs]))
289       return ofs;
290   return eof ? ofs : -1;
291 }
292
293 static int
294 segmenter_parse_number__ (struct segmenter *s, const char *input, size_t n,
295                           bool eof, enum segment_type *type)
296 {
297   int ofs;
298
299   assert (s->state == S_GENERAL);
300
301   ofs = skip_digits (input, n, eof, 0);
302   if (ofs < 0)
303     return -1;
304
305   if (ofs >= n)
306     {
307       if (!eof)
308         return -1;
309       goto number;
310     }
311   if (input[ofs] == '.')
312     {
313       if (ofs + 1 >= n)
314         {
315           if (!eof)
316             return -1;
317           goto number;
318         }
319
320       ofs = skip_digits (input, n, eof, ofs + 1);
321       if (ofs < 0)
322         return -1;
323       else if (ofs >= n)
324         goto number;
325     }
326
327   if (input[ofs] == 'e' || input[ofs] == 'E')
328     {
329       ofs++;
330       if (ofs >= n)
331         {
332           if (!eof)
333             return -1;
334           goto expected_exponent;
335         }
336
337       if (input[ofs] == '+' || input[ofs] == '-')
338         {
339           ofs++;
340           if (ofs >= n)
341             {
342               if (!eof)
343                 return -1;
344               goto expected_exponent;
345             }
346         }
347
348       if (!c_isdigit (input[ofs]))
349         goto expected_exponent;
350
351       ofs = skip_digits (input, n, eof, ofs);
352       if (ofs < 0)
353         return -1;
354     }
355
356   if (input[ofs - 1] == '.')
357     {
358       int eol = at_end_of_line (input, n, eof, ofs);
359       if (eol < 0)
360         return -1;
361       else if (eol)
362         ofs--;
363     }
364
365 number:
366   *type = SEG_NUMBER;
367   s->substate = 0;
368   return ofs;
369
370 expected_exponent:
371   *type = SEG_EXPECTED_EXPONENT;
372   s->substate = 0;
373   return ofs;
374 }
375
376 static bool
377 is_reserved_word (const char *s, int n)
378 {
379   char s0, s1, s2, s3;
380
381   s0 = c_toupper (s[0]);
382   switch (n)
383     {
384     case 2:
385       s1 = c_toupper (s[1]);
386       return ((s0 == 'B' && s1 == 'Y')
387               || (s0 == 'E' && s1 == 'Q')
388               || (s0 == 'G' && (s1 == 'E' || s1 == 'T'))
389               || (s0 == 'L' && (s1 == 'E' || s1 == 'T'))
390               || (s0 == 'N' && s1 == 'E')
391               || (s0 == 'O' && s1 == 'R')
392               || (s0 == 'T' && s1 == 'O'));
393
394     case 3:
395       s1 = c_toupper (s[1]);
396       s2 = c_toupper (s[2]);
397       return ((s0 == 'A' && ((s1 == 'L' && s2 == 'L')
398                              || (s1 == 'N' && s2 == 'D')))
399               || (s0 == 'N' && s1 == 'O' && s2 == 'T'));
400
401     case 4:
402       s1 = c_toupper (s[1]);
403       s2 = c_toupper (s[2]);
404       s3 = c_toupper (s[3]);
405       return s0 == 'W' && s1 == 'I' && s2 == 'T' && s3 == 'H';
406
407     default:
408       return false;
409     }
410 }
411
412 static int
413 segmenter_parse_comment_1__ (struct segmenter *s,
414                              const char *input, size_t n, bool eof,
415                              enum segment_type *type)
416 {
417   int endcmd;
418   int ofs;
419
420   endcmd = -2;
421   ofs = 0;
422   while (ofs < n)
423     {
424       ucs4_t uc;
425       int mblen;
426
427       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
428       if (mblen < 0)
429         return -1;
430
431       switch (uc)
432         {
433         case '.':
434           endcmd = ofs;
435           break;
436
437         case '\n':
438           if (ofs > 1 && input[ofs - 1] == '\r')
439             ofs--;
440           if (endcmd == -2)
441             {
442               /* Blank line ends comment command. */
443               s->state = S_GENERAL;
444               s->substate = SS_START_OF_COMMAND;
445               *type = SEG_SEPARATE_COMMANDS;
446               return ofs;
447             }
448           else if (endcmd >= 0)
449             {
450               /* '.' at end of line ends comment command. */
451               s->state = S_GENERAL;
452               s->substate = 0;
453               *type = SEG_COMMENT_COMMAND;
454               return endcmd;
455             }
456           else
457             {
458               /* Comment continues onto next line. */
459               *type = SEG_COMMENT_COMMAND;
460               s->state = S_COMMENT_2;
461               return ofs;
462             }
463           NOT_REACHED ();
464
465         default:
466           if (!lex_uc_is_space (uc))
467             endcmd = -1;
468           break;
469         }
470
471       ofs += mblen;
472     }
473
474   if (eof)
475     {
476       /* End of file. */
477       s->state = S_GENERAL;
478       s->substate = SS_START_OF_COMMAND;
479       *type = SEG_SEPARATE_COMMANDS;
480       return ofs;
481     }
482
483   return -1;
484 }
485
486 static int
487 segmenter_parse_comment_2__ (struct segmenter *s, const char *input,
488                              size_t n, bool eof, enum segment_type *type)
489 {
490   int ofs = segmenter_parse_newline__ (input, n, eof, type);
491   if (ofs < 0)
492     return -1;
493
494   int new_cmd;
495   if (ofs >= n)
496     {
497       if (!eof)
498         return -1;
499       new_cmd = false;
500     }
501   else
502     {
503       ucs4_t uc;
504       int mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
505       if (mblen < 0)
506         return -1;
507
508       if (uc == '+' || uc == '-' || uc == '.')
509         new_cmd = true;
510       else if (!lex_uc_is_space (uc))
511         switch (s->mode)
512           {
513           case SEG_MODE_INTERACTIVE:
514             new_cmd = false;
515             break;
516
517           case SEG_MODE_BATCH:
518             new_cmd = true;
519             break;
520
521           case SEG_MODE_AUTO:
522             new_cmd = segmenter_detect_command_name__ (input, n, eof, ofs);
523             if (new_cmd < 0)
524               return -1;
525             break;
526
527           default:
528             NOT_REACHED ();
529           }
530       else
531         new_cmd = false;
532     }
533
534   if (new_cmd)
535     {
536       s->state = S_GENERAL;
537       s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
538     }
539   else
540     s->state = S_COMMENT_1;
541   return ofs;
542 }
543
544 static int
545 segmenter_parse_document_1__ (struct segmenter *s, const char *input, size_t n,
546                               bool eof, enum segment_type *type)
547 {
548   bool end_cmd;
549   int ofs;
550
551   end_cmd = false;
552   ofs = 0;
553   while (ofs < n)
554     {
555       ucs4_t uc;
556       int mblen;
557
558       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
559       if (mblen < 0)
560         return -1;
561
562       switch (uc)
563         {
564         case '.':
565           end_cmd = true;
566           break;
567
568         case '\n':
569           if (ofs > 1 && input[ofs - 1] == '\r')
570             ofs--;
571
572           *type = SEG_DOCUMENT;
573           s->state = end_cmd ? S_DOCUMENT_3 : S_DOCUMENT_2;
574           return ofs;
575
576         default:
577           if (!lex_uc_is_space (uc))
578             end_cmd = false;
579           break;
580         }
581
582       ofs += mblen;
583     }
584   if (eof)
585     {
586       *type = SEG_DOCUMENT;
587       s->state = S_DOCUMENT_3;
588       return ofs;
589     }
590   return -1;
591 }
592
593 static int
594 segmenter_parse_document_2__ (struct segmenter *s, const char *input, size_t n,
595                               bool eof, enum segment_type *type)
596 {
597   int ofs;
598
599   ofs = segmenter_parse_newline__ (input, n, eof, type);
600   if (ofs < 0)
601     return -1;
602
603   s->state = S_DOCUMENT_1;
604   return ofs;
605 }
606
607 static int
608 segmenter_parse_document_3__ (struct segmenter *s, enum segment_type *type)
609 {
610   *type = SEG_END_COMMAND;
611   s->state = S_GENERAL;
612   s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
613   return 0;
614 }
615
616 static int
617 segmenter_unquoted (const char *input, size_t n, bool eof, int ofs)
618
619 {
620   ofs = skip_spaces_and_comments (input, n, eof, ofs);
621   if (ofs < 0)
622     return -1;
623   else if (ofs < n)
624     {
625       char c = input[ofs];
626       return c != '\'' && c != '"' && c != '\n';
627     }
628   else
629     {
630       assert (eof);
631       return 0;
632     }
633 }
634
635 static int
636 next_id_in_command (const struct segmenter *s, const char *input, size_t n,
637                     bool eof, int ofs, char id[], size_t id_size)
638 {
639   struct segmenter sub;
640
641   assert (id_size > 0);
642
643   sub.mode = s->mode;
644   sub.state = S_GENERAL;
645   sub.substate = 0;
646   for (;;)
647     {
648       enum segment_type type;
649       int retval;
650
651       retval = segmenter_push (&sub, input + ofs, n - ofs, eof, &type);
652       if (retval < 0)
653         {
654           id[0] = '\0';
655           return -1;
656         }
657
658       switch (type)
659         {
660         case SEG_SHBANG:
661         case SEG_SPACES:
662         case SEG_COMMENT:
663         case SEG_NEWLINE:
664           break;
665
666         case SEG_IDENTIFIER:
667           if (retval < id_size)
668             {
669               memcpy (id, input + ofs, retval);
670               id[retval] = '\0';
671               return ofs + retval;
672             }
673           /* fall through */
674
675         case SEG_NUMBER:
676         case SEG_QUOTED_STRING:
677         case SEG_HEX_STRING:
678         case SEG_UNICODE_STRING:
679         case SEG_UNQUOTED_STRING:
680         case SEG_RESERVED_WORD:
681         case SEG_PUNCT:
682         case SEG_COMMENT_COMMAND:
683         case SEG_DO_REPEAT_COMMAND:
684         case SEG_INLINE_DATA:
685         case SEG_MACRO_ID:
686         case SEG_MACRO_BODY:
687         case SEG_START_DOCUMENT:
688         case SEG_DOCUMENT:
689         case SEG_START_COMMAND:
690         case SEG_SEPARATE_COMMANDS:
691         case SEG_END_COMMAND:
692         case SEG_END:
693         case SEG_EXPECTED_QUOTE:
694         case SEG_EXPECTED_EXPONENT:
695         case SEG_UNEXPECTED_CHAR:
696           id[0] = '\0';
697           return ofs + retval;
698         }
699       ofs += retval;
700     }
701 }
702
703 /* Called when INPUT begins with a character that can start off an ID token. */
704 static int
705 segmenter_parse_id__ (struct segmenter *s, const char *input, size_t n,
706                       bool eof, enum segment_type *type)
707 {
708   ucs4_t uc;
709   int ofs;
710
711   assert (n > 0);
712   assert (s->state == S_GENERAL);
713
714   ofs = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, input), n);
715   for (;;)
716     {
717       int mblen;
718
719       if (ofs >= n)
720         {
721           if (eof)
722             break;
723           return -1;
724         }
725
726       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
727       if (mblen < 0)
728         return -1;
729       else if (!lex_uc_is_idn (uc))
730         break;
731
732       ofs += mblen;
733     }
734
735   if (input[ofs - 1] == '.')
736     {
737       int eol = at_end_of_line (input, n, eof, ofs);
738       if (eol < 0)
739         return -1;
740       else if (eol)
741         ofs--;
742     }
743
744   *type = (is_reserved_word (input, ofs) ? SEG_RESERVED_WORD
745            : input[0] == '!' ? SEG_MACRO_ID
746            : SEG_IDENTIFIER);
747
748   if (s->substate & SS_START_OF_COMMAND)
749     {
750       struct substring word = ss_buffer (input, ofs);
751
752       if (lex_id_match_n (ss_cstr ("COMMENT"), word, 4))
753         {
754           s->state = S_COMMENT_1;
755           return segmenter_parse_comment_1__ (s, input, n, eof, type);
756         }
757       else if (lex_id_match (ss_cstr ("DOCUMENT"), word))
758         {
759           s->state = S_DOCUMENT_1;
760           *type = SEG_START_DOCUMENT;
761           return 0;
762         }
763       else if (lex_id_match_n (ss_cstr ("DEFINE"), word, 6))
764         {
765           s->state = S_DEFINE_1;
766           return ofs;
767         }
768       else if (lex_id_match (ss_cstr ("FILE"), word))
769         {
770           char id[16];
771
772           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
773             return -1;
774           else if (lex_id_match (ss_cstr ("LABEL"), ss_cstr (id)))
775             {
776               s->state = S_FILE_LABEL_1;
777               s->substate = 0;
778               return ofs;
779             }
780         }
781       else if (lex_id_match (ss_cstr ("DO"), word))
782         {
783           char id[16];
784
785           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
786             return -1;
787           else if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
788             {
789               s->state = S_DO_REPEAT_1;
790               s->substate = 0;
791               return ofs;
792             }
793         }
794       else if (lex_id_match (ss_cstr ("BEGIN"), word))
795         {
796           char id[16];
797           int ofs2;
798
799           ofs2 = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
800           if (ofs2 < 0)
801             return -1;
802           else if (lex_id_match (ss_cstr ("DATA"), ss_cstr (id)))
803             {
804               int eol;
805
806               ofs2 = skip_spaces_and_comments (input, n, eof, ofs2);
807               if (ofs2 < 0)
808                 return -1;
809
810               if (ofs2 >= n)
811                 assert (eof);
812               else if (input[ofs2] == '.')
813                 {
814                   ofs2 = skip_spaces_and_comments (input, n, eof, ofs2 + 1);
815                   if (ofs2 < 0)
816                     return -1;
817                 }
818
819               eol = is_end_of_line (input, n, eof, ofs2);
820               if (eol < 0)
821                 return -1;
822               else if (eol)
823                 {
824                   if (memchr (input, '\n', ofs2))
825                     s->state = S_BEGIN_DATA_1;
826                   else
827                     s->state = S_BEGIN_DATA_2;
828                   s->substate = 0;
829                   return ofs;
830                 }
831             }
832         }
833     }
834
835   s->substate = 0;
836   return ofs;
837 }
838
839 static int
840 segmenter_parse_string__ (enum segment_type string_type,
841                           int ofs, struct segmenter *s,
842                           const char *input, size_t n, bool eof,
843                           enum segment_type *type)
844 {
845   int quote = input[ofs];
846
847   ofs++;
848   while (ofs < n)
849     if (input[ofs] == quote)
850       {
851         ofs++;
852         if (ofs < n)
853           {
854             if (input[ofs] == quote)
855               {
856                 ofs++;
857                 continue;
858               }
859           }
860         else if (!eof)
861           return -1;
862
863         *type = string_type;
864         s->substate = 0;
865         return ofs;
866       }
867     else if (input[ofs] == '\n')
868       goto expected_quote;
869     else
870       ofs++;
871
872   if (eof)
873     goto expected_quote;
874
875   return -1;
876
877 expected_quote:
878   *type = SEG_EXPECTED_QUOTE;
879   s->substate = 0;
880   return ofs;
881 }
882
883 static int
884 segmenter_maybe_parse_string__ (enum segment_type string_type,
885                                 struct segmenter *s,
886                                 const char *input, size_t n, bool eof,
887                                 enum segment_type *type)
888 {
889   if (n < 2)
890     {
891       if (!eof)
892         return -1;
893     }
894   else if (input[1] == '\'' || input[1] == '"')
895     return segmenter_parse_string__ (string_type, 1, s, input, n, eof, type);
896
897   return segmenter_parse_id__ (s, input, n, eof, type);
898 }
899
900 static int
901 segmenter_parse_mid_command__ (struct segmenter *s,
902                                const char *input, size_t n, bool eof,
903                                enum segment_type *type)
904 {
905   ucs4_t uc;
906   int mblen;
907   int ofs;
908
909   assert (s->state == S_GENERAL);
910   assert (!(s->substate & SS_START_OF_LINE));
911
912   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
913   if (mblen < 0)
914     return -1;
915
916   switch (uc)
917     {
918     case '\n':
919       s->substate |= SS_START_OF_LINE;
920       *type = SEG_NEWLINE;
921       return 1;
922
923     case '/':
924       if (n < 2)
925         {
926           if (!eof)
927             return -1;
928         }
929       else if (input[1] == '*')
930         {
931           ofs = skip_comment (input, n, eof, 2);
932           if (ofs < 0)
933             return -1;
934
935           *type = SEG_COMMENT;
936           return ofs;
937         }
938
939       s->substate = 0;
940       *type = SEG_PUNCT;
941       return 1;
942
943     case '(': case ')': case ',': case '=': case '-':
944     case '[': case ']': case '&': case '|': case '+':
945       *type = SEG_PUNCT;
946       s->substate = 0;
947       return 1;
948
949     case '*':
950       if (s->substate & SS_START_OF_COMMAND)
951         {
952           /* '*' at the beginning of a command begins a comment. */
953           s->state = S_COMMENT_1;
954           return segmenter_parse_comment_1__ (s, input, n, eof, type);
955         }
956       else
957         return segmenter_parse_digraph__ ("*", s, input, n, eof, type);
958
959     case '<':
960       return segmenter_parse_digraph__ ("=>", s, input, n, eof, type);
961
962     case '>':
963       return segmenter_parse_digraph__ ("=", s, input, n, eof, type);
964
965     case '~':
966       return segmenter_parse_digraph__ ("=", s, input, n, eof, type);
967
968     case '.':
969       if (n < 2)
970         {
971           if (!eof)
972             return -1;
973         }
974       else if (c_isdigit (input[1]))
975         return segmenter_parse_number__ (s, input, n, eof, type);
976
977       int eol = at_end_of_line (input, n, eof, 1);
978       if (eol < 0)
979         return -1;
980
981       if (eol)
982         {
983           *type = SEG_END_COMMAND;
984           s->substate = SS_START_OF_COMMAND;
985         }
986       else
987         *type = SEG_PUNCT;
988       return 1;
989
990     case '0': case '1': case '2': case '3': case '4':
991     case '5': case '6': case '7': case '8': case '9':
992       return segmenter_parse_number__ (s, input, n, eof, type);
993
994     case 'u': case 'U':
995       return segmenter_maybe_parse_string__ (SEG_UNICODE_STRING,
996                                              s, input, n, eof, type);
997
998     case 'x': case 'X':
999       return segmenter_maybe_parse_string__ (SEG_HEX_STRING,
1000                                              s, input, n, eof, type);
1001
1002     case '\'': case '"':
1003       return segmenter_parse_string__ (SEG_QUOTED_STRING, 0,
1004                                        s, input, n, eof, type);
1005
1006     case '!':
1007       return segmenter_parse_id__ (s, input, n, eof, type);
1008
1009     default:
1010       if (lex_uc_is_space (uc))
1011         {
1012           ofs = skip_spaces (input, n, eof, mblen);
1013           if (ofs < 0)
1014             return -1;
1015
1016           if (input[ofs - 1] == '\r' && input[ofs] == '\n')
1017             {
1018               if (ofs == 1)
1019                 {
1020                   s->substate |= SS_START_OF_LINE;
1021                   *type = SEG_NEWLINE;
1022                   return 2;
1023                 }
1024               else
1025                 ofs--;
1026             }
1027           *type = SEG_SPACES;
1028           return ofs;
1029         }
1030       else if (lex_uc_is_id1 (uc))
1031         return segmenter_parse_id__ (s, input, n, eof, type);
1032       else if (uc > 32 && uc < 127 && uc != '\\' && uc != '^')
1033         {
1034           *type = SEG_PUNCT;
1035           s->substate = 0;
1036           return 1;
1037         }
1038       else
1039         {
1040           *type = SEG_UNEXPECTED_CHAR;
1041           s->substate = 0;
1042           return mblen;
1043         }
1044     }
1045 }
1046
1047 static int
1048 compare_commands (const void *a_, const void *b_)
1049 {
1050   const char *const *ap = a_;
1051   const char *const *bp = b_;
1052   const char *a = *ap;
1053   const char *b = *bp;
1054
1055   return c_strcasecmp (a, b);
1056 }
1057
1058 static const char **
1059 segmenter_get_command_name_candidates (unsigned char first)
1060 {
1061 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) NAME,
1062 #define UNIMPL_CMD(NAME, DESCRIPTION) NAME,
1063   static const char *commands[] =
1064     {
1065 #include "language/command.def"
1066       ""
1067     };
1068   static size_t n_commands = (sizeof commands / sizeof *commands) - 1;
1069 #undef DEF_CMD
1070 #undef UNIMPL_CMD
1071
1072   static bool inited;
1073
1074   static const char **cindex[UCHAR_MAX + 1];
1075
1076   if (!inited)
1077     {
1078       size_t i;
1079
1080       inited = true;
1081
1082       qsort (commands, n_commands, sizeof *commands, compare_commands);
1083       for (i = 0; i < n_commands; i++)
1084         {
1085           unsigned char c = c_toupper (commands[i][0]);
1086           if (cindex[c] == NULL)
1087             cindex[c] = &commands[i];
1088         }
1089       for (i = 0; i <= UCHAR_MAX; i++)
1090         if (cindex[i] == NULL)
1091           cindex[i] = &commands[n_commands];
1092     }
1093
1094   return cindex[c_toupper (first)];
1095 }
1096
1097 static int
1098 segmenter_detect_command_name__ (const char *input, size_t n, bool eof,
1099                                  int ofs)
1100 {
1101   const char **commands;
1102
1103   input += ofs;
1104   n -= ofs;
1105   ofs = 0;
1106   for (;;)
1107     {
1108       ucs4_t uc;
1109       int mblen;
1110
1111       if (ofs >= n)
1112         {
1113           if (eof)
1114             break;
1115           return -1;
1116         }
1117
1118       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1119       if (mblen < 0)
1120         return -1;
1121
1122       if (uc == '\n'
1123           || !(lex_uc_is_space (uc) || lex_uc_is_idn (uc) || uc == '-'))
1124         break;
1125
1126       ofs += mblen;
1127     }
1128   if (!ofs)
1129     return 0;
1130
1131   if (input[ofs - 1] == '.')
1132     ofs--;
1133
1134   for (commands = segmenter_get_command_name_candidates (input[0]);
1135        c_toupper (input[0]) == c_toupper ((*commands)[0]);
1136        commands++)
1137     {
1138       int missing_words;
1139       bool exact;
1140
1141       if (command_match (ss_cstr (*commands), ss_buffer (input, ofs),
1142                          &exact, &missing_words)
1143           && missing_words <= 0)
1144         return 1;
1145     }
1146
1147   return 0;
1148 }
1149
1150 static int
1151 is_start_of_string__ (const char *input, size_t n, bool eof, int ofs)
1152 {
1153   if (ofs >= n)
1154     return eof ? 0 : -1;
1155
1156   int c = input[ofs];
1157   if (c == 'x' || c == 'X' || c == 'u' || c == 'U')
1158     {
1159       if (ofs + 1 >= n)
1160         return eof ? 0 : -1;
1161
1162       return input[ofs + 1] == '\'' || input[ofs + 1] == '"';
1163     }
1164   else
1165     return c == '\'' || c == '"' || c == '\n';
1166 }
1167
1168 static int
1169 segmenter_parse_start_of_line__ (struct segmenter *s,
1170                                  const char *input, size_t n, bool eof,
1171                                  enum segment_type *type)
1172 {
1173   ucs4_t uc;
1174   int mblen;
1175   int ofs;
1176
1177   assert (s->state == S_GENERAL);
1178   assert (s->substate & SS_START_OF_LINE);
1179
1180   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
1181   if (mblen < 0)
1182     return -1;
1183
1184   switch (uc)
1185     {
1186     case '+':
1187       ofs = skip_spaces_and_comments (input, n, eof, 1);
1188       if (ofs < 0)
1189         return -1;
1190       else
1191         {
1192           int is_string = is_start_of_string__ (input, n, eof, ofs);
1193           if (is_string < 0)
1194             return -1;
1195           else if (is_string)
1196             {
1197               /* This is punctuation that may separate pieces of a string. */
1198               *type = SEG_PUNCT;
1199               s->substate = 0;
1200               return 1;
1201             }
1202         }
1203       /* Fall through. */
1204
1205     case '-':
1206     case '.':
1207       *type = SEG_START_COMMAND;
1208       s->substate = SS_START_OF_COMMAND;
1209       return 1;
1210
1211     default:
1212       if (lex_uc_is_space (uc))
1213         {
1214           int eol = at_end_of_line (input, n, eof, 0);
1215           if (eol < 0)
1216             return -1;
1217           else if (eol)
1218             {
1219               s->substate = SS_START_OF_COMMAND;
1220               *type = SEG_SEPARATE_COMMANDS;
1221               return 0;
1222             }
1223           break;
1224         }
1225
1226       if (s->mode == SEG_MODE_INTERACTIVE || s->substate & SS_START_OF_COMMAND)
1227         break;
1228       else if (s->mode == SEG_MODE_AUTO)
1229         {
1230           int cmd = segmenter_detect_command_name__ (input, n, eof, 0);
1231           if (cmd < 0)
1232             return -1;
1233           else if (cmd == 0)
1234             break;
1235         }
1236       else
1237         assert (s->mode == SEG_MODE_BATCH);
1238
1239       s->substate = SS_START_OF_COMMAND;
1240       *type = SEG_START_COMMAND;
1241       return 0;
1242     }
1243
1244   s->substate = SS_START_OF_COMMAND;
1245   return segmenter_parse_mid_command__ (s, input, n, eof, type);
1246 }
1247
1248 static int
1249 segmenter_parse_file_label_1__ (struct segmenter *s,
1250                                 const char *input, size_t n, bool eof,
1251                                 enum segment_type *type)
1252 {
1253   struct segmenter sub;
1254   int ofs;
1255
1256   sub = *s;
1257   sub.state = S_GENERAL;
1258   ofs = segmenter_push (&sub, input, n, eof, type);
1259
1260   if (ofs < 0)
1261     return -1;
1262   else if (*type == SEG_IDENTIFIER)
1263     {
1264       int result;
1265
1266       assert (lex_id_match (ss_cstr ("LABEL"),
1267                             ss_buffer ((char *) input, ofs)));
1268       result = segmenter_unquoted (input, n, eof, ofs);
1269       if (result < 0)
1270         return -1;
1271       else
1272         {
1273           if (result)
1274             s->state = S_FILE_LABEL_2;
1275           else
1276             *s = sub;
1277           return ofs;
1278         }
1279     }
1280   else
1281     {
1282       s->substate = sub.substate;
1283       return ofs;
1284     }
1285 }
1286
1287 static int
1288 segmenter_parse_file_label_2__ (struct segmenter *s,
1289                                 const char *input, size_t n, bool eof,
1290                                 enum segment_type *type)
1291 {
1292   int ofs;
1293
1294   ofs = skip_spaces (input, n, eof, 0);
1295   if (ofs < 0)
1296     return -1;
1297   s->state = S_FILE_LABEL_3;
1298   *type = SEG_SPACES;
1299   return ofs;
1300 }
1301
1302 static int
1303 segmenter_parse_file_label_3__ (struct segmenter *s,
1304                                 const char *input, size_t n, bool eof,
1305                                 enum segment_type *type)
1306 {
1307   int endcmd;
1308   int ofs;
1309
1310   endcmd = -1;
1311   ofs = 0;
1312   while (ofs < n)
1313     {
1314       ucs4_t uc;
1315       int mblen;
1316
1317       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1318       if (mblen < 0)
1319         return -1;
1320
1321       switch (uc)
1322         {
1323         case '\n':
1324           goto end_of_line;
1325
1326         case '.':
1327           endcmd = ofs;
1328           break;
1329
1330         default:
1331           if (!lex_uc_is_space (uc))
1332             endcmd = -1;
1333           break;
1334         }
1335
1336       ofs += mblen;
1337     }
1338
1339   if (eof)
1340     {
1341     end_of_line:
1342       s->state = S_GENERAL;
1343       s->substate = 0;
1344       *type = SEG_UNQUOTED_STRING;
1345       return endcmd >= 0 ? endcmd : ofs;
1346     }
1347
1348   return -1;
1349 }
1350
1351 static int
1352 segmenter_subparse (struct segmenter *s,
1353                     const char *input, size_t n, bool eof,
1354                     enum segment_type *type)
1355 {
1356   struct segmenter sub;
1357   int ofs;
1358
1359   sub.mode = s->mode;
1360   sub.state = S_GENERAL;
1361   sub.substate = s->substate;
1362   ofs = segmenter_push (&sub, input, n, eof, type);
1363   s->substate = sub.substate;
1364   return ofs;
1365 }
1366
1367 /* We are segmenting a DO REPEAT command, currently reading the syntax that
1368    defines the stand-in variables (the head) before the lines of syntax to be
1369    repeated (the body). */
1370 static int
1371 segmenter_parse_do_repeat_1__ (struct segmenter *s,
1372                                const char *input, size_t n, bool eof,
1373                                enum segment_type *type)
1374 {
1375   int ofs = segmenter_subparse (s, input, n, eof, type);
1376   if (ofs < 0)
1377     return -1;
1378
1379   if (*type == SEG_SEPARATE_COMMANDS)
1380     {
1381       /* We reached a blank line that separates the head from the body. */
1382       s->state = S_DO_REPEAT_2;
1383     }
1384   else if (*type == SEG_END_COMMAND || *type == SEG_START_COMMAND)
1385     {
1386       /* We reached the body. */
1387       s->state = S_DO_REPEAT_3;
1388       s->substate = 1;
1389     }
1390
1391   return ofs;
1392 }
1393
1394 /* We are segmenting a DO REPEAT command, currently reading a blank line that
1395    separates the head from the body. */
1396 static int
1397 segmenter_parse_do_repeat_2__ (struct segmenter *s,
1398                                const char *input, size_t n, bool eof,
1399                                enum segment_type *type)
1400 {
1401   int ofs = segmenter_subparse (s, input, n, eof, type);
1402   if (ofs < 0)
1403     return -1;
1404
1405   if (*type == SEG_NEWLINE)
1406     {
1407       /* We reached the body. */
1408       s->state = S_DO_REPEAT_3;
1409       s->substate = 1;
1410     }
1411
1412   return ofs;
1413 }
1414
1415 static bool
1416 check_repeat_command (struct segmenter *s,
1417                       const char *input, size_t n, bool eof)
1418 {
1419   int direction;
1420   char id[16];
1421   int ofs;
1422
1423   ofs = 0;
1424   if (input[ofs] == '+' || input[ofs] == '-')
1425     ofs++;
1426
1427   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1428   if (ofs < 0)
1429     return false;
1430   else if (lex_id_match (ss_cstr ("DO"), ss_cstr (id)))
1431     direction = 1;
1432   else if (lex_id_match (ss_cstr ("END"), ss_cstr (id)))
1433     direction = -1;
1434   else
1435     return true;
1436
1437   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1438   if (ofs < 0)
1439     return false;
1440
1441   if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
1442     s->substate += direction;
1443   return true;
1444 }
1445
1446 static int
1447 segmenter_parse_full_line__ (const char *input, size_t n, bool eof,
1448                              enum segment_type *type)
1449 {
1450   const char *newline = memchr (input, '\n', n);
1451   if (!newline)
1452     return eof ? n : -1;
1453
1454   ptrdiff_t ofs = newline - input;
1455   if (ofs == 0 || (ofs == 1 && input[0] == '\r'))
1456     {
1457       *type = SEG_NEWLINE;
1458       return ofs + 1;
1459     }
1460   else
1461     return ofs - (input[ofs - 1] == '\r');
1462 }
1463
1464 /* We are in the body of DO REPEAT, segmenting the lines of syntax that are to
1465    be repeated.  Report each line of syntax as a single SEG_DO_REPEAT_COMMAND.
1466
1467    DO REPEAT can be nested, so we look for DO REPEAT...END REPEAT blocks inside
1468    the lines we're segmenting.  s->substate counts the nesting level, starting
1469    at 1. */
1470 static int
1471 segmenter_parse_do_repeat_3__ (struct segmenter *s,
1472                                const char *input, size_t n, bool eof,
1473                                enum segment_type *type)
1474 {
1475   int ofs;
1476
1477   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1478   if (ofs < 0 || (ofs > 0 && input[ofs - 1] == '\n'))
1479     return ofs;
1480   else if (!check_repeat_command (s, input, n, eof) && !eof)
1481     return -1;
1482   else if (s->substate == 0)
1483     {
1484       /* Nesting level dropped to 0, so we've finished reading the DO REPEAT
1485          body. */
1486       s->state = S_GENERAL;
1487       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1488       return segmenter_push (s, input, n, eof, type);
1489     }
1490   else
1491     {
1492       *type = SEG_DO_REPEAT_COMMAND;
1493       return ofs;
1494     }
1495 }
1496
1497 /* We are segmenting a DEFINE command, which consists of:
1498
1499   - The DEFINE keyword.
1500
1501   - Anything but "(".
1502
1503   - "(" followed by a sequence of tokens possibly including balanced parentheses
1504     up to a final ")".
1505
1506   - A sequence of any number of lines, one string per line, ending with
1507     "!ENDDEFINE".  The first line is usually blank (that is, a newline follows
1508     the "(").  The last line usually just has "!ENDDEFINE." on it, but it can
1509     start with other tokens.  The whole DEFINE...!ENDDEFINE can be on a single
1510     line, even.
1511    */
1512 static int
1513 segmenter_parse_define_1__ (struct segmenter *s,
1514                             const char *input, size_t n, bool eof,
1515                             enum segment_type *type)
1516 {
1517   int ofs = segmenter_subparse (s, input, n, eof, type);
1518   if (ofs < 0)
1519     return -1;
1520
1521   if (*type == SEG_SEPARATE_COMMANDS
1522       || *type == SEG_END_COMMAND
1523       || *type == SEG_START_COMMAND)
1524     {
1525       /* The DEFINE command is malformed because we reached its end without
1526          ever hitting a "(" token.  Transition back to general parsing. */
1527       s->state = S_GENERAL;
1528       return ofs;
1529     }
1530   else if (*type == SEG_PUNCT && input[0] == '(')
1531     {
1532       s->state = S_DEFINE_2;
1533       s->nest = 1;
1534       return ofs;
1535     }
1536
1537   return ofs;
1538 }
1539
1540 static int
1541 segmenter_parse_define_2__ (struct segmenter *s,
1542                             const char *input, size_t n, bool eof,
1543                             enum segment_type *type)
1544 {
1545   int ofs = segmenter_subparse (s, input, n, eof, type);
1546   if (ofs < 0)
1547     return -1;
1548
1549   if (*type == SEG_SEPARATE_COMMANDS
1550       || *type == SEG_END_COMMAND
1551       || *type == SEG_START_COMMAND)
1552     {
1553       /* The DEFINE command is malformed because we reached its end before
1554          closing the set of parentheses.  Transition back to general
1555          parsing. */
1556       s->state = S_GENERAL;
1557       return ofs;
1558     }
1559   else if (*type == SEG_PUNCT && input[0] == '(')
1560     {
1561       s->nest++;
1562       return ofs;
1563     }
1564   else if (*type == SEG_PUNCT && input[0] == ')')
1565     {
1566       s->nest--;
1567       if (!s->nest)
1568         {
1569           s->state = S_DEFINE_3;
1570           s->substate = 0;
1571         }
1572       return ofs;
1573     }
1574
1575   return ofs;
1576 }
1577
1578 static size_t
1579 find_enddefine (struct substring input)
1580 {
1581   size_t n = input.length;
1582   const struct substring enddefine = ss_cstr ("!ENDDEFINE");
1583   for (int ofs = 0;;)
1584     {
1585       /* Skip !ENDDEFINE in comment. */
1586       ofs = skip_spaces_and_comments (input.string, n, true, ofs);
1587       if (ofs + enddefine.length > n)
1588         return SIZE_MAX;
1589
1590       char c = input.string[ofs];
1591       if (c == '!'
1592                && ss_equals_case (ss_substr (input, ofs, enddefine.length),
1593                                   enddefine))
1594         return ofs;
1595       else if (c == '\'' || c == '"')
1596         {
1597           /* Skip quoted !ENDDEFINE. */
1598           ofs++;
1599           for (;;)
1600             {
1601               if (ofs >= n)
1602                 return SIZE_MAX;
1603               else if (input.string[ofs++] == c)
1604                 break;
1605             }
1606         }
1607       else
1608         ofs++;
1609     }
1610 }
1611
1612 /* We are in the body of a macro definition, looking for additional lines of
1613    the body or !ENDDEFINE. */
1614 static int
1615 segmenter_parse_define_3__ (struct segmenter *s,
1616                             const char *input, size_t n, bool eof,
1617                             enum segment_type *type)
1618 {
1619   /* Gather a whole line. */
1620   const char *newline = memchr (input, '\n', n);
1621   int ofs = (newline ? newline - input - (newline > input && newline[-1] == '\r')
1622              : eof ? n
1623              : -1);
1624   if (ofs < 0)
1625     return -1;
1626
1627   /* Does the line contain !ENDDEFINE? */
1628   size_t end = find_enddefine (ss_buffer (input, ofs));
1629   if (end == SIZE_MAX)
1630     {
1631       /* No !ENDDEFINE.  We have a full line of macro body.
1632
1633          The line might be blank, whether completely empty or just spaces and
1634          comments.  That's OK: we need to report blank lines because they can
1635          have significance.
1636
1637          However, if the first line of the macro body (the same line as the
1638          closing parenthesis in the argument definition) is blank, we just
1639          report it as spaces because it's not significant. */
1640       *type = (s->substate == 0 && is_all_spaces (input, ofs)
1641                ? SEG_SPACES : SEG_MACRO_BODY);
1642       s->state = S_DEFINE_4;
1643       s->substate = 1;
1644       return ofs;
1645     }
1646   else
1647     {
1648       /* Macro ends at the !ENDDEFINE on this line. */
1649       s->state = S_GENERAL;
1650       s->substate = 0;
1651       if (!end)
1652         {
1653           /* Line starts with !ENDDEFINE. */
1654           return segmenter_push (s, input, n, eof, type);
1655         }
1656       else
1657         {
1658           if (is_all_spaces (input, end))
1659             {
1660               /* Line starts with spaces followed by !ENDDEFINE. */
1661               *type = SEG_SPACES;
1662             }
1663           else
1664             {
1665               /* Line starts with some content followed by !ENDDEFINE. */
1666               *type = SEG_MACRO_BODY;
1667             }
1668           return end;
1669         }
1670     }
1671 }
1672
1673 static int
1674 segmenter_parse_define_4__ (struct segmenter *s,
1675                             const char *input, size_t n, bool eof,
1676                             enum segment_type *type)
1677 {
1678   int ofs = segmenter_parse_newline__ (input, n, eof, type);
1679   if (ofs < 0)
1680     return -1;
1681
1682   s->state = S_DEFINE_3;
1683   return ofs;
1684 }
1685
1686 static int
1687 segmenter_parse_begin_data_1__ (struct segmenter *s,
1688                                 const char *input, size_t n, bool eof,
1689                                 enum segment_type *type)
1690 {
1691   int ofs = segmenter_subparse (s, input, n, eof, type);
1692   if (ofs < 0)
1693     return -1;
1694
1695   if (*type == SEG_NEWLINE)
1696     s->state = S_BEGIN_DATA_2;
1697
1698   return ofs;
1699 }
1700
1701 static int
1702 segmenter_parse_begin_data_2__ (struct segmenter *s,
1703                                 const char *input, size_t n, bool eof,
1704                                 enum segment_type *type)
1705 {
1706   int ofs = segmenter_subparse (s, input, n, eof, type);
1707   if (ofs < 0)
1708     return -1;
1709
1710   if (*type == SEG_NEWLINE)
1711     s->state = S_BEGIN_DATA_3;
1712
1713   return ofs;
1714 }
1715
1716 static bool
1717 is_end_data (const char *input, size_t n)
1718 {
1719   const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
1720   bool endcmd;
1721   ucs4_t uc;
1722   int mblen;
1723   int ofs;
1724
1725   if (n < 4 || c_strncasecmp (input, "END", 3))
1726     return false;
1727
1728   ofs = 3;
1729   mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1730   if (!lex_uc_is_space (uc))
1731     return false;
1732   ofs += mblen;
1733
1734   if (n - ofs < 4 || c_strncasecmp (input + ofs, "DATA", 4))
1735     return false;
1736   ofs += 4;
1737
1738   endcmd = false;
1739   while (ofs < n)
1740     {
1741       mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1742       if (uc == '.')
1743         {
1744           if (endcmd)
1745             return false;
1746           endcmd = true;
1747         }
1748       else if (!lex_uc_is_space (uc))
1749         return false;
1750       ofs += mblen;
1751     }
1752
1753   return true;
1754 }
1755
1756 static int
1757 segmenter_parse_begin_data_3__ (struct segmenter *s,
1758                                 const char *input, size_t n, bool eof,
1759                                 enum segment_type *type)
1760 {
1761   int ofs;
1762
1763   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1764   if (ofs < 0)
1765     return -1;
1766   else if (is_end_data (input, ofs))
1767     {
1768       s->state = S_GENERAL;
1769       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1770       return segmenter_push (s, input, n, eof, type);
1771     }
1772   else
1773     {
1774       *type = SEG_INLINE_DATA;
1775       s->state = S_BEGIN_DATA_4;
1776       return input[ofs - 1] == '\n' ? 0 : ofs;
1777     }
1778 }
1779
1780 static int
1781 segmenter_parse_begin_data_4__ (struct segmenter *s,
1782                                 const char *input, size_t n, bool eof,
1783                                 enum segment_type *type)
1784 {
1785   int ofs;
1786
1787   ofs = segmenter_parse_newline__ (input, n, eof, type);
1788   if (ofs < 0)
1789     return -1;
1790
1791   s->state = S_BEGIN_DATA_3;
1792   return ofs;
1793 }
1794
1795 /* Returns the name of segment TYPE as a string.  The caller must not modify
1796    or free the returned string.
1797
1798    This is useful only for debugging and testing. */
1799 const char *
1800 segment_type_to_string (enum segment_type type)
1801 {
1802   switch (type)
1803     {
1804 #define SEG_TYPE(NAME) case SEG_##NAME: return #NAME;
1805       SEG_TYPES
1806 #undef SEG_TYPE
1807     default:
1808       return "unknown segment type";
1809     }
1810 }
1811
1812 /* Returns a segmenter with the given syntax MODE.
1813
1814    If IS_SNIPPET is false, then the segmenter will parse as if it's being given
1815    a whole file.  This means, for example, that it will interpret - or + at the
1816    beginning of the syntax as a separator between commands (since - or + at the
1817    beginning of a line has this meaning).
1818
1819    If IS_SNIPPET is true, then the segmenter will parse as if it's being given
1820    an isolated piece of syntax.  This means that, for example, that it will
1821    interpret - or + at the beginning of the syntax as an operator token or (if
1822    followed by a digit) as part of a number.
1823
1824    A segmenter does not contain any external references, so nothing needs to be
1825    done to destroy one.  For the same reason, segmenters may be copied with
1826    plain struct assignment (or memcpy). */
1827 struct segmenter
1828 segmenter_init (enum segmenter_mode mode, bool is_snippet)
1829 {
1830   return (struct segmenter) {
1831     .state = is_snippet ? S_GENERAL : S_SHBANG,
1832     .mode = mode,
1833   };
1834 }
1835
1836 /* Returns the mode passed to segmenter_init() for S. */
1837 enum segmenter_mode
1838 segmenter_get_mode (const struct segmenter *s)
1839 {
1840   return s->mode;
1841 }
1842
1843 /* Attempts to label a prefix of S's remaining input with a segment type.  The
1844    caller supplies the first N bytes of the remaining input as INPUT, which
1845    must be a UTF-8 encoded string.  If EOF is true, then the N bytes supplied
1846    are the entire (remainder) of the input; if EOF is false, then further input
1847    is potentially available.
1848
1849    The input may contain '\n' or '\r\n' line ends in any combination.
1850
1851    If successful, returns the number of bytes in the segment at the beginning
1852    of INPUT (between 0 and N, inclusive) and stores the type of that segment
1853    into *TYPE.  The next call to segmenter_push() should not include those
1854    bytes as part of INPUT, because they have (figuratively) been consumed by
1855    the segmenter.
1856
1857    Failure occurs only if the segment type of the N bytes in INPUT cannot yet
1858    be determined.  In this case segmenter_push() returns -1.  If more input is
1859    available, the caller should obtain some more, then call again with a larger
1860    N.  If this is not enough, the process might need to repeat again and agin.
1861    If input is exhausted, then the caller may call again setting EOF to true.
1862    segmenter_push() will never return -1 when EOF is true.
1863
1864    The caller must not, in a sequence of calls, supply contradictory input.
1865    That is, bytes provided as part of INPUT in one call, but not consumed, must
1866    not be provided with *different* values on subsequent calls.  This is
1867    because segmenter_push() must often make decisions based on looking ahead
1868    beyond the bytes that it consumes. */
1869 int
1870 segmenter_push (struct segmenter *s, const char *input, size_t n, bool eof,
1871                 enum segment_type *type)
1872 {
1873   if (!n)
1874     {
1875       if (eof)
1876         {
1877           *type = SEG_END;
1878           return 0;
1879         }
1880       else
1881         return -1;
1882     }
1883
1884   switch (s->state)
1885     {
1886     case S_SHBANG:
1887       return segmenter_parse_shbang__ (s, input, n, eof, type);
1888
1889     case S_GENERAL:
1890       return (s->substate & SS_START_OF_LINE
1891               ? segmenter_parse_start_of_line__ (s, input, n, eof, type)
1892               : segmenter_parse_mid_command__ (s, input, n, eof, type));
1893
1894     case S_COMMENT_1:
1895       return segmenter_parse_comment_1__ (s, input, n, eof, type);
1896     case S_COMMENT_2:
1897       return segmenter_parse_comment_2__ (s, input, n, eof, type);
1898
1899     case S_DOCUMENT_1:
1900       return segmenter_parse_document_1__ (s, input, n, eof, type);
1901     case S_DOCUMENT_2:
1902       return segmenter_parse_document_2__ (s, input, n, eof, type);
1903     case S_DOCUMENT_3:
1904       return segmenter_parse_document_3__ (s, type);
1905
1906     case S_FILE_LABEL_1:
1907       return segmenter_parse_file_label_1__ (s, input, n, eof, type);
1908     case S_FILE_LABEL_2:
1909       return segmenter_parse_file_label_2__ (s, input, n, eof, type);
1910     case S_FILE_LABEL_3:
1911       return segmenter_parse_file_label_3__ (s, input, n, eof, type);
1912
1913     case S_DO_REPEAT_1:
1914       return segmenter_parse_do_repeat_1__ (s, input, n, eof, type);
1915     case S_DO_REPEAT_2:
1916       return segmenter_parse_do_repeat_2__ (s, input, n, eof, type);
1917     case S_DO_REPEAT_3:
1918       return segmenter_parse_do_repeat_3__ (s, input, n, eof, type);
1919
1920     case S_DEFINE_1:
1921       return segmenter_parse_define_1__ (s, input, n, eof, type);
1922     case S_DEFINE_2:
1923       return segmenter_parse_define_2__ (s, input, n, eof, type);
1924     case S_DEFINE_3:
1925       return segmenter_parse_define_3__ (s, input, n, eof, type);
1926     case S_DEFINE_4:
1927       return segmenter_parse_define_4__ (s, input, n, eof, type);
1928
1929     case S_BEGIN_DATA_1:
1930       return segmenter_parse_begin_data_1__ (s, input, n, eof, type);
1931     case S_BEGIN_DATA_2:
1932       return segmenter_parse_begin_data_2__ (s, input, n, eof, type);
1933     case S_BEGIN_DATA_3:
1934       return segmenter_parse_begin_data_3__ (s, input, n, eof, type);
1935     case S_BEGIN_DATA_4:
1936       return segmenter_parse_begin_data_4__ (s, input, n, eof, type);
1937     }
1938
1939   NOT_REACHED ();
1940 }
1941
1942 /* Returns the style of command prompt to display to an interactive user for
1943    input in S.  The return value is most accurate in mode SEG_MODE_INTERACTIVE
1944    and at the beginning of a line (that is, if segmenter_push() consumed as
1945    much as possible of the input up to a new-line).  */
1946 enum prompt_style
1947 segmenter_get_prompt (const struct segmenter *s)
1948 {
1949   switch (s->state)
1950     {
1951     case S_SHBANG:
1952       return PROMPT_FIRST;
1953
1954     case S_GENERAL:
1955       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1956
1957     case S_COMMENT_1:
1958     case S_COMMENT_2:
1959       return PROMPT_COMMENT;
1960
1961     case S_DOCUMENT_1:
1962     case S_DOCUMENT_2:
1963       return PROMPT_DOCUMENT;
1964     case S_DOCUMENT_3:
1965       return PROMPT_FIRST;
1966
1967     case S_FILE_LABEL_1:
1968       return PROMPT_LATER;
1969     case S_FILE_LABEL_2:
1970     case S_FILE_LABEL_3:
1971       return PROMPT_FIRST;
1972
1973     case S_DO_REPEAT_1:
1974     case S_DO_REPEAT_2:
1975       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1976     case S_DO_REPEAT_3:
1977       return PROMPT_DO_REPEAT;
1978
1979     case S_DEFINE_1:
1980     case S_DEFINE_2:
1981       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1982     case S_DEFINE_3:
1983     case S_DEFINE_4:
1984       return PROMPT_DEFINE;
1985
1986     case S_BEGIN_DATA_1:
1987       return PROMPT_FIRST;
1988     case S_BEGIN_DATA_2:
1989       return PROMPT_LATER;
1990     case S_BEGIN_DATA_3:
1991     case S_BEGIN_DATA_4:
1992       return PROMPT_DATA;
1993
1994     }
1995
1996   NOT_REACHED ();
1997 }