return r;
}
+/*** flip ***/
+
+class flip_cmd : public cmd_exec {
+public:
+ bool horizontal;
+ bool vertical;
+ vector<page *> process(vector<page *> &pages);
+};
+
+vector<page *> flip_cmd::process(vector<page *> &pages)
+{
+ vector<page *> out;
+ for (auto p: pages)
+ {
+ pdf_matrix m;
+ if (vertical)
+ {
+ m.scale(1, -1);
+ m.shift(0, p->height);
+ }
+ if (horizontal)
+ {
+ m.scale(-1, 1);
+ m.shift(p->width, 0);
+ }
+ out.push_back(new xform_page(p, m));
+ }
+ return out;
+}
+
+static const arg_def flip_args[] = {
+ { "h", AT_SWITCH },
+ { "v", AT_SWITCH },
+ { NULL, 0 }
+};
+
+static cmd_exec *flip_ctor(cmd *c)
+{
+ flip_cmd *f = new flip_cmd;
+ f->horizontal = c->args.at(0)->as_int(0);
+ f->vertical = c->args.at(1)->as_int(0);
+ if (!f->horizontal && !f->vertical)
+ die("Flip has no direction specified");
+ return f;
+}
+
/*** select ***/
class select_cmd : public cmd_exec {
{ "move", move_args, 0, move_ctor },
{ "scale", scale_args, 0, scale_ctor },
{ "rotate", rotate_args, 0, rotate_ctor },
+ { "flip", flip_args, 0, flip_ctor },
{ "select", no_args, 1, select_ctor },
{ "apply", no_args, 1, apply_ctor },
{ "modulo", modulo_args, 1, modulo_ctor },
for (;;)
{
t = next_token();
+ if (t == TOK_CLOSE_PAREN)
+ break;
uint argi = 0;
+ bool has_value = false;
if (t == TOK_IDENT)
{
while (adefs[argi].name && token != adefs[argi].name)
if (c->args.at(argi)->given())
parse_error("Parameter %s given multiple times", token.c_str());
t = next_token();
- if (t != TOK_EQUAL)
- parse_error("Parameter name must be followed by '='");
+ if (t == TOK_EQUAL)
+ has_value = true;
+ else
+ return_token();
saw_named = true;
}
else if (saw_named)
if (next_pos >= num_args)
parse_error("Too many positional arguments for command %s", cdef->name);
argi = next_pos++;
+ has_value = true;
}
const arg_def *adef = &adefs[argi];
+ uint type = adef->type & AT_TYPE_MASK;
arg_val *val = NULL;
- switch (adef->type & AT_TYPE_MASK)
- {
- case AT_STRING:
- t = next_token();
- if (t != TOK_STRING)
- parse_error("Parameter %s must be a string", adef->name);
- val = new arg_string(token);
- break;
- case AT_INT:
- t = next_token();
- if (t != TOK_NUMBER || !token_is_int())
- parse_error("Parameter %s must be an integer", adef->name);
- val = new arg_int((int) token_num);
- break;
- case AT_DOUBLE:
- t = next_token();
- if (t != TOK_NUMBER)
- parse_error("Parameter %s must be a number", adef->name);
- val = new arg_double(token_num);
- break;
- case AT_DIMEN:
- val = new arg_double(parse_dimen(adef));
- break;
- default:
- abort();
+ if (has_value)
+ {
+ switch (type)
+ {
+ case AT_STRING:
+ t = next_token();
+ if (t != TOK_STRING)
+ parse_error("Parameter %s must be a string", adef->name);
+ val = new arg_string(token);
+ break;
+ case AT_INT:
+ t = next_token();
+ if (t != TOK_NUMBER || !token_is_int())
+ parse_error("Parameter %s must be an integer", adef->name);
+ val = new arg_int((int) token_num);
+ break;
+ case AT_DOUBLE:
+ t = next_token();
+ if (t != TOK_NUMBER)
+ parse_error("Parameter %s must be a number", adef->name);
+ val = new arg_double(token_num);
+ break;
+ case AT_DIMEN:
+ val = new arg_double(parse_dimen(adef));
+ break;
+ case AT_SWITCH:
+ t = next_token();
+ if (t != TOK_NUMBER || !token_is_int() || ((int) token_num != 0 && (int) token_num != 1))
+ parse_error("Parameter %s must be a switch", adef->name);
+ val = new arg_int((int) token_num);
+ break;
+ default:
+ abort();
+ }
+ }
+ else
+ {
+ if (type == AT_SWITCH)
+ val = new arg_int(1);
+ else
+ parse_error("Parameter %s must have a value", adef->name);
}
c->args.at(argi) = val;
const arg_def *arg = def->arg_defs;
static const char * const type_names[] = {
- "string", "int", "double", "dimen"
+ "string", "int", "double", "dimen", "switch"
};
while (arg->name)
{