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