+ yylex_destroy ();
+}
+
+static inline warnings
+flag (const char *arg)
+{
+ switch (arg[1])
+ {
+ case 'w': return Wother;
+ case 'c': return complaint;
+ case 'f': return fatal;
+ default: aver (false); break;
+ }
+}
+
+static void
+at_directive_perform (int argc, char *argv[], char **outnamep, int *out_linenop)
+{
+ if (STREQ (argv[0], "@basename"))
+ {
+ if (argc > 2)
+ fail_for_at_directive_too_many_args (argv[0]);
+ fputs (last_component (argv[1]), yyout);
+ }
+ else if (STREQ (argv[0], "@warn") || STREQ (argv[0], "@warn_at")
+ || STREQ (argv[0], "@complain") || STREQ (argv[0], "@complain_at")
+ || STREQ (argv[0], "@fatal") || STREQ (argv[0], "@fatal_at"))
+ {
+ warnings w = flag (*argv);
+ location loc;
+ location *locp = NULL;
+ if (STREQ (*argv + strlen (*argv) - 3, "_at"))
+ {
+ if (argc < 4)
+ fail_for_at_directive_too_few_args (argv[0]);
+ boundary_set_from_string (&loc.start, argv[1]);
+ boundary_set_from_string (&loc.end, argv[2]);
+ argc -= 2;
+ argv += 2;
+ locp = &loc;
+ }
+ else if (argc < 2)
+ fail_for_at_directive_too_few_args (argv[0]);
+ complain_args (locp, w, argc, argv);
+ }
+ else if (STREQ (argv[0], "@output"))
+ {
+ if (argc > 2)
+ fail_for_at_directive_too_many_args (argv[0]);
+ if (*outnamep)
+ {
+ free (*outnamep);
+ xfclose (yyout);
+ }
+ *outnamep = xstrdup (argv[1]);
+ output_file_name_check (outnamep);
+ yyout = xfopen (*outnamep, "w");
+ *out_linenop = 1;
+ }
+ else
+ fail_for_invalid_at (argv[0]);
+}
+
+static void
+fail_for_at_directive_too_few_args (char const *at_directive_name)
+{
+ complain (NULL, fatal, _("too few arguments for %s directive in skeleton"),
+ at_directive_name);
+}
+
+static void
+fail_for_at_directive_too_many_args (char const *at_directive_name)
+{
+ complain (NULL, fatal, _("too many arguments for %s directive in skeleton"),
+ at_directive_name);
+}
+
+static void
+fail_for_invalid_at (char const *at)
+{
+ complain (NULL, fatal, "invalid @ in skeleton: %s", at);