/* @(#)main.c 1.11 89/12/12 * * Main routine and declarations used by the popi program. * * Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs. * This version is based on the code in his Prentice Hall book, * "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7, * which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. * * Permission is given to distribute these extensions, as long as these * introductory messages are not removed, and no monies are exchanged. * * No responsibility is taken for any errors or inaccuracies inherent * either to the comments or the code of this program, but if reported * (see README file) then an attempt will be made to fix them. */ #include #include #include "popi.h" #include "patchlevel.h" /* prototypes for local functions */ bool do_parse P((void)); void get_options P((char **)); void Usage P((int)); int main P((int, char **)); struct SRC src[MAXIMG]; /* array of images */ short CUROLD = 0; /* index of "old" image */ short CURNEW = 1; /* index of "new" image */ int noerr = 1; int lexval; /* value of numerical token */ int Xsize = DEF_X, /* image width */ Ysize = DEF_Y, /* image height */ Zsize = DEF_ZSIZE; /* no. brightness levels */ pixel_t Zmax = DEF_ZSIZE - 1; /* max brightness level */ char text[512]; /* value of string token */ char *ProgName, /* program name (for err messages) */ *LogFile = "popi.log"; /* Name of log file */ FILE *Debug = NULL, /* debugging output stream */ *LogStr = NULL; /* logging output stream */ int disp_active = 1, /* so we can turn off the display */ Truncate = 0, /* Truncate assignments instead of wrapping. */ Verbose = 0; /* be chatty */ char geometry[MAXLINE]; /* X11 geometry information. */ char x11_display[MAXLINE]; /* X11 display information. */ int iconic = 0; /* Set if the window is in an iconic state. */ #if SEQPAR int ncpus = 1; /* default is single-tasking */ #endif /* SEQPAR */ static char *UsageMsg[] = { "valid options:", "\t-xWidth\t\tspecify image width (number pixels)", "\t-yHeight\tspecify image height (number scanlines)", "\t-a[+-]\t\tturn auto-display on or off", "\t-r[+-]\t\tturn range checking on or off", (char *) 0 }; void PrStrs(msg) char *msg[]; { char **p; p = msg; for (p = msg; *p; ++p) FPRINTF(stderr, "%s\n", *p); } static void Usage(status) int status; { FPRINTF(stderr, "Usage: %s [options] [image-files]\n", ProgName); PrStrs(UsageMsg); /* Also need a driver-specific usage message appended */ exit(status); } void version() { FPRINTF(stderr, "%s: version 2.1.%1d\n", ProgName, PATCHLEVEL); } static void get_options(argv) /* read command line options. */ char *argv[]; { for (ProgName = *argv++; *argv && **argv == '-'; ++argv) { switch (*++*argv) { case 'x': Xsize = atoi(++*argv); break; case 'y': Ysize = atoi(++*argv); break; case 'z': Zsize = atoi(++*argv); Zmax = (pixel_t) (Zsize - 1); break; case 'D': if (*++*argv) { if ((Debug = fopen(*argv, "w")) == NULL) { SPRINTF(ErrBuf, "Can't open debug file '%s' - using stderr", *argv); error(ERR_SYS); Debug = stderr; } } else Debug = stderr; setbuf(Debug, NULL); /**/ break; case 'l': /* log all commands */ if (*++*argv) LogFile = *argv; OpenLog(); break; case 'p': /* No. cpus to use in parallel */ /* Still recognise the option on other machines, * so scripts can use this option portably. */ #if SEQPAR if (*++*argv) { ncpus = atoi(*argv); if (ncpus >= cpus_online()) ncpus = cpus_online() - 1; if (ncpus < 0) ncpus = 0; } else ncpus = cpus_online() - 1; #endif /* SEQPAR */ break; case 'd': /* x11 display information. */ ++argv; STRCPY(x11_display,*argv); break; case 'g': /* x11 geometry information. */ ++argv; STRCPY(geometry,*argv); break; case 'i': /* start window iconically. */ iconic = 1; break; case 'r': /* range checking */ if (*++*argv == '-') RangeCheck = 0; else RangeCheck = 1; break; case 'a': /* auto-display */ if (*++*argv == '+') disp_active = 1; else disp_active = 0; break; case 'v': /* verbose */ if (*++*argv == '-') Verbose = 0; else ++Verbose; break; case 'V': /* print version number. */ version(); exit(0); break; case '?': /* Print usage message */ Usage(0); /* NOTREACHED */ /* Note: no error on default because drivers may * interpret other options. */ default: --*argv; /* reset for disp_init() */ } } src[CUROLD].pix = ImgAlloc(); src[CUROLD].str = "old"; src[CURNEW].pix = ImgAlloc(); src[CURNEW].str = "new"; for (; *argv; ++argv) getpix(*argv, (char *) 0); } /* * Parse = # special * | '?' help * | 'q' quit */ static bool do_parse() { extern int lat ; /* look ahead token */ /* display popi prompt and clear input line. Returns length of popi prompt. */ CharPos = disp_prompt(); if (LogStr) { FPRINTF(LogStr, "-> "); FFLUSH(LogStr); } lex(); switch (lat) { case '#': special(); break; case '?': help(); Skip(); break; case 'q': return FALSE; case '\n': break; default: transform(); if (noerr) run(); break; } assert(lat == '\n'); return TRUE; } /* * We deliberately don't exit on error here. * The user may have some picture that has taken ages to develop. * If we run out of memory, they have a chance to save the * image and exit themselves, which they should do as soon * as possible. */ char * Emalloc(n) unsigned int n; { char *try; static unsigned long TotalAllocated = 0L; if ((try = malloc(n)) == NULL) { SPRINTF(ErrBuf, "Allocate %u bytes failed (total malloc=%lx)", n, TotalAllocated); error(ERR_SYS); } TotalAllocated += n; return try; } main(argc,argv) int argc; char **argv; { get_options(argv) ; /* read the command line options. */ disp_init(argc, argv); #if SEQPAR m_set_procs(ncpus); #endif /* SEQPAR */ do noerr = TRUE; while (do_parse()); disp_finish(); /* Some compilers don't get the exit status right when * you return from main() */ exit(0); return 0; /* shut up warning messages from some compilers */ }