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