summaryrefslogtreecommitdiff
path: root/pcl/pcmacros.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcl/pcmacros.c')
-rw-r--r--pcl/pcmacros.c267
1 files changed, 267 insertions, 0 deletions
diff --git a/pcl/pcmacros.c b/pcl/pcmacros.c
new file mode 100644
index 000000000..be95b444e
--- /dev/null
+++ b/pcl/pcmacros.c
@@ -0,0 +1,267 @@
+/* Portions Copyright (C) 2001 artofcode LLC.
+ Portions Copyright (C) 1996, 2001 Artifex Software Inc.
+ Portions Copyright (C) 1988, 2000 Aladdin Enterprises.
+ This software is based in part on the work of the Independent JPEG Group.
+ All Rights Reserved.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/ or
+ contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+ San Rafael, CA 94903, (415)492-9861, for further information. */
+/*$Id$ */
+
+/* pcmacros.c */
+/* PCL5 macro commands */
+#include "stdio_.h" /* std.h + NULL */
+#include "pcommand.h"
+#include "pgmand.h"
+#include "pcstate.h"
+#include "pcparse.h"
+
+/* ---------------- Macro execution ---------------- */
+
+/* Execute a macro. We're willing to use C recursion for this because */
+/* the PCL5 specification only allows 2 levels of call. */
+static int
+do_copies(pcl_state_t *psaved, pcl_state_t *pcs,
+ pcl_copy_operation_t copy)
+{ const pcl_init_t **init = pcl_init_table;
+ int code = 0;
+
+ for ( ; *init && code >= 0; ++init )
+ if ( (*init)->do_copy )
+ code = (*(*init)->do_copy)(psaved, pcs, copy);
+ return code;
+}
+int
+pcl_execute_macro(const pcl_macro_t *pmac, pcl_state_t *pcs,
+ pcl_copy_operation_t before, pcl_reset_type_t reset,
+ pcl_copy_operation_t after)
+{
+ pcl_parser_state_t state;
+ hpgl_parser_state_t gstate;
+ pcl_state_t saved;
+ stream_cursor_read r;
+ int code;
+
+ if ( before ) {
+ memcpy(&saved, pcs, sizeof(*pcs));
+ do_copies(&saved, pcs, before);
+ pcs->saved = &saved;
+ }
+ if ( reset )
+ pcl_do_resets(pcs, reset);
+ state.definitions = pcs->pcl_commands;
+ state.hpgl_parser_state=&gstate;
+ pcl_process_init(&state);
+ r.ptr = (const byte *)(pmac + 1) - 1;
+ r.limit =
+ (const byte *)pmac + (gs_object_size(pcs->memory, pmac) - 1);
+ pcs->macro_level++;
+ code = pcl_process(&state, pcs, &r);
+ pcs->macro_level--;
+ if ( after ) {
+ do_copies(&saved, pcs, after);
+ memcpy(pcs, &saved, sizeof(*pcs));
+ }
+ return code;
+}
+
+/* ---------------- Commands ---------------- */
+
+/* Define the macro control operations. */
+enum {
+ macro_end_definition = 1,
+ macro_execute = 2,
+ macro_call = 3,
+ macro_delete_temporary = 7
+};
+
+static int /* ESC & f <mc_enum> X */
+pcl_macro_control(pcl_args_t *pargs, pcl_state_t *pcs)
+{ int i = int_arg(pargs);
+ gs_const_string key;
+ void *value;
+ pl_dict_enum_t denum;
+
+ if ( i == macro_end_definition )
+ { if ( pcs->defining_macro )
+ { /* The parser has included everything through this command */
+ /* in the macro_definition, so we can finish things up. */
+ int code;
+ code = pl_dict_put(&pcs->macros, current_macro_id,
+ current_macro_id_size, pcs->macro_definition);
+ pcs->defining_macro = false;
+ pcs->macro_definition = 0;
+ return code;
+ }
+ }
+ else if ( pcs->defining_macro )
+ return 0; /* don't execute other macro operations */
+ else if ( i == macro_execute || i == macro_call )
+ { /*
+ * TRM 12-9 says that "two levels of nesting are allowed",
+ * which means 3 levels of macros (1 non-nested, 2 nested).
+ */
+ if ( pcs->macro_level > 2 )
+ return 0;
+ }
+ else if ( pcs->macro_level )
+ return e_Range; /* macro operations not allowed inside macro */
+ switch ( i )
+ {
+ case 0:
+ { /* Start defining <macro_id>. */
+ pcl_macro_t *pmac;
+
+ pl_dict_undef_purge_synonyms(&pcs->macros, current_macro_id, current_macro_id_size);
+ pmac = (pcl_macro_t *)
+ gs_alloc_bytes(pcs->memory, sizeof(pcl_macro_t),
+ "begin macro definition");
+ if ( pmac == 0 )
+ return_error(e_Memory);
+ pmac->storage = pcds_temporary;
+ pcs->macro_definition = (byte *)pmac;
+ pcs->defining_macro = true;
+ return 0;
+ }
+ case macro_end_definition: /* 1 */
+ { /* Stop defining macro. Outside a macro, this is an error. */
+ return e_Range;
+ }
+ case macro_execute: /* 2 */
+ { /* Execute <macro_id>. */
+ void *value;
+ if ( !pl_dict_find(&pcs->macros, current_macro_id, current_macro_id_size,
+ &value)
+ )
+ return 0;
+ return pcl_execute_macro((const pcl_macro_t *)value, pcs,
+ pcl_copy_none, pcl_reset_none, pcl_copy_none);
+ }
+ case macro_call: /* 3 */
+ { /* Call <macro_id>, saving and restoring environment. */
+ void *value;
+ if ( !pl_dict_find(&pcs->macros, current_macro_id, current_macro_id_size,
+ &value)
+ )
+ return 0;
+ return pcl_execute_macro((const pcl_macro_t *)value, pcs,
+ pcl_copy_before_call, pcl_reset_none,
+ pcl_copy_after_call);
+ }
+ case 4:
+ { /* Define <macro_id> as automatic overlay. */
+ pcs->overlay_macro_id = pcs->macro_id;
+ pcs->overlay_enabled = true;
+ return 0;
+ }
+ case 5:
+ { /* Cancel automatic overlay. */
+ pcs->overlay_enabled = false;
+ return 0;
+ }
+ case 6:
+ { /* Delete all macros. */
+ pl_dict_release(&pcs->macros);
+ return 0;
+ }
+ case macro_delete_temporary: /* 7 */
+ { /* Delete temporary macros. */
+ pl_dict_enum_stack_begin(&pcs->macros, &denum, false);
+ while ( pl_dict_enum_next(&denum, &key, &value) )
+ if ( ((pcl_macro_t *)value)->storage == pcds_temporary )
+ pl_dict_undef_purge_synonyms(&pcs->macros, key.data, key.size);
+ return 0;
+ }
+ case 8:
+ { /* Delete <macro_id>. */
+ pl_dict_undef_purge_synonyms(&pcs->macros, current_macro_id, current_macro_id_size);
+ return 0;
+ }
+ case 9:
+ { /* Make <macro_id> temporary. */
+ if ( pl_dict_find(&pcs->macros, current_macro_id, current_macro_id_size, &value) )
+ ((pcl_macro_t *)value)->storage = pcds_temporary;
+ return 0;
+ }
+ case 10:
+ { /* Make <macro_id> permanent. */
+ if ( pl_dict_find(&pcs->macros, current_macro_id, current_macro_id_size, &value) )
+ ((pcl_macro_t *)value)->storage = pcds_permanent;
+ return 0;
+ }
+ default:
+ return e_Range;
+ }
+}
+
+static int /* ESC & f <id> Y */
+pcl_assign_macro_id(pcl_args_t *pargs, pcl_state_t *pcs)
+{ uint id = uint_arg(pargs);
+ id_set_value(pcs->macro_id, id);
+ pcs->macro_id_type = numeric_id;
+ return 0;
+}
+
+/* Initialization */
+static int
+pcmacros_do_registration(
+ pcl_parser_state_t *pcl_parser_state,
+ gs_memory_t *mem)
+{ /* Register commands */
+ DEFINE_CLASS('&')
+ {'f', 'X',
+ PCL_COMMAND("Macro Control", pcl_macro_control,
+ pca_neg_error|pca_big_error|pca_in_macro)},
+ {'f', 'Y',
+ PCL_COMMAND("Assign Macro ID", pcl_assign_macro_id,
+ pca_neg_error|pca_big_error)},
+ END_CLASS
+ return 0;
+}
+static void
+pcmacros_do_reset(pcl_state_t *pcs, pcl_reset_type_t type)
+{ if ( type & (pcl_reset_initial | pcl_reset_printer) )
+ { pcs->overlay_enabled = false;
+ pcs->macro_level = 0;
+ pcs->defining_macro = false;
+ pcs->saved = 0;
+ pcs->macro_definition = 0;
+
+ if ( type & pcl_reset_initial )
+ pl_dict_init(&pcs->macros, pcs->memory, NULL);
+ else
+ { pcl_args_t args;
+ arg_set_uint(&args, macro_delete_temporary);
+ pcl_macro_control(&args, pcs);
+ if ( pcs->alpha_macro_id.id != 0 )
+ gs_free_object(pcs->memory,
+ pcs->alpha_macro_id.id,
+ "pcmacros_do_reset");
+ }
+ }
+
+ if ( type & (pcl_reset_initial | pcl_reset_printer | pcl_reset_overlay | pcl_reset_permanent) )
+ {
+ pcs->alpha_macro_id.size = 0;
+ pcs->macro_id_type = numeric_id;
+ id_set_value(pcs->macro_id, 0);
+ pcs->alpha_macro_id.id = 0;
+ }
+ if ( type & pcl_reset_permanent )
+ pl_dict_release(&pcs->macros);
+}
+static int
+pcmacros_do_copy(pcl_state_t *psaved, const pcl_state_t *pcs,
+ pcl_copy_operation_t operation)
+{ if ( operation & pcl_copy_after )
+ { /* Don't restore the macro dictionary. */
+ psaved->macros = pcs->macros;
+ }
+ return 0;
+}
+const pcl_init_t pcmacros_init = {
+ pcmacros_do_registration, pcmacros_do_reset, pcmacros_do_copy
+};