home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / dtp / ghost / gs301src / atari / gs.c < prev    next >
C/C++ Source or Header  |  1994-09-17  |  15KB  |  574 lines

  1. /* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gs.c */
  20. /* Driver program for Ghostscript */
  21. /* Define PROGRAM_NAME before we include std.h */
  22. #define PROGRAM_NAME gs_product
  23. #include "ctype_.h"
  24. #include "memory_.h"
  25. #include "string_.h"
  26. /* Capture stdin/out/err before gs.h redefines them. */
  27. #include <stdio.h>
  28. static FILE *real_stdin, *real_stdout, *real_stderr;
  29. static void
  30. get_real(void)
  31. {    real_stdin = stdin, real_stdout = stdout, real_stderr = stderr;
  32. }
  33. #include "ghost.h"
  34. #include "gxdevice.h"
  35. #include "gxdevmem.h"
  36. #include "gsdevice.h"
  37. #include "stream.h"
  38. #include "errors.h"
  39. #include "estack.h"
  40. #include "ialloc.h"
  41. #include "strimpl.h"        /* for sfilter.h */
  42. #include "sfilter.h"        /* for iscan.h */
  43. #include "ostack.h"        /* must precede iscan.h */
  44. #include "iscan.h"
  45. #include "main.h"
  46. #include "store.h"
  47. #include "files.h"                /* requires stream.h */
  48. #include "interp.h"
  49. #include "iutil.h"
  50.  
  51. /* Import operator procedures */
  52. extern int zflush (P1(os_ptr));
  53. extern int zflushpage (P1(os_ptr));
  54.  
  55. #ifndef GS_LIB
  56. #  define GS_LIB "GS_LIB"
  57. #endif
  58.  
  59. #ifndef GS_OPTIONS
  60. #  define GS_OPTIONS "GS_OPTIONS"
  61. #endif
  62.  
  63. /* Library routines not declared in a standard header */
  64. extern char *getenv(P1(const char *));
  65. /* Note: sscanf incorrectly defines its first argument as char * */
  66. /* rather than const char *.  This accounts for the ugly casts below. */
  67.  
  68. /* Other imported data */
  69. extern const char **gs_lib_paths;
  70. extern const char *gs_doc_directory;
  71.  
  72. /*
  73.  * Help strings.  We have to break them up into parts, because
  74.  * the Watcom compiler has a limit of 510 characters for a single token.
  75.  * For PC displays, we want to limit the strings to 24 lines.
  76.  */
  77. private const char far_data gs_help1a[] = "\
  78. Usage: gs [switches] [file1.ps file2.ps ...]\n\
  79. Available devices:";
  80. private const char far_data gs_help1b[] = "\n\
  81. Search path:";
  82. private const char far_data gs_help2a[] = "\n\
  83. Most frequently used switches: (you can use # in place of =)\n\
  84.     -d<name>[=<token>]   define name as token, or true if no token given\n\
  85.     -dNOPAUSE            don't pause between pages\n\
  86.     -g<width>x<height>   set width and height (`geometry'), in pixels\n\
  87.     -q                   `quiet' mode, suppress most messages\n\
  88.     -r<res>              set resolution, in pixels per inch\n";
  89. private const char far_data gs_help2b[] = "\
  90.     -s<name>=<string>    define name as string\n\
  91.     -sDEVICE=<devname>   select initial device\n\
  92.     -sOutputFile=<file>  select output file: embed %%d or %%ld for page #,\n\
  93.                            - means stdout, use |command to pipe\n\
  94.     -                    read from stdin (e.g., a pipe) non-interactively\n\
  95. For more information, see the (plain text) file use.doc\n\
  96.   in the directory %s.\n";
  97.  
  98. /* Forward references */
  99. typedef struct arg_list_s arg_list;
  100. private int swproc(P2(const char *, arg_list *));
  101. private void argproc(P1(const char *));
  102. private void print_revision(P0());
  103. private int esc_strlen(P1(const char *));
  104. private void esc_strcat(P2(char *, const char *));
  105. private void runarg(P4(const char *, const char *, const char *, bool));
  106. private void run_string(P2(const char *, bool));
  107.  
  108. /* Parameters set by swproc */
  109. private bool quiet;
  110. private bool batch;
  111.  
  112. /* ------ Argument management ------ */
  113.  
  114. /* We need to handle recursion into @-files. */
  115. /* The following structures keep track of the state. */
  116. typedef struct arg_source_s {
  117.     int is_file;
  118.     union _u {
  119.         const char *str;
  120.         FILE *file;
  121.     } u;
  122. } arg_source;
  123. struct arg_list_s {
  124.     bool expand_ats;    /* if true, expand @-files */
  125.     const char **argp;
  126.     int argn;
  127.     int depth;        /* depth of @-files */
  128. #define cstr_max 128
  129.     char cstr[cstr_max + 1];
  130. #define csource_max 10
  131.     arg_source sources[csource_max];
  132. };
  133.  
  134. /* Initialize an arg list. */
  135. private void
  136. arg_init(arg_list *pal, const char **argv, int argc)
  137. {    pal->expand_ats = true;
  138.     pal->argp = argv + 1;
  139.     pal->argn = argc - 1;
  140.     pal->depth = 0;
  141. }
  142.  
  143. /* Push a string onto an arg list. */
  144. /* (Only used at top level, so no need to check depth.) */
  145. private void
  146. arg_push_string(arg_list *pal, const char *str)
  147. {    arg_source *pas = &pal->sources[pal->depth];
  148.     pas->is_file = 0;
  149.     pas->u.str = str;
  150.     pal->depth++;
  151. }
  152.  
  153. /* Clean up an arg list. */
  154. private void
  155. arg_finit(arg_list *pal)
  156. {    while ( pal->depth )
  157.       if ( pal->sources[--(pal->depth)].is_file )
  158.         fclose(pal->sources[pal->depth].u.file);
  159. }
  160.  
  161. /* Get the next arg from a list. */
  162. /* Note that these are not copied to the heap. */
  163. private const char *
  164. arg_next(arg_list *pal)
  165. {    arg_source *pas;
  166.     FILE *f;
  167.     const char *astr;
  168.     char *cstr;
  169.     const char *result;
  170.     int endc;
  171.     register int c;
  172.     register int i;
  173. top:    pas = &pal->sources[pal->depth - 1];
  174.     if ( pal->depth == 0 )
  175.     {    if ( pal->argn == 0 )        /* all done */
  176.             return 0;
  177.         pal->argn--;
  178.         result = *(pal->argp++);
  179.         goto at;
  180.     }
  181.     if ( pas->is_file )
  182.         f = pas->u.file, endc = EOF;
  183.     else
  184.         astr = pas->u.str, f = NULL, endc = 0;
  185.     result = cstr = pal->cstr;
  186. #define cfsgetc() (f == NULL ? (*astr ? *astr++ : 0) : fgetc(f))
  187.     while ( isspace(c = cfsgetc()) ) ;
  188.     if ( c == endc )
  189.     {    if ( f != NULL )
  190.             fclose(f);
  191.         pal->depth--;
  192.         goto top;
  193.     }
  194.     for ( i = 0; ; )
  195.     {    if ( i == cstr_max - 1 )
  196.         {    cstr[i] = 0;
  197.             fprintf(stdout, "Command too long: %s\n", cstr);
  198.             gs_exit(1);
  199.         }
  200.         cstr[i++] = c;
  201.         c = cfsgetc();
  202.         if ( c == endc || isspace(c) )
  203.             break;
  204.     }
  205.     cstr[i] = 0;
  206.     if ( f == NULL )
  207.         pas->u.str = astr;
  208. at:    if ( pal->expand_ats && result[0] == '@' )
  209.     {    if ( pal->depth == csource_max )
  210.         {    lprintf("Too much nesting of @-files.\n");
  211.             gs_exit(1);
  212.         }
  213.         gs_set_lib_paths();
  214.         result++;        /* skip @ */
  215.         f = lib_fopen(result);
  216.         if ( f == NULL )
  217.         {    fprintf(stdout, "Unable to open command line file %s\n", result);
  218.             gs_exit(1);
  219.         }
  220.         pal->depth++;
  221.         pas++;
  222.         pas->is_file = 1;
  223.         pas->u.file = f;
  224.         goto top;
  225.     }
  226.     return result;
  227. }
  228.  
  229. /* Copy an argument string to the heap. */
  230. private char *
  231. arg_copy(const char *str)
  232. {    char *sstr = gs_malloc(strlen(str) + 1, 1, "arg_copy");
  233.     if ( sstr == 0 )
  234.     {    lprintf("Out of memory!\n");
  235.         gs_exit(1);
  236.     }
  237.     strcpy(sstr, str);
  238.     return sstr;
  239. }
  240.  
  241. /* ------ Main program ------ */
  242.  
  243. int
  244. main(int argc, const char *argv[])
  245. {    const char *arg;
  246.     arg_list args;
  247.     get_real();
  248.     arg_init(&args, argv, argc);
  249.     gs_init0(real_stdin, real_stdout, real_stderr, argc);
  250.        {    char *lib = getenv(GS_LIB);
  251.         if ( lib != 0 ) 
  252.            {    int len = strlen(lib);
  253.             gs_lib_env_path = gs_malloc(len + 1, 1, "GS_LIB");
  254.             strcpy(gs_lib_env_path, lib);
  255.            }
  256.        }
  257.     /* Execute files named in the command line, */
  258.     /* processing options along the way. */
  259.     /* Wait until the first file name (or the end */
  260.     /* of the line) to finish initialization. */
  261.     batch = false;
  262.     quiet = false;
  263.     {    const char *opts = getenv(GS_OPTIONS);
  264.         if ( opts != 0 )
  265.             arg_push_string(&args, opts);
  266.     }
  267.     while ( (arg = arg_next(&args)) != 0 )
  268.        {    switch ( *arg )
  269.         {
  270.         case '-':
  271.             if ( swproc(arg, &args) < 0 )
  272.               fprintf(stdout,
  273.                   "Unknown switch %s - ignoring\n", arg);
  274.             break;
  275.         default:
  276.             argproc(arg);
  277.         }
  278.        }
  279.     gs_init2();
  280.     if ( !batch )
  281.         run_string("systemdict /start get exec", true);
  282.  
  283. #ifdef atarist
  284.     gs_exit(0);
  285. #else
  286.     return 0;            /* exit */
  287. #endif
  288. }
  289.  
  290. /* Process switches */
  291. private int
  292. swproc(const char *arg, arg_list *pal)
  293. {    char sw = arg[1];
  294.     arg += 2;        /* skip - and letter */
  295.     switch ( sw )
  296.        {
  297.     default:
  298.         return -1;
  299.     case 0:                /* read stdin as a file */
  300.         batch = true;
  301.         /* Set NOPAUSE so showpage won't try to read from stdin. */
  302.         swproc("-dNOPAUSE=true", pal);
  303.         gs_init2();        /* Finish initialization */
  304.         /* We delete this only to make Ghostview work properly. */
  305.         /**************** This is WRONG. ****************/
  306.         /*gs_stdin_is_interactive = false;*/
  307.         run_string("(%stdin) (r) file cvx execute0", true);
  308.         break;
  309.     case '-':            /* run with command line args */
  310.     case '+':
  311.         pal->expand_ats = false;
  312.     case '@':            /* ditto with @-expansion */
  313.        {    const char *psarg = arg_next(pal);
  314.         if ( psarg == 0 )
  315.         {    fprintf(stdout, "Usage: gs ... -%c file.ps arg1 ... argn", sw);
  316.             arg_finit(pal);
  317.             gs_exit(1);
  318.         }
  319.         psarg = arg_copy(psarg);
  320.         gs_init2();
  321.         run_string("userdict/ARGUMENTS[", false);
  322.         while ( (arg = arg_next(pal)) != 0 )
  323.             runarg("", arg_copy(arg), "", false);
  324.         runarg("]put{", psarg, ".runfile}execute", true);
  325.         gs_exit(0);
  326.        }
  327.     case 'A':            /* trace allocator */
  328.         gs_alloc_debug = 1; break;
  329.     case 'c':            /* code follows */
  330.       {    bool ats = pal->expand_ats;
  331.         gs_init2();
  332.         pal->expand_ats = false;
  333.         while ( (arg = arg_next(pal)) != 0 )
  334.           {    char *sarg;
  335.             if ( arg[0] == '@' ||
  336.                  (arg[0] == '-' && !isdigit(arg[1]))
  337.                )
  338.                 break;
  339.             sarg = arg_copy(arg);
  340.             run_string(sarg, false);
  341.           }
  342.         if ( arg != 0 )
  343.             arg_push_string(pal, arg_copy(arg));
  344.         pal->expand_ats = ats;
  345.         break;
  346.       }
  347.     case 'E':            /* log errors */
  348.         gs_log_errors = 1; break;
  349.     case 'f':            /* run file of arbitrary name */
  350.         if ( *arg != 0 )
  351.             argproc(arg);
  352.         break;
  353.     case 'h':            /* print help */
  354.     case '?':            /* ditto */
  355.         print_revision();
  356.         fputs(gs_help1a, stdout);
  357.         {    int i;
  358.             gx_device *pdev;
  359.             for ( i = 0; (pdev = gs_getdevice(i)) != 0; i++ )
  360.                 fprintf(stdout, (i & 7 ? " %s" : "\n    %s"),
  361.                     gs_devicename(pdev));
  362.         }
  363.         fputs(gs_help1b, stdout);
  364.         gs_set_lib_paths();
  365.         {    const char **ppath = gs_lib_paths;
  366.             while ( *ppath != 0 )
  367.                 fprintf(stdout, "\n    %s", *ppath++);
  368.         }
  369.         fputs(gs_help2a, stdout);
  370.         fprintf(stdout, gs_help2b, gs_doc_directory);
  371.         gs_exit(0);
  372.     case 'I':            /* specify search path */
  373.         gs_add_lib_path(arg_copy(arg));
  374.         break;
  375.     case 'q':            /* quiet startup */
  376.        {    ref vtrue;
  377.         quiet = true;
  378.         gs_init1();
  379.         make_true(&vtrue);
  380.         initial_enter_name("QUIET", &vtrue);
  381.        }    break;
  382.     case 'D':            /* define name */
  383.     case 'd':
  384.     case 'S':            /* define name as string */
  385.     case 's':
  386.        {    char *adef = arg_copy(arg);
  387.         char *eqp = strchr(adef, '=');
  388.         bool isd = (sw == 'D' || sw == 'd');
  389.         ref value;
  390.         if ( eqp == NULL )
  391.             eqp = strchr(adef, '#');
  392.         /* Initialize the object memory, scanner, and */
  393.         /* name table now if needed. */
  394.         gs_init1();
  395.         if ( eqp == adef )
  396.            {    puts("Usage: -dname, -dname=token, -sname=string");
  397.             gs_exit(1);
  398.            }
  399.         if ( eqp == NULL )
  400.            {    if ( isd )
  401.                 make_true(&value);
  402.             else
  403.                 make_string(&value, a_readonly, 0, NULL);
  404.            }
  405.         else
  406.            {    int code;
  407.             *eqp++ = 0;
  408.             if ( isd )
  409.                {    stream astream;
  410.                 scanner_state state;
  411.                 sread_string(&astream,
  412.                          (const byte *)eqp, strlen(eqp));
  413.                 scanner_state_init(&state, false);
  414.                 code = scan_token(&astream, &value, &state);
  415.                 if ( code )
  416.                    {    puts("-dname= must be followed by a valid token");
  417.                     gs_exit(1);
  418.                    }
  419.                }
  420.             else
  421.                {    int len = strlen(eqp);
  422.                 char *str = gs_malloc((uint)len, 1, "-s");
  423.                 if ( str == 0 )
  424.                    {    lprintf("Out of memory!\n");
  425.                     gs_exit(1);
  426.                    }
  427.                 memcpy(str, eqp, len);
  428.                 make_const_string(&value, a_readonly + a_foreign, len, (const byte *)str);
  429.                }
  430.            }
  431.         /* Enter the name in systemdict. */
  432.         initial_enter_name(adef, &value);
  433.         break;
  434.        }
  435.     case 'g':            /* define device geometry */
  436.        {    long width, height;
  437.         ref value;
  438.         gs_init1();
  439.         if ( sscanf((char *)arg, "%ldx%ld", &width, &height) != 2 )
  440.            {    puts("-g must be followed by <width>x<height>");
  441.             gs_exit(1);
  442.            }
  443.         make_int(&value, width);
  444.         initial_enter_name("DEVICEWIDTH", &value);
  445.         make_int(&value, height);
  446.         initial_enter_name("DEVICEHEIGHT", &value);
  447.         break;
  448.        }
  449.     case 'M':            /* set memory allocation increment */
  450.        {    unsigned msize = 0;
  451.         sscanf((char *)arg, "%d", &msize);
  452.         if ( msize <= 0 || msize >= 64 )
  453.            {    puts("-M must be between 1 and 63");
  454.             gs_exit(1);
  455.            }
  456.         gs_memory_chunk_size = msize << 10;
  457.        }
  458.         break;
  459.     case 'r':            /* define device resolution */
  460.        {    float xres, yres;
  461.         ref value;
  462.         gs_init1();
  463.         switch ( sscanf((char *)arg, "%fx%f", &xres, &yres) )
  464.            {
  465.         default:
  466.             puts("-r must be followed by <res> or <xres>x<yres>");
  467.             gs_exit(1);
  468.         case 1:            /* -r<res> */
  469.             yres = xres;
  470.         case 2:            /* -r<xres>x<yres> */
  471.             make_real(&value, xres);
  472.             initial_enter_name("DEVICEXRESOLUTION", &value);
  473.             make_real(&value, yres);
  474.             initial_enter_name("DEVICEYRESOLUTION", &value);
  475.            }
  476.         break;
  477.        }
  478.     case 'v':            /* print revision */
  479.         print_revision();
  480.         gs_exit(0);
  481.     case 'Z':
  482.         while ( *arg )
  483.             gs_debug[*arg++ & 127] = 0xff;
  484.         break;
  485.        }
  486.     return 0;
  487. }
  488.  
  489. /* Define versions of strlen and strcat that encode strings in hex. */
  490. /* This is so we can enter escaped characters regardless of whether */
  491. /* the Level 1 convention of ignoring \s in strings-within-strings */
  492. /* is being observed (sigh). */
  493. private int
  494. esc_strlen(const char *str)
  495. {    return strlen(str) * 2 + 2;
  496. }
  497. private void
  498. esc_strcat(char *dest, const char *src)
  499. {    char *d = dest + strlen(dest);
  500.     const char *p;
  501.     static const char *hex = "0123456789abcdef";
  502.     *d++ = '<';
  503.     for ( p = src; *p; p++ )
  504.     {    byte c = (byte)*p;
  505.         *d++ = hex[c >> 4];
  506.         *d++ = hex[c & 0xf];
  507.     }
  508.     *d++ = '>';
  509.     *d = 0;
  510. }
  511.  
  512. /* Process file names */
  513. private void
  514. argproc(const char *arg)
  515. {    runarg("{", arg, ".runfile}execute", true);
  516. }
  517. private void
  518. runarg(const char *pre, const char *arg, const char *post, bool flush)
  519. {    int len = strlen(pre) + esc_strlen(arg) + strlen(post) + 1;
  520.     char *line;
  521.     gs_init2();    /* Finish initialization */
  522.     line = gs_malloc(len, 1, "argproc");
  523.     if ( line == 0 )
  524.     {    lprintf("Out of memory!\n");
  525.         gs_exit(1);
  526.     }
  527.     strcpy(line, pre);
  528.     esc_strcat(line, arg);
  529.     strcat(line, post);
  530.     run_string(line, flush);
  531. }
  532. private void
  533. run_string(const char *str, bool flush)
  534. {    int exit_code;
  535.     ref error_object;
  536.     int code = gs_run_string(str, gs_user_errors, &exit_code, &error_object);
  537.     if ( flush || code != 0 )
  538.     {    zflush(osp);        /* flush stdout */
  539.         zflushpage(osp);    /* force display update */
  540.     }
  541.     switch ( code )
  542.     {
  543.     case 0:
  544.         break;
  545.     case e_Quit:
  546.         gs_exit(0);
  547.     case e_Fatal:
  548.         eprintf1("Unrecoverable error, exit code %d\n", exit_code);
  549.         gs_exit(exit_code);
  550.     default:
  551.         gs_debug_dump_stack(code, &error_object);
  552.         gs_exit_with_code(255, code);
  553.     }
  554. }
  555.  
  556. /* Print the revision and revision date. */
  557. private void
  558. print_revision(void)
  559. {    ref rrev;
  560.     byte rstr[10];
  561.     uint len;
  562.     byte *pchars;
  563.     /* We use obj_cvs to guarantee a '.' in the printed output. */
  564.     /* What a nuisance! */
  565.     make_real(&rrev, gs_revision / 100.0);
  566.     obj_cvs(&rrev, rstr, sizeof(rstr), &len, &pchars);
  567.     rstr[len] = 0;
  568.     fprintf(stdout, "%s version %s", gs_product, rstr);
  569.     fprintf(stdout, " (%d/%d/%d)\n%s",
  570.         (int)(gs_revisiondate / 100 % 100),
  571.         (int)(gs_revisiondate % 100), (int)(gs_revisiondate / 10000),
  572.         gs_copyright);
  573. }
  574.