segment: Allow '.' as separate token with a line, for macros.
[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_CHAR:
680           id[0] = '\0';
681           return ofs + retval;
682         }
683       ofs += retval;
684     }
685 }
686
687 /* Called when INPUT begins with a character that can start off an ID token. */
688 static int
689 segmenter_parse_id__ (struct segmenter *s, const char *input, size_t n,
690                       bool eof, enum segment_type *type)
691 {
692   ucs4_t uc;
693   int ofs;
694
695   assert (n > 0);
696   assert (s->state == S_GENERAL);
697
698   ofs = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, input), n);
699   for (;;)
700     {
701       int mblen;
702
703       if (ofs >= n)
704         {
705           if (eof)
706             break;
707           return -1;
708         }
709
710       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
711       if (mblen < 0)
712         return -1;
713       else if (!lex_uc_is_idn (uc))
714         break;
715
716       ofs += mblen;
717     }
718
719   if (input[ofs - 1] == '.')
720     {
721       int eol = at_end_of_line (input, n, eof, ofs);
722       if (eol < 0)
723         return -1;
724       else if (eol)
725         ofs--;
726     }
727
728   *type = (is_reserved_word (input, ofs) ? SEG_RESERVED_WORD
729            : input[0] == '!' ? SEG_MACRO_ID
730            : SEG_IDENTIFIER);
731
732   if (s->substate & SS_START_OF_COMMAND)
733     {
734       struct substring word = ss_buffer (input, ofs);
735
736       if (lex_id_match_n (ss_cstr ("COMMENT"), word, 4))
737         {
738           s->state = S_COMMENT_1;
739           return segmenter_parse_comment_1__ (s, input, n, eof, type);
740         }
741       else if (lex_id_match (ss_cstr ("DOCUMENT"), word))
742         {
743           s->state = S_DOCUMENT_1;
744           *type = SEG_START_DOCUMENT;
745           return 0;
746         }
747       else if (lex_id_match (ss_cstr ("TITLE"), word)
748                || lex_id_match (ss_cstr ("SUBTITLE"), word))
749         {
750           int result = segmenter_unquoted (input, n, eof, ofs);
751           if (result < 0)
752             return -1;
753           else if (result)
754             {
755               s->state = S_TITLE_1;
756               return ofs;
757             }
758         }
759       else if (lex_id_match_n (ss_cstr ("DEFINE"), word, 6))
760         {
761           s->state = S_DEFINE_1;
762           return ofs;
763         }
764       else if (lex_id_match (ss_cstr ("FILE"), word))
765         {
766           char id[16];
767
768           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
769             return -1;
770           else if (lex_id_match (ss_cstr ("LABEL"), ss_cstr (id)))
771             {
772               s->state = S_FILE_LABEL;
773               s->substate = 0;
774               return ofs;
775             }
776         }
777       else if (lex_id_match (ss_cstr ("DO"), word))
778         {
779           char id[16];
780
781           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
782             return -1;
783           else if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
784             {
785               s->state = S_DO_REPEAT_1;
786               s->substate = 0;
787               return ofs;
788             }
789         }
790       else if (lex_id_match (ss_cstr ("BEGIN"), word))
791         {
792           char id[16];
793           int ofs2;
794
795           ofs2 = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
796           if (ofs2 < 0)
797             return -1;
798           else if (lex_id_match (ss_cstr ("DATA"), ss_cstr (id)))
799             {
800               int eol;
801
802               ofs2 = skip_spaces_and_comments (input, n, eof, ofs2);
803               if (ofs2 < 0)
804                 return -1;
805
806               if (ofs2 >= n)
807                 assert (eof);
808               else if (input[ofs2] == '.')
809                 {
810                   ofs2 = skip_spaces_and_comments (input, n, eof, ofs2 + 1);
811                   if (ofs2 < 0)
812                     return -1;
813                 }
814
815               eol = is_end_of_line (input, n, eof, ofs2);
816               if (eol < 0)
817                 return -1;
818               else if (eol)
819                 {
820                   if (memchr (input, '\n', ofs2))
821                     s->state = S_BEGIN_DATA_1;
822                   else
823                     s->state = S_BEGIN_DATA_2;
824                   s->substate = 0;
825                   return ofs;
826                 }
827             }
828         }
829     }
830
831   s->substate = 0;
832   return ofs;
833 }
834
835 static int
836 segmenter_parse_string__ (enum segment_type string_type,
837                           int ofs, struct segmenter *s,
838                           const char *input, size_t n, bool eof,
839                           enum segment_type *type)
840 {
841   int quote = input[ofs];
842
843   ofs++;
844   while (ofs < n)
845     if (input[ofs] == quote)
846       {
847         ofs++;
848         if (ofs < n)
849           {
850             if (input[ofs] == quote)
851               {
852                 ofs++;
853                 continue;
854               }
855           }
856         else if (!eof)
857           return -1;
858
859         *type = string_type;
860         s->substate = 0;
861         return ofs;
862       }
863     else if (input[ofs] == '\n')
864       goto expected_quote;
865     else
866       ofs++;
867
868   if (eof)
869     goto expected_quote;
870
871   return -1;
872
873 expected_quote:
874   *type = SEG_EXPECTED_QUOTE;
875   s->substate = 0;
876   return ofs;
877 }
878
879 static int
880 segmenter_maybe_parse_string__ (enum segment_type string_type,
881                                 struct segmenter *s,
882                                 const char *input, size_t n, bool eof,
883                                 enum segment_type *type)
884 {
885   if (n < 2)
886     {
887       if (!eof)
888         return -1;
889     }
890   else if (input[1] == '\'' || input[1] == '"')
891     return segmenter_parse_string__ (string_type, 1, s, input, n, eof, type);
892
893   return segmenter_parse_id__ (s, input, n, eof, type);
894 }
895
896 static int
897 segmenter_parse_mid_command__ (struct segmenter *s,
898                                const char *input, size_t n, bool eof,
899                                enum segment_type *type)
900 {
901   ucs4_t uc;
902   int mblen;
903   int ofs;
904
905   assert (s->state == S_GENERAL);
906   assert (!(s->substate & SS_START_OF_LINE));
907
908   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
909   if (mblen < 0)
910     return -1;
911
912   switch (uc)
913     {
914     case '\n':
915       s->substate |= SS_START_OF_LINE;
916       *type = SEG_NEWLINE;
917       return 1;
918
919     case '/':
920       if (n < 2)
921         {
922           if (!eof)
923             return -1;
924         }
925       else if (input[1] == '*')
926         {
927           ofs = skip_comment (input, n, eof, 2);
928           if (ofs < 0)
929             return -1;
930
931           *type = SEG_COMMENT;
932           return ofs;
933         }
934
935       s->substate = 0;
936       *type = SEG_PUNCT;
937       return 1;
938
939     case '(': case ')': case ',': case '=': case '-':
940     case '[': case ']': case '&': case '|': case '+':
941       *type = SEG_PUNCT;
942       s->substate = 0;
943       return 1;
944
945     case '*':
946       if (s->substate & SS_START_OF_COMMAND)
947         {
948           /* '*' at the beginning of a command begins a comment. */
949           s->state = S_COMMENT_1;
950           return segmenter_parse_comment_1__ (s, input, n, eof, type);
951         }
952       else
953         return segmenter_parse_digraph__ ("*", s, input, n, eof, type);
954
955     case '<':
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       if (n < 2)
966         {
967           if (!eof)
968             return -1;
969         }
970       else if (c_isdigit (input[1]))
971         return segmenter_parse_number__ (s, input, n, eof, type);
972
973       int eol = at_end_of_line (input, n, eof, 1);
974       if (eol < 0)
975         return -1;
976
977       if (eol)
978         {
979           *type = SEG_END_COMMAND;
980           s->substate = SS_START_OF_COMMAND;
981         }
982       else
983         *type = SEG_PUNCT;
984       return 1;
985
986     case '0': case '1': case '2': case '3': case '4':
987     case '5': case '6': case '7': case '8': case '9':
988       return segmenter_parse_number__ (s, input, n, eof, type);
989
990     case 'u': case 'U':
991       return segmenter_maybe_parse_string__ (SEG_UNICODE_STRING,
992                                              s, input, n, eof, type);
993
994     case 'x': case 'X':
995       return segmenter_maybe_parse_string__ (SEG_HEX_STRING,
996                                              s, input, n, eof, type);
997
998     case '\'': case '"':
999       return segmenter_parse_string__ (SEG_QUOTED_STRING, 0,
1000                                        s, input, n, eof, type);
1001
1002     case '!':
1003       return segmenter_parse_id__ (s, input, n, eof, type);
1004
1005     default:
1006       if (lex_uc_is_space (uc))
1007         {
1008           ofs = skip_spaces (input, n, eof, mblen);
1009           if (ofs < 0)
1010             return -1;
1011
1012           if (input[ofs - 1] == '\r' && input[ofs] == '\n')
1013             {
1014               if (ofs == 1)
1015                 {
1016                   s->substate |= SS_START_OF_LINE;
1017                   *type = SEG_NEWLINE;
1018                   return 2;
1019                 }
1020               else
1021                 ofs--;
1022             }
1023           *type = SEG_SPACES;
1024           return ofs;
1025         }
1026       else if (lex_uc_is_id1 (uc))
1027         return segmenter_parse_id__ (s, input, n, eof, type);
1028       else if (uc > 32 && uc < 127 && uc != '\\' && uc != '^')
1029         {
1030           *type = SEG_PUNCT;
1031           s->substate = 0;
1032           return 1;
1033         }
1034       else
1035         {
1036           *type = SEG_UNEXPECTED_CHAR;
1037           s->substate = 0;
1038           return mblen;
1039         }
1040     }
1041 }
1042
1043 static int
1044 compare_commands (const void *a_, const void *b_)
1045 {
1046   const char *const *ap = a_;
1047   const char *const *bp = b_;
1048   const char *a = *ap;
1049   const char *b = *bp;
1050
1051   return c_strcasecmp (a, b);
1052 }
1053
1054 static const char **
1055 segmenter_get_command_name_candidates (unsigned char first)
1056 {
1057 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) NAME,
1058 #define UNIMPL_CMD(NAME, DESCRIPTION) NAME,
1059   static const char *commands[] =
1060     {
1061 #include "language/command.def"
1062       ""
1063     };
1064   static size_t n_commands = (sizeof commands / sizeof *commands) - 1;
1065 #undef DEF_CMD
1066 #undef UNIMPL_CMD
1067
1068   static bool inited;
1069
1070   static const char **cindex[UCHAR_MAX + 1];
1071
1072   if (!inited)
1073     {
1074       size_t i;
1075
1076       inited = true;
1077
1078       qsort (commands, n_commands, sizeof *commands, compare_commands);
1079       for (i = 0; i < n_commands; i++)
1080         {
1081           unsigned char c = c_toupper (commands[i][0]);
1082           if (cindex[c] == NULL)
1083             cindex[c] = &commands[i];
1084         }
1085       for (i = 0; i <= UCHAR_MAX; i++)
1086         if (cindex[i] == NULL)
1087           cindex[i] = &commands[n_commands];
1088     }
1089
1090   return cindex[c_toupper (first)];
1091 }
1092
1093 static int
1094 segmenter_detect_command_name__ (const char *input, size_t n, bool eof,
1095                                  int ofs)
1096 {
1097   const char **commands;
1098
1099   input += ofs;
1100   n -= ofs;
1101   ofs = 0;
1102   for (;;)
1103     {
1104       ucs4_t uc;
1105       int mblen;
1106
1107       if (ofs >= n)
1108         {
1109           if (eof)
1110             break;
1111           return -1;
1112         }
1113
1114       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1115       if (mblen < 0)
1116         return -1;
1117
1118       if (uc == '\n'
1119           || !(lex_uc_is_space (uc) || lex_uc_is_idn (uc) || uc == '-'))
1120         break;
1121
1122       ofs += mblen;
1123     }
1124   if (!ofs)
1125     return 0;
1126
1127   if (input[ofs - 1] == '.')
1128     ofs--;
1129
1130   for (commands = segmenter_get_command_name_candidates (input[0]);
1131        c_toupper (input[0]) == c_toupper ((*commands)[0]);
1132        commands++)
1133     {
1134       int missing_words;
1135       bool exact;
1136
1137       if (command_match (ss_cstr (*commands), ss_buffer (input, ofs),
1138                          &exact, &missing_words)
1139           && missing_words <= 0)
1140         return 1;
1141     }
1142
1143   return 0;
1144 }
1145
1146 static int
1147 is_start_of_string__ (const char *input, size_t n, bool eof, int ofs)
1148 {
1149   if (ofs >= n)
1150     return eof ? 0 : -1;
1151
1152   int c = input[ofs];
1153   if (c == 'x' || c == 'X' || c == 'u' || c == 'U')
1154     {
1155       if (ofs + 1 >= n)
1156         return eof ? 0 : -1;
1157
1158       return input[ofs + 1] == '\'' || input[ofs + 1] == '"';
1159     }
1160   else
1161     return c == '\'' || c == '"' || c == '\n';
1162 }
1163
1164 static int
1165 segmenter_parse_start_of_line__ (struct segmenter *s,
1166                                  const char *input, size_t n, bool eof,
1167                                  enum segment_type *type)
1168 {
1169   ucs4_t uc;
1170   int mblen;
1171   int ofs;
1172
1173   assert (s->state == S_GENERAL);
1174   assert (s->substate & SS_START_OF_LINE);
1175
1176   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
1177   if (mblen < 0)
1178     return -1;
1179
1180   switch (uc)
1181     {
1182     case '+':
1183       ofs = skip_spaces_and_comments (input, n, eof, 1);
1184       if (ofs < 0)
1185         return -1;
1186       else
1187         {
1188           int is_string = is_start_of_string__ (input, n, eof, ofs);
1189           if (is_string < 0)
1190             return -1;
1191           else if (is_string)
1192             {
1193               /* This is punctuation that may separate pieces of a string. */
1194               *type = SEG_PUNCT;
1195               s->substate = 0;
1196               return 1;
1197             }
1198         }
1199       /* Fall through. */
1200
1201     case '-':
1202     case '.':
1203       *type = SEG_START_COMMAND;
1204       s->substate = SS_START_OF_COMMAND;
1205       return 1;
1206
1207     default:
1208       if (lex_uc_is_space (uc))
1209         {
1210           int eol = at_end_of_line (input, n, eof, 0);
1211           if (eol < 0)
1212             return -1;
1213           else if (eol)
1214             {
1215               s->substate = SS_START_OF_COMMAND;
1216               *type = SEG_SEPARATE_COMMANDS;
1217               return 0;
1218             }
1219           break;
1220         }
1221
1222       if (s->mode == SEG_MODE_INTERACTIVE || s->substate & SS_START_OF_COMMAND)
1223         break;
1224       else if (s->mode == SEG_MODE_AUTO)
1225         {
1226           int cmd = segmenter_detect_command_name__ (input, n, eof, 0);
1227           if (cmd < 0)
1228             return -1;
1229           else if (cmd == 0)
1230             break;
1231         }
1232       else
1233         assert (s->mode == SEG_MODE_BATCH);
1234
1235       s->substate = SS_START_OF_COMMAND;
1236       *type = SEG_START_COMMAND;
1237       return 0;
1238     }
1239
1240   s->substate = SS_START_OF_COMMAND;
1241   return segmenter_parse_mid_command__ (s, input, n, eof, type);
1242 }
1243
1244 static int
1245 segmenter_parse_file_label__ (struct segmenter *s,
1246                               const char *input, size_t n, bool eof,
1247                               enum segment_type *type)
1248 {
1249   struct segmenter sub;
1250   int ofs;
1251
1252   sub = *s;
1253   sub.state = S_GENERAL;
1254   ofs = segmenter_push (&sub, input, n, eof, type);
1255
1256   if (ofs < 0)
1257     return -1;
1258   else if (*type == SEG_IDENTIFIER)
1259     {
1260       int result;
1261
1262       assert (lex_id_match (ss_cstr ("LABEL"),
1263                             ss_buffer ((char *) input, ofs)));
1264       result = segmenter_unquoted (input, n, eof, ofs);
1265       if (result < 0)
1266         return -1;
1267       else
1268         {
1269           if (result)
1270             s->state = S_TITLE_1;
1271           else
1272             *s = sub;
1273           return ofs;
1274         }
1275     }
1276   else
1277     {
1278       s->substate = sub.substate;
1279       return ofs;
1280     }
1281 }
1282
1283 static int
1284 segmenter_subparse (struct segmenter *s,
1285                     const char *input, size_t n, bool eof,
1286                     enum segment_type *type)
1287 {
1288   struct segmenter sub;
1289   int ofs;
1290
1291   sub.mode = s->mode;
1292   sub.state = S_GENERAL;
1293   sub.substate = s->substate;
1294   ofs = segmenter_push (&sub, input, n, eof, type);
1295   s->substate = sub.substate;
1296   return ofs;
1297 }
1298
1299 /* We are segmenting a DO REPEAT command, currently reading the syntax that
1300    defines the stand-in variables (the head) before the lines of syntax to be
1301    repeated (the body). */
1302 static int
1303 segmenter_parse_do_repeat_1__ (struct segmenter *s,
1304                                const char *input, size_t n, bool eof,
1305                                enum segment_type *type)
1306 {
1307   int ofs = segmenter_subparse (s, input, n, eof, type);
1308   if (ofs < 0)
1309     return -1;
1310
1311   if (*type == SEG_SEPARATE_COMMANDS)
1312     {
1313       /* We reached a blank line that separates the head from the body. */
1314       s->state = S_DO_REPEAT_2;
1315     }
1316   else if (*type == SEG_END_COMMAND || *type == SEG_START_COMMAND)
1317     {
1318       /* We reached the body. */
1319       s->state = S_DO_REPEAT_3;
1320       s->substate = 1;
1321     }
1322
1323   return ofs;
1324 }
1325
1326 /* We are segmenting a DO REPEAT command, currently reading a blank line that
1327    separates the head from the body. */
1328 static int
1329 segmenter_parse_do_repeat_2__ (struct segmenter *s,
1330                                const char *input, size_t n, bool eof,
1331                                enum segment_type *type)
1332 {
1333   int ofs = segmenter_subparse (s, input, n, eof, type);
1334   if (ofs < 0)
1335     return -1;
1336
1337   if (*type == SEG_NEWLINE)
1338     {
1339       /* We reached the body. */
1340       s->state = S_DO_REPEAT_3;
1341       s->substate = 1;
1342     }
1343
1344   return ofs;
1345 }
1346
1347 static bool
1348 check_repeat_command (struct segmenter *s,
1349                       const char *input, size_t n, bool eof)
1350 {
1351   int direction;
1352   char id[16];
1353   int ofs;
1354
1355   ofs = 0;
1356   if (input[ofs] == '+' || input[ofs] == '-')
1357     ofs++;
1358
1359   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1360   if (ofs < 0)
1361     return false;
1362   else if (lex_id_match (ss_cstr ("DO"), ss_cstr (id)))
1363     direction = 1;
1364   else if (lex_id_match (ss_cstr ("END"), ss_cstr (id)))
1365     direction = -1;
1366   else
1367     return true;
1368
1369   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1370   if (ofs < 0)
1371     return false;
1372
1373   if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
1374     s->substate += direction;
1375   return true;
1376 }
1377
1378 static int
1379 segmenter_parse_full_line__ (const char *input, size_t n, bool eof,
1380                              enum segment_type *type)
1381 {
1382   const char *newline = memchr (input, '\n', n);
1383   if (!newline)
1384     return eof ? n : -1;
1385
1386   ptrdiff_t ofs = newline - input;
1387   if (ofs == 0 || (ofs == 1 && input[0] == '\r'))
1388     {
1389       *type = SEG_NEWLINE;
1390       return ofs + 1;
1391     }
1392   else
1393     return ofs - (input[ofs - 1] == '\r');
1394 }
1395
1396 /* We are in the body of DO REPEAT, segmenting the lines of syntax that are to
1397    be repeated.  Report each line of syntax as a single SEG_DO_REPEAT_COMMAND.
1398
1399    DO REPEAT can be nested, so we look for DO REPEAT...END REPEAT blocks inside
1400    the lines we're segmenting.  s->substate counts the nesting level, starting
1401    at 1. */
1402 static int
1403 segmenter_parse_do_repeat_3__ (struct segmenter *s,
1404                                const char *input, size_t n, bool eof,
1405                                enum segment_type *type)
1406 {
1407   int ofs;
1408
1409   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1410   if (ofs < 0 || (ofs > 0 && input[ofs - 1] == '\n'))
1411     return ofs;
1412   else if (!check_repeat_command (s, input, n, eof) && !eof)
1413     return -1;
1414   else if (s->substate == 0)
1415     {
1416       /* Nesting level dropped to 0, so we've finished reading the DO REPEAT
1417          body. */
1418       s->state = S_GENERAL;
1419       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1420       return segmenter_push (s, input, n, eof, type);
1421     }
1422   else
1423     {
1424       *type = SEG_DO_REPEAT_COMMAND;
1425       return ofs;
1426     }
1427 }
1428
1429 /* We are segmenting a DEFINE command, which consists of:
1430
1431   - The DEFINE keyword.
1432
1433   - Anything but "(".
1434
1435   - "(" followed by a sequence of tokens possibly including balanced parentheses
1436     up to a final ")".
1437
1438   - A newline.
1439
1440   - A sequence of lines that don't start with "!ENDDEFINE", one string per line,
1441     each ending in a newline.
1442
1443   - "!ENDDEFINE".
1444
1445    */
1446 static int
1447 segmenter_parse_define_1__ (struct segmenter *s,
1448                             const char *input, size_t n, bool eof,
1449                             enum segment_type *type)
1450 {
1451   int ofs = segmenter_subparse (s, input, n, eof, type);
1452   if (ofs < 0)
1453     return -1;
1454
1455   if (*type == SEG_SEPARATE_COMMANDS
1456       || *type == SEG_END_COMMAND
1457       || *type == SEG_START_COMMAND)
1458     {
1459       /* The DEFINE command is malformed because we reached its end without
1460          ever hitting a "(" token.  Transition back to general parsing. */
1461       s->state = S_GENERAL;
1462       return ofs;
1463     }
1464   else if (*type == SEG_PUNCT && input[0] == '(')
1465     {
1466       s->state = S_DEFINE_2;
1467       s->nest = 1;
1468       return ofs;
1469     }
1470
1471   return ofs;
1472 }
1473
1474 static int
1475 segmenter_parse_define_2__ (struct segmenter *s,
1476                             const char *input, size_t n, bool eof,
1477                             enum segment_type *type)
1478 {
1479   int ofs = segmenter_subparse (s, input, n, eof, type);
1480   if (ofs < 0)
1481     return -1;
1482
1483   if (*type == SEG_SEPARATE_COMMANDS
1484       || *type == SEG_END_COMMAND
1485       || *type == SEG_START_COMMAND)
1486     {
1487       /* The DEFINE command is malformed because we reached its end before
1488          closing the set of parentheses.  Transition back to general
1489          parsing. */
1490       s->state = S_GENERAL;
1491       return ofs;
1492     }
1493   else if (*type == SEG_PUNCT && input[0] == '(')
1494     {
1495       s->nest++;
1496       return ofs;
1497     }
1498   else if (*type == SEG_PUNCT && input[0] == ')')
1499     {
1500       s->nest--;
1501       if (!s->nest)
1502         s->state = S_DEFINE_3;
1503       return ofs;
1504     }
1505
1506   return ofs;
1507 }
1508
1509 static int
1510 segmenter_parse_define_3__ (struct segmenter *s,
1511                             const char *input, size_t n, bool eof,
1512                             enum segment_type *type)
1513 {
1514   int ofs = segmenter_subparse (s, input, n, eof, type);
1515   if (ofs < 0)
1516     return -1;
1517
1518   if (*type == SEG_END_COMMAND)
1519     {
1520       /* The DEFINE command is malformed because there was a command terminator
1521          before the first line of the body.  Transition back to general
1522          parsing. */
1523       s->state = S_GENERAL;
1524       return ofs;
1525     }
1526   else if (*type == SEG_NEWLINE)
1527     s->state = S_DEFINE_4;
1528
1529   return ofs;
1530 }
1531
1532 static bool
1533 is_enddefine (const char *input, size_t n)
1534 {
1535   int ofs = skip_spaces_and_comments (input, n, true, 0);
1536   assert (ofs >= 0);
1537
1538   const struct substring enddefine = ss_cstr ("!ENDDEFINE");
1539   if (n - ofs < enddefine.length)
1540     return false;
1541
1542   if (!ss_equals_case (ss_buffer (input + ofs, enddefine.length), enddefine))
1543     return false;
1544
1545   if (ofs + enddefine.length >= n)
1546     return true;
1547
1548   const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
1549   ucs4_t uc;
1550   u8_mbtouc (&uc, u_input + ofs, n - ofs);
1551   return uc == '.' || !lex_uc_is_idn (uc);
1552 }
1553
1554 static int
1555 segmenter_parse_define_4__ (struct segmenter *s,
1556                             const char *input, size_t n, bool eof,
1557                             enum segment_type *type)
1558 {
1559   int ofs;
1560
1561   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1562   if (ofs < 0)
1563     return -1;
1564   else if (is_enddefine (input, ofs))
1565     {
1566       s->state = S_GENERAL;
1567       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1568       return segmenter_push (s, input, n, eof, type);
1569     }
1570   else
1571     {
1572       *type = SEG_MACRO_BODY;
1573       s->state = S_DEFINE_5;
1574       return input[ofs - 1] == '\n' ? 0 : ofs;
1575     }
1576 }
1577
1578 static int
1579 segmenter_parse_define_5__ (struct segmenter *s,
1580                             const char *input, size_t n, bool eof,
1581                             enum segment_type *type)
1582 {
1583   int ofs;
1584
1585   ofs = segmenter_parse_newline__ (input, n, eof, type);
1586   if (ofs < 0)
1587     return -1;
1588
1589   s->state = S_DEFINE_4;
1590   return ofs;
1591 }
1592
1593 static int
1594 segmenter_parse_begin_data_1__ (struct segmenter *s,
1595                                 const char *input, size_t n, bool eof,
1596                                 enum segment_type *type)
1597 {
1598   int ofs = segmenter_subparse (s, input, n, eof, type);
1599   if (ofs < 0)
1600     return -1;
1601
1602   if (*type == SEG_NEWLINE)
1603     s->state = S_BEGIN_DATA_2;
1604
1605   return ofs;
1606 }
1607
1608 static int
1609 segmenter_parse_begin_data_2__ (struct segmenter *s,
1610                                 const char *input, size_t n, bool eof,
1611                                 enum segment_type *type)
1612 {
1613   int ofs = segmenter_subparse (s, input, n, eof, type);
1614   if (ofs < 0)
1615     return -1;
1616
1617   if (*type == SEG_NEWLINE)
1618     s->state = S_BEGIN_DATA_3;
1619
1620   return ofs;
1621 }
1622
1623 static bool
1624 is_end_data (const char *input, size_t n)
1625 {
1626   const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
1627   bool endcmd;
1628   ucs4_t uc;
1629   int mblen;
1630   int ofs;
1631
1632   if (n < 4 || c_strncasecmp (input, "END", 3))
1633     return false;
1634
1635   ofs = 3;
1636   mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1637   if (!lex_uc_is_space (uc))
1638     return false;
1639   ofs += mblen;
1640
1641   if (n - ofs < 4 || c_strncasecmp (input + ofs, "DATA", 4))
1642     return false;
1643   ofs += 4;
1644
1645   endcmd = false;
1646   while (ofs < n)
1647     {
1648       mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1649       if (uc == '.')
1650         {
1651           if (endcmd)
1652             return false;
1653           endcmd = true;
1654         }
1655       else if (!lex_uc_is_space (uc))
1656         return false;
1657       ofs += mblen;
1658     }
1659
1660   return true;
1661 }
1662
1663 static int
1664 segmenter_parse_begin_data_3__ (struct segmenter *s,
1665                                 const char *input, size_t n, bool eof,
1666                                 enum segment_type *type)
1667 {
1668   int ofs;
1669
1670   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1671   if (ofs < 0)
1672     return -1;
1673   else if (is_end_data (input, ofs))
1674     {
1675       s->state = S_GENERAL;
1676       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1677       return segmenter_push (s, input, n, eof, type);
1678     }
1679   else
1680     {
1681       *type = SEG_INLINE_DATA;
1682       s->state = S_BEGIN_DATA_4;
1683       return input[ofs - 1] == '\n' ? 0 : ofs;
1684     }
1685 }
1686
1687 static int
1688 segmenter_parse_begin_data_4__ (struct segmenter *s,
1689                                 const char *input, size_t n, bool eof,
1690                                 enum segment_type *type)
1691 {
1692   int ofs;
1693
1694   ofs = segmenter_parse_newline__ (input, n, eof, type);
1695   if (ofs < 0)
1696     return -1;
1697
1698   s->state = S_BEGIN_DATA_3;
1699   return ofs;
1700 }
1701
1702 static int
1703 segmenter_parse_title_1__ (struct segmenter *s,
1704                            const char *input, size_t n, bool eof,
1705                            enum segment_type *type)
1706 {
1707   int ofs;
1708
1709   ofs = skip_spaces (input, n, eof, 0);
1710   if (ofs < 0)
1711     return -1;
1712   s->state = S_TITLE_2;
1713   *type = SEG_SPACES;
1714   return ofs;
1715 }
1716
1717 static int
1718 segmenter_parse_title_2__ (struct segmenter *s,
1719                            const char *input, size_t n, bool eof,
1720                            enum segment_type *type)
1721 {
1722   int endcmd;
1723   int ofs;
1724
1725   endcmd = -1;
1726   ofs = 0;
1727   while (ofs < n)
1728     {
1729       ucs4_t uc;
1730       int mblen;
1731
1732       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1733       if (mblen < 0)
1734         return -1;
1735
1736       switch (uc)
1737         {
1738         case '\n':
1739           goto end_of_line;
1740
1741         case '.':
1742           endcmd = ofs;
1743           break;
1744
1745         default:
1746           if (!lex_uc_is_space (uc))
1747             endcmd = -1;
1748           break;
1749         }
1750
1751       ofs += mblen;
1752     }
1753
1754   if (eof)
1755     {
1756     end_of_line:
1757       s->state = S_GENERAL;
1758       s->substate = 0;
1759       *type = SEG_UNQUOTED_STRING;
1760       return endcmd >= 0 ? endcmd : ofs;
1761     }
1762
1763   return -1;
1764 }
1765
1766 /* Returns the name of segment TYPE as a string.  The caller must not modify
1767    or free the returned string.
1768
1769    This is useful only for debugging and testing. */
1770 const char *
1771 segment_type_to_string (enum segment_type type)
1772 {
1773   switch (type)
1774     {
1775 #define SEG_TYPE(NAME) case SEG_##NAME: return #NAME;
1776       SEG_TYPES
1777 #undef SEG_TYPE
1778     default:
1779       return "unknown segment type";
1780     }
1781 }
1782
1783 /* Initializes S as a segmenter with the given syntax MODE.
1784
1785    A segmenter does not contain any external references, so nothing needs to be
1786    done to destroy one.  For the same reason, segmenters may be copied with
1787    plain struct assignment (or memcpy). */
1788 void
1789 segmenter_init (struct segmenter *s, enum segmenter_mode mode)
1790 {
1791   s->state = S_SHBANG;
1792   s->substate = 0;
1793   s->mode = mode;
1794 }
1795
1796 /* Returns the mode passed to segmenter_init() for S. */
1797 enum segmenter_mode
1798 segmenter_get_mode (const struct segmenter *s)
1799 {
1800   return s->mode;
1801 }
1802
1803 /* Attempts to label a prefix of S's remaining input with a segment type.  The
1804    caller supplies the first N bytes of the remaining input as INPUT, which
1805    must be a UTF-8 encoded string.  If EOF is true, then the N bytes supplied
1806    are the entire (remainder) of the input; if EOF is false, then further input
1807    is potentially available.
1808
1809    The input may contain '\n' or '\r\n' line ends in any combination.
1810
1811    If successful, returns the number of bytes in the segment at the beginning
1812    of INPUT (between 0 and N, inclusive) and stores the type of that segment
1813    into *TYPE.  The next call to segmenter_push() should not include those
1814    bytes as part of INPUT, because they have (figuratively) been consumed by
1815    the segmenter.
1816
1817    Failure occurs only if the segment type of the N bytes in INPUT cannot yet
1818    be determined.  In this case segmenter_push() returns -1.  If more input is
1819    available, the caller should obtain some more, then call again with a larger
1820    N.  If this is not enough, the process might need to repeat again and agin.
1821    If input is exhausted, then the caller may call again setting EOF to true.
1822    segmenter_push() will never return -1 when EOF is true.
1823
1824    The caller must not, in a sequence of calls, supply contradictory input.
1825    That is, bytes provided as part of INPUT in one call, but not consumed, must
1826    not be provided with *different* values on subsequent calls.  This is
1827    because segmenter_push() must often make decisions based on looking ahead
1828    beyond the bytes that it consumes. */
1829 int
1830 segmenter_push (struct segmenter *s, const char *input, size_t n, bool eof,
1831                 enum segment_type *type)
1832 {
1833   if (!n)
1834     {
1835       if (eof)
1836         {
1837           *type = SEG_END;
1838           return 0;
1839         }
1840       else
1841         return -1;
1842     }
1843
1844   switch (s->state)
1845     {
1846     case S_SHBANG:
1847       return segmenter_parse_shbang__ (s, input, n, eof, type);
1848
1849     case S_GENERAL:
1850       return (s->substate & SS_START_OF_LINE
1851               ? segmenter_parse_start_of_line__ (s, input, n, eof, type)
1852               : segmenter_parse_mid_command__ (s, input, n, eof, type));
1853
1854     case S_COMMENT_1:
1855       return segmenter_parse_comment_1__ (s, input, n, eof, type);
1856     case S_COMMENT_2:
1857       return segmenter_parse_comment_2__ (s, input, n, eof, type);
1858
1859     case S_DOCUMENT_1:
1860       return segmenter_parse_document_1__ (s, input, n, eof, type);
1861     case S_DOCUMENT_2:
1862       return segmenter_parse_document_2__ (s, input, n, eof, type);
1863     case S_DOCUMENT_3:
1864       return segmenter_parse_document_3__ (s, type);
1865
1866     case S_FILE_LABEL:
1867       return segmenter_parse_file_label__ (s, input, n, eof, type);
1868
1869     case S_DO_REPEAT_1:
1870       return segmenter_parse_do_repeat_1__ (s, input, n, eof, type);
1871     case S_DO_REPEAT_2:
1872       return segmenter_parse_do_repeat_2__ (s, input, n, eof, type);
1873     case S_DO_REPEAT_3:
1874       return segmenter_parse_do_repeat_3__ (s, input, n, eof, type);
1875
1876     case S_DEFINE_1:
1877       return segmenter_parse_define_1__ (s, input, n, eof, type);
1878     case S_DEFINE_2:
1879       return segmenter_parse_define_2__ (s, input, n, eof, type);
1880     case S_DEFINE_3:
1881       return segmenter_parse_define_3__ (s, input, n, eof, type);
1882     case S_DEFINE_4:
1883       return segmenter_parse_define_4__ (s, input, n, eof, type);
1884     case S_DEFINE_5:
1885       return segmenter_parse_define_5__ (s, input, n, eof, type);
1886
1887     case S_BEGIN_DATA_1:
1888       return segmenter_parse_begin_data_1__ (s, input, n, eof, type);
1889     case S_BEGIN_DATA_2:
1890       return segmenter_parse_begin_data_2__ (s, input, n, eof, type);
1891     case S_BEGIN_DATA_3:
1892       return segmenter_parse_begin_data_3__ (s, input, n, eof, type);
1893     case S_BEGIN_DATA_4:
1894       return segmenter_parse_begin_data_4__ (s, input, n, eof, type);
1895
1896     case S_TITLE_1:
1897       return segmenter_parse_title_1__ (s, input, n, eof, type);
1898     case S_TITLE_2:
1899       return segmenter_parse_title_2__ (s, input, n, eof, type);
1900     }
1901
1902   NOT_REACHED ();
1903 }
1904
1905 /* Returns the style of command prompt to display to an interactive user for
1906    input in S.  The return value is most accurate in mode SEG_MODE_INTERACTIVE
1907    and at the beginning of a line (that is, if segmenter_push() consumed as
1908    much as possible of the input up to a new-line).  */
1909 enum prompt_style
1910 segmenter_get_prompt (const struct segmenter *s)
1911 {
1912   switch (s->state)
1913     {
1914     case S_SHBANG:
1915       return PROMPT_FIRST;
1916
1917     case S_GENERAL:
1918       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1919
1920     case S_COMMENT_1:
1921     case S_COMMENT_2:
1922       return PROMPT_COMMENT;
1923
1924     case S_DOCUMENT_1:
1925     case S_DOCUMENT_2:
1926       return PROMPT_DOCUMENT;
1927     case S_DOCUMENT_3:
1928       return PROMPT_FIRST;
1929
1930     case S_FILE_LABEL:
1931       return PROMPT_LATER;
1932
1933     case S_DO_REPEAT_1:
1934     case S_DO_REPEAT_2:
1935       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1936     case S_DO_REPEAT_3:
1937       return PROMPT_DO_REPEAT;
1938
1939     case S_DEFINE_1:
1940     case S_DEFINE_2:
1941     case S_DEFINE_3:
1942       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1943     case S_DEFINE_4:
1944     case S_DEFINE_5:
1945       return PROMPT_DEFINE;
1946
1947     case S_BEGIN_DATA_1:
1948       return PROMPT_FIRST;
1949     case S_BEGIN_DATA_2:
1950       return PROMPT_LATER;
1951     case S_BEGIN_DATA_3:
1952     case S_BEGIN_DATA_4:
1953       return PROMPT_DATA;
1954
1955     case S_TITLE_1:
1956     case S_TITLE_2:
1957       return PROMPT_FIRST;
1958     }
1959
1960   NOT_REACHED ();
1961 }