+ yylex_destroy ();
+}
+
+static inline warnings
+flag (const char *arg)
+{
+ /* compare with values issued from b4_error */
+ if (STREQ (arg, "warn"))
+ return Wother;
+ else if (STREQ (arg, "complain"))
+ return complaint;
+ else if (STREQ (arg, "fatal"))
+ return fatal;
+ else
+ aver (false);
+}
+
+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], "@complain"))
+ {
+ if (argc < 4)
+ fail_for_at_directive_too_few_args (argv[0]);
+ warnings w = flag (argv[1]);
+ location loc;
+ location *locp = NULL;
+ if (argv[2] && argv[2][0])
+ {
+ boundary_set_from_string (&loc.start, argv[2]);
+ boundary_set_from_string (&loc.end, argv[3]);
+ locp = &loc;
+ }
+ complain_args (locp, w, argc - 3, argv + 3);
+ }
+ 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);