home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume22 / popi / part02 < prev    next >
Text File  |  1991-08-22  |  50KB  |  2,033 lines

  1. Newsgroups: comp.sources.misc
  2. From: Rich Burridge <richb@Aus.Sun.COM>
  3. Subject:  v22i041:  popi - The Digital Darkroom, Part02/09
  4. Message-ID: <1991Aug22.152951.15472@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: cbe43b2ce1a4e1cd1a09acf062ce3c0e
  6. Date: Thu, 22 Aug 1991 15:29:51 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Rich Burridge <richb@Aus.Sun.COM>
  10. Posting-number: Volume 22, Issue 41
  11. Archive-name: popi/part02
  12. Environment: Xlib, Xview, SunView
  13. Supersedes: popi: Volume 9, Issue 47-55
  14.  
  15. #! /bin/sh
  16. # 1. Remove everything above the #! /bin/sh line
  17. # 2. Save the resulting text in a file.
  18. # 3. Execute the file with /bin/sh to create the files:
  19. #    debug.c
  20. #    expr.c
  21. #    io.c
  22. #    lex.c
  23. #    main.c
  24. #    polar.c
  25. # This archive created: Wed Aug 21 10:35:49 EST 1991
  26. #
  27. #
  28. export PATH; PATH=/bin:$PATH
  29. #
  30. if [ -f debug.c ]
  31. then
  32. echo shar: will not over-write existing file debug.c
  33. else
  34. echo shar: extracting 'debug.c',     1542 characters
  35. cat > debug.c <<'Funky_Stuff'
  36.  
  37. /*  @(#)debug.c 1.2 90/12/28
  38.  *
  39.  *  Debug routines used by the popi program.
  40.  *
  41.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  42.  *  This version is based on the code in his Prentice Hall book,
  43.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  44.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc.
  45.  *
  46.  *  Permission is given to distribute these extensions, as long as these
  47.  *  introductory messages are not removed, and no monies are exchanged.
  48.  *
  49.  *  No responsibility is taken for any errors or inaccuracies inherent
  50.  *  either to the comments or the code of this program, but if reported
  51.  *  (see README file) then an attempt will be made to fix them.
  52.  */
  53.  
  54. #include "popi.h"
  55.  
  56. #ifdef DEBUG
  57. char *LatStrings[] = {
  58.   "PLUS",
  59.   "MINUS",
  60.   "MULT",
  61.   "DIV",
  62.   "MOD",
  63.   "GT",
  64.   "LT",
  65.   "GE",
  66.   "LE",
  67.   "EQ",
  68.   "NE",
  69.   "AND",
  70.   "OR",
  71.   "XOR",
  72.   "BOR",
  73.   "BAND",
  74.   "X",
  75.   "Y",
  76.   "UMIN",
  77.   "LNOT",
  78.   "ASSIGN",
  79.   "CRVAL",
  80.   "CLVAL",
  81.   "PRVAL",
  82.   "PLVAL",
  83.   "POW",
  84.   "ANGLE",
  85.   "RADIUS",
  86.   "SIN",
  87.   "COS",
  88.   "ATAN",
  89.   "HYPOT",
  90.   "ABS",
  91.   "LOG",
  92.   "SQRT",
  93.   "RAND",
  94.   "LSHIFT",
  95.   "RSHIFT",
  96.   "QUEST",
  97.   "COLON",
  98. } ;
  99.  
  100. char *LatStrings1[] = {
  101.   "FNAME",
  102.   "FNUM",
  103.   "INAME",
  104.   "INUM",
  105.   "NAME",
  106.   "NEW",
  107.   "SPECIAL",
  108.   "VALUE",
  109.   "NL",
  110.   "AT",
  111.   "DOLLAR",
  112.   "LPAREN",
  113.   "RPAREN",
  114.   "LSQUARE",
  115.   "RSQUARE",
  116.   "LCURLY",
  117.   "RCURLY",
  118.   "COMMA",
  119.   "QUIT",
  120.   "OLDSPECIAL",
  121. };
  122.  
  123.  
  124. char *
  125. LatString(t)
  126. int t ;
  127. {
  128.   if (t < 100) return(LatStrings[t-1]) ;
  129.   return(LatStrings1[t-100]) ;
  130. }
  131. #endif /* DEBUG */
  132. Funky_Stuff
  133. len=`wc -c < debug.c`
  134. if [ $len !=     1542 ] ; then
  135. echo error: debug.c was $len bytes long, should have been     1542
  136. fi
  137. fi # end of overwriting check
  138. if [ -f expr.c ]
  139. then
  140. echo shar: will not over-write existing file expr.c
  141. else
  142. echo shar: extracting 'expr.c',    14811 characters
  143. cat > expr.c <<'Funky_Stuff'
  144.  
  145. /*  @(#)expr.c 1.3 91/03/25
  146.  *
  147.  *  Parser routines used by the popi program.
  148.  *
  149.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  150.  *  This version is based on the code in his Prentice Hall book,
  151.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  152.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  153.  *
  154.  *  Permission is given to distribute these extensions, as long as these
  155.  *  introductory messages are not removed, and no monies are exchanged.
  156.  *
  157.  *  No responsibility is taken for any errors or inaccuracies inherent
  158.  *  either to the comments or the code of this program, but if reported
  159.  *  (see README file) then an attempt will be made to fix them.
  160.  */
  161.  
  162. #include <stdio.h>
  163. #include <ctype.h>
  164. #include "popi.h"
  165. #include "lex.h"
  166.  
  167. int lat ;                     /* Look ahead token. */
  168. int prs = 0 ;
  169. int RangeCheck = 1 ;
  170.  
  171. parse_t parsed[MAXTOKENS] ;
  172.  
  173. /* Prototypes for local functions */
  174.  
  175. void expr P((void)) ;
  176. void level P((int)) ;
  177. void factor P((void)) ;
  178. void fileref P((int, int)) ;
  179. void expect P((int)) ;
  180. void emit P((int)) ;
  181. void transform P((void)) ;
  182.  
  183. #define  MAX_SAME_PREC  5     /* Max length row of op[], +1 */
  184.  
  185. static int op[][MAX_SAME_PREC] = {
  186.   { T_POW },
  187.   { '*', },            /* Do mul before div, to avoid int underflow */
  188.   { '/', '%' },
  189.   { '+', '-' },
  190.   { T_LSHIFT, T_RSHIFT },
  191.   { '>', '<',  T_GE, T_LE },
  192.   { T_EQ, T_NE },
  193.   { '&' },
  194.   { '^' },
  195.   { '|' },
  196.   { T_AND },
  197.   { T_OR },
  198. } ;
  199.  
  200. static int op_op[][MAX_SAME_PREC] = {
  201.   { OP_POW },
  202.   { OP_MUL, },         /* Do mul before div, to avoid int underflow */
  203.   { OP_DIV, OP_MOD },
  204.   { OP_PLUS, OP_MINUS },
  205.   { OP_LSHIFT, OP_RSHIFT },
  206.   { OP_GT, OP_LT,  OP_GE, OP_LE },
  207.   { OP_EQ, OP_NE },
  208.   { OP_AND },
  209.   { OP_XOR },
  210.   { OP_OR },
  211.   { OP_CAND },
  212.   { OP_COR },
  213. } ;
  214.  
  215. /*  I was using NELS(op) here (see popi.h) but Microsoft Quick C
  216.  *  gets this wrong (it thinks sizeof *op == sizeof op).
  217.  */
  218.  
  219. /** #define PREC_LEVELS  NELS(op) **/
  220. #define  PREC_LEVELS  (sizeof op / sizeof (int [MAX_SAME_PREC]))
  221.  
  222.  
  223. static void
  224. emit(what)
  225. int what ;
  226. {
  227.   DEBUG((Debug, "emit(%d)\n", what)) ;
  228.  
  229.   if (prs >= MAXTOKENS)
  230.     {
  231.       SPRINTF(ErrBuf, "expression too long") ;
  232.       error(ERR_PARSE) ;
  233.     }
  234.   parsed[prs++] = what ;
  235. }
  236.  
  237.  
  238. /*  Token is either CLVAL or CRVAL, indicating an lvalue or an rvalue.
  239.  *  We actually determine if the coordinates are polar or cartesian.
  240.  */
  241.  
  242. static void
  243. fileref(val, opc)
  244. int val, opc ;
  245. {
  246.   DEBUG((Debug, "fileref(val=%d, opc=%d)\n", val, opc)) ;
  247.  
  248.   if (val < 0 || val >= nimages || Images[val].str == (char *) 0)
  249.     {
  250.       SPRINTF(ErrBuf, "bad file number: %d", val - 1) ;
  251.       error(ERR_PARSE) ;
  252.     }
  253.  
  254.   DEBUG((Debug, "fileref name='%s'\n", Images[val].str)) ;
  255.  
  256.   emit(OP_VALUE) ;
  257.   emit(val) ;
  258.   if (lat == '[')
  259.     {
  260.  
  261. /* Cartesian coordinate reference */
  262.  
  263.       lex() ;
  264.       expr() ;
  265.       expect(',') ;
  266.       expr() ;
  267.       expect(']') ;    /* [x, y] */
  268.       emit(opc) ;
  269.       return ;
  270.     }
  271.  
  272.   if (lat == '{')
  273.     {
  274.  
  275. /* Polar coordinate reference */
  276.  
  277.       lex() ;
  278.       expr() ;
  279.       expect(',') ;
  280.       expr() ;
  281.       expect('}') ;    /* {r, a} */
  282.       emit(opc == OP_CLVAL ? OP_PLVAL : OP_PRVAL) ;
  283.       return ;
  284.     }
  285.  
  286. /* Default (no index specified) is [x, y]. */
  287.  
  288.   emit(OP_X) ;
  289.   emit(OP_Y) ;
  290.   emit(opc) ;
  291. }
  292.  
  293.  
  294. /*  factor  = '(' expr ')'
  295.  *     | UNARYOP factor
  296.  *     | FNCALL1 '(' expr ')'
  297.  *     | FNCALL2 '(' expr ',' expr ')'
  298.  *
  299.  *  UNARYOP  = '!'
  300.  *     | '~'
  301.  *
  302.  *  FNCALL1  = 'sin'
  303.  *     | 'cos'
  304.  *     | 'log'
  305.  *     | 'sqrt'
  306.  *     | 'abs'
  307.  *
  308.  *  FNCALL2  = 'atan'
  309.  */
  310.  
  311. static void
  312. factor()
  313. {
  314.   int token ;
  315.  
  316.   DEBUG((Debug, "factor() lat='%c'\n", lat)) ;
  317.  
  318.   switch (token = lat)
  319.     {
  320.       case '('     : lex() ;
  321.                      expr() ;
  322.                      expect(')') ;
  323.                      break ;
  324.  
  325.       case '-'     : lex() ;
  326.                      factor();
  327.                      if (parsed[prs-2] == OP_VALUE)  /* Constant evaluation */
  328.                        parsed[prs-1] = -parsed[prs-1] ;
  329.                      else
  330.                        emit(OP_UMIN) ;
  331.                      break ;
  332.  
  333.       case '!'     : lex() ;
  334.                      factor() ;
  335.                      if (parsed[prs-2] == OP_VALUE)
  336.                        parsed[prs-1] = !parsed[prs-1] ;
  337.                      else
  338.                        emit(OP_NOT) ;
  339.                      break ;
  340.  
  341.       case '~'     : lex() ;
  342.                      factor() ;
  343.                      if (parsed[prs-2] == OP_XOR)
  344.                        parsed[prs-1] = ~parsed[prs-1] ;
  345.                      else
  346.                        emit(token) ;
  347.                      break ;
  348.  
  349.       case T_INAME : lex() ;
  350.                      fileref(lexval, OP_CRVAL) ;
  351.                      break ;
  352.  
  353.       case '$'     : lex() ;
  354.                      expect(T_VALUE) ;
  355.  
  356. /* $1 refers to Images[2] */
  357.  
  358.                      fileref(lexval-1+2, OP_CRVAL) ;
  359.                      break ;
  360.  
  361.       case T_VALUE : emit(OP_VALUE) ;
  362.                      emit(lexval) ;
  363.                      lex() ;
  364.                      break ;
  365.  
  366.       case 'r'     : MakePolar() ;  /* Create polar coordinate lookup tables */
  367.                      emit(OP_R) ;
  368.                      lex() ;
  369.                      break ;
  370.  
  371.       case 'a'     : MakePolar() ;  /* Create polar coordinate lookup tables */
  372.                      emit(OP_A) ;
  373.                      lex() ;
  374.                      break ;
  375.  
  376.       case 'y'     : emit(OP_Y) ;
  377.                      lex() ;
  378.                      break ;
  379.  
  380.       case 'x'     : emit(OP_X) ;
  381.                      lex() ;
  382.                      break ;
  383.  
  384.       case T_RAND  : lex() ;
  385.                      expect('(') ;
  386.                      expect(')') ;
  387.                      emit(OP_RAND) ;
  388.                      break ;
  389.  
  390.       case T_SIN   :
  391.       case T_COS   :
  392.       case T_LOG   :
  393.       case T_SQRT  :
  394.       case T_ABS   : lex() ;
  395.                      expect('(');
  396.                      expr() ;
  397.                      expect(')') ;
  398.                      if (parsed[prs-2] == OP_VALUE)
  399.                        {
  400.                          switch (token)
  401.                            {
  402.                              case T_SIN  : parsed[prs-1] = (parse_t)
  403.                                             sin((double) DtoR(parsed[prs-1])) ;
  404.                                            break ;
  405.                              case T_COS  : parsed[prs-1] = (parse_t)
  406.                                             cos((double) DtoR(parsed[prs-1])) ;
  407.                                            break ;
  408.                              case T_LOG  : parsed[prs-1] = (parse_t)
  409.                                             log((double) parsed[prs-1]) ;
  410.                                            break ;
  411.                              case T_SQRT : parsed[prs-1] = (parse_t)
  412.                                             sqrt((double) parsed[prs-1]) ;
  413.                                            break ;
  414.                              case T_ABS  : if (parsed[prs-1] < 0)
  415.                                              parsed[prs-1] = -parsed[prs-1] ;
  416.                            }
  417.                        }
  418.                      else
  419.                        {
  420.                          switch (token)
  421.                            {
  422.                              case T_SIN  : emit(OP_SIN) ;
  423.                                            break ;
  424.                              case T_COS  : emit(OP_COS) ;
  425.                                            break ;
  426.                              case T_LOG  : emit(OP_LOG) ;
  427.                                            break ;
  428.                              case T_SQRT : emit(OP_SQRT) ;
  429.                                            break ;
  430.                              case T_ABS  : emit(OP_ABS) ;
  431.                            }
  432.                        }
  433.                      break ;
  434.  
  435.       case T_ATAN  :
  436.       case T_HYPOT : lex() ;
  437.                      expect('(') ;
  438.                      expr() ;
  439.                      expect(',') ;
  440.                      expr() ;
  441.                      expect(')') ;
  442.                      emit(token == T_ATAN? OP_ATAN : OP_HYPOT) ;
  443.                      break ;
  444.  
  445.       default      : SPRINTF(ErrBuf, "expr: syntax error (expected factor)") ;
  446.                      error(ERR_PARSE) ;
  447.     }
  448. }
  449.  
  450.  
  451. /*  Recursive descent parser for binary operators as specified
  452.  *  in the op[] array above.
  453.  *
  454.  *  term  = factor BINARYOP term
  455.  */
  456.  
  457. static void
  458. level(nr)
  459. int nr ;
  460. {
  461.   int i ;
  462.   extern int noerro ;
  463.  
  464.   DEBUG((Debug, "level(%d) lat='%c'\n", nr, lat)) ;
  465.  
  466.   if (nr < 0)
  467.     {
  468.       factor() ;
  469.       return ;
  470.     }
  471.  
  472.   level(nr-1) ;
  473.  
  474.   for (i = 0; op[nr][i] != 0 && noerr; i++)
  475.     if (lat == op[nr][i])
  476.       {
  477.  
  478. /*  LHS of op is already on parse string;
  479.  *  process RHS and then emit the operator
  480.  */
  481.         lex() ;
  482.         level(nr) ;
  483.  
  484. /*  Do a little compile-time constant evaluation here
  485.  *
  486.  *  If the parse string looks like this:
  487.  *      <= prs
  488.  *  +  value    (prs - 1)  RHS
  489.  *  ^  VALUE    (prs - 2)
  490.  *  v  value    (prs - 3)  LHS
  491.  *  -  VALUE    (prs - 4)
  492.  *  then instead of emitting the operation, we can evaluate.
  493.  */
  494.  
  495.         if (prs >= 4 && parsed[prs-2] == OP_VALUE && parsed[prs-4] == OP_VALUE)
  496.           {
  497.             parse_t *dest = &parsed[prs-3] ;
  498.             parse_t *src  = &parsed[prs-1] ;
  499.  
  500.             DEBUG((Debug, "Optimise: %ld %ld '%c'(%d) ",
  501.                            *dest, *src, lat, lat)) ;
  502.             switch(op[nr][i])
  503.               {
  504.                 case T_POW    : *dest = (parse_t)
  505.                                         pow((double) *dest, (double) *src) ;
  506.                                 break ;
  507.  
  508.                 case '*'      : *dest *= *src ;
  509.                                 break ;
  510.  
  511.                 case '/'      : if (*src == 0) *dest = Zmax ;
  512.                                 else           *dest /= *src ;
  513.                                 break ;
  514.  
  515.                 case '%'      : if (*src != 0) *dest %= *src ;
  516.                                 break ;
  517.  
  518.                 case '+'      : *dest += *src ;
  519.                                 break ;
  520.  
  521.                 case '-'      : *dest -= *src ;
  522.                                 break ;
  523.  
  524.                 case T_LSHIFT : *dest <<= *src ;
  525.                                 break ;
  526.  
  527.                 case T_RSHIFT : *dest >>= *src ;
  528.                                 break ;
  529.  
  530.                 case '>'      : *dest = *dest > *src ;
  531.                                 break ;
  532.  
  533.                 case '<'      : *dest = *dest < *src ;
  534.                                 break ;
  535.  
  536.                 case T_GE     : *dest = *dest >= *src ;
  537.                                 break ;
  538.  
  539.                 case T_LE     : *dest = *dest <= *src;
  540.                                 break ;
  541.  
  542.                 case T_EQ     : *dest = *dest == *src ;
  543.                                 break ;
  544.  
  545.                 case T_NE     : *dest = *dest != *src ;
  546.                                 break ;
  547.  
  548.                 case '&'      : *dest &= *src ;
  549.                                 break ;
  550.  
  551.                 case '^'      : *dest ^= *src ;
  552.                                 break ;
  553.  
  554.                 case '|'      : *dest |= *src ;
  555.                                 break ;
  556.  
  557.                 case T_AND    : *dest = *dest && *src ;
  558.                                 break ;
  559.  
  560.                 case T_OR     : *dest = *dest || *src ;
  561.                                 break ;
  562.  
  563.                 default : SPRINTF(ErrBuf,
  564.                            "Unrecognised token (%d) found during optimisation",
  565.                            lat) ;
  566.                           error(ERR_SNARK) ;
  567.               }
  568.             prs -= 2 ;
  569.             DEBUG((Debug, "=> %ld\n", *dest)) ;
  570.           }
  571.         else emit(op_op[nr][i]) ;
  572.         break ;
  573.       }
  574. }
  575.  
  576.  
  577. #ifndef __MSC__        /* MSC gets scope rules wrong */
  578. static
  579. #endif  /* __MSC__ */
  580. void
  581. expr()
  582. {
  583.   extern int prs ;
  584.   int remem1, remem2 ;
  585.  
  586.   DEBUG((Debug, "expr() lat='%c'\n", lat)) ;
  587.   DEBUG((Debug, "levels of precedence: %d\n", PREC_LEVELS)) ;
  588.  
  589.   level(PREC_LEVELS - 1) ;
  590.  
  591.   if (lat == '?')
  592.     {
  593.       lex() ;
  594.       emit(OP_CONDIT) ;
  595.       remem1 = prs ;
  596.       emit(0) ;             /* Actual value filled in below. */
  597.       expr() ;
  598.       expect(':') ;
  599.       emit(OP_COLON) ;
  600.       remem2 = prs ;
  601.       emit(0) ;             /* Actual value filled in below. */
  602.       parsed[remem1] = prs-1 ;
  603.       expr() ;
  604.       parsed[remem2] = prs-1 ;
  605.     }
  606. }
  607.  
  608.  
  609. void
  610. expect(t)
  611. int t ;
  612. {
  613.   DEBUG((Debug, "expect('%c')\n", t)) ;
  614.  
  615.   if (lat == t) lex() ;
  616.   else
  617.     {
  618.       if (t < 127) SPRINTF(ErrBuf, "expected token '%c' (%d)", t, t) ;
  619.       else         SPRINTF(ErrBuf, "expected token (%d)", t) ;
  620.       error(ERR_PARSE) ;
  621.     }
  622. }
  623.  
  624.  
  625. /*  Transform  =  NEW '[' index ']' '=' expr
  626.  *     |  NEW '=' expr
  627.  *     |  expr
  628.  */
  629.  
  630. static void
  631. transform()
  632. {
  633.   extern int prs ;
  634.  
  635.   DEBUG((Debug, "transform() lat='%c'\n", lat)) ;
  636.  
  637.   prs = 0 ;     /* initial length of parse string */
  638.   DEBUG((Debug, "lat=%d, NEW=%d, lat!=NEW = %d\n", lat, T_NEW, lat != T_NEW)) ;
  639.   if (lat != T_NEW)
  640.     {
  641.       expr() ;
  642.       emit(OP_AT) ;
  643.     }
  644.   else
  645.     {
  646.       lex() ;
  647.       if (lat == '[')
  648.         {
  649.           fileref((int)(CurNew - Images), OP_CLVAL) ;
  650.           expect('=') ;
  651.           expr() ;
  652.           emit(OP_ASGN) ;
  653.         }
  654.       else
  655.         {
  656.           expect((int) "=") ;
  657.           expr() ;
  658.           emit(OP_AT) ;
  659.         }
  660.     }
  661.   if (lat != '\n')
  662.     {
  663.       SPRINTF(ErrBuf,
  664.               "syntax error - expected operator or end of expression") ;
  665.               error(ERR_PARSE) ;
  666.     }
  667.   assert(lat == '\n') ;
  668. }
  669.  
  670.  
  671. /*  Parse  = :          special
  672.  *     | '?'            help
  673.  *     | 'q'            quit
  674.  *     | transform      transformation expression
  675.  */
  676.  
  677. void
  678. parse(istr)
  679. FILE *istr ;
  680. {
  681.   extern int lat ;       /* Look ahead token. */
  682.   FILE *SaveInput ;      /* Saved previous input stream. */
  683.  
  684.   DEBUG((Debug, "parse()\n")) ;
  685.  
  686. /* Save and then reset current input stream. */
  687.  
  688.   SaveInput = InputStream;
  689.   InputStream = istr;
  690.  
  691.   do
  692.     {
  693.       DEBUG((Debug, "parse() - top of loop\n")) ;
  694.       noerr = TRUE ;
  695.  
  696. /* Display popi prompt and clear input line. Returns length of popi prompt. */
  697.  
  698.       CharPos = istr ? 0 : disp_prompt() ;
  699.  
  700.       if (LogStr)
  701.         {
  702.           FPRINTF(LogStr, "-> ") ;
  703.           FFLUSH(LogStr) ;
  704.         }
  705.  
  706.       lex() ;
  707.  
  708.       switch (lat)
  709.         {
  710.  
  711. /* Keep '#' for backwards compatibility */
  712.  
  713.           case '#'  :
  714.           case ':'  : special() ;
  715.                       break ;
  716.  
  717.           case '?'  : help() ;
  718.                       Skip() ;
  719.                       break ;
  720.  
  721.           case 'q'  : Quit() ;
  722.                       /* NOTREACHED */
  723.  
  724.           case EOF  :
  725.           case '\n' : break ;
  726.  
  727.           default   : transform() ;
  728.                       if (noerr) run() ;
  729.         }
  730.       assert(lat == '\n' || lat == EOF) ;
  731.     }
  732.   while (lat != EOF) ;
  733.  
  734. /* Restore saved previous input stream. */
  735.  
  736.   InputStream = SaveInput ;
  737. }
  738. Funky_Stuff
  739. len=`wc -c < expr.c`
  740. if [ $len !=    14811 ] ; then
  741. echo error: expr.c was $len bytes long, should have been    14811
  742. fi
  743. fi # end of overwriting check
  744. if [ -f io.c ]
  745. then
  746. echo shar: will not over-write existing file io.c
  747. else
  748. echo shar: extracting 'io.c',    10951 characters
  749. cat > io.c <<'Funky_Stuff'
  750.  
  751. /*  @(#)io.c 1.7 91/08/20
  752.  *
  753.  *  File handling routines used by the popi program.
  754.  *
  755.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  756.  *  This version is based on the code in his Prentice Hall book,
  757.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  758.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  759.  *
  760.  *  Permission is given to distribute these extensions, as long as these
  761.  *  introductory messages are not removed, and no monies are exchanged.
  762.  *
  763.  *  No responsibility is taken for any errors or inaccuracies inherent
  764.  *  either to the comments or the code of this program, but if reported
  765.  *  (see README file) then an attempt will be made to fix them.
  766.  */
  767.  
  768.  
  769. #include <stdio.h>
  770. #include <string.h>
  771. #include <errno.h>
  772. #include <ctype.h>
  773. #include "popi.h"
  774. #include "libpbm.h"
  775.  
  776. #if           unix || AMIGA
  777. #define  RMODE  "r"
  778. #define  WMODE  "w"
  779. #else   /* ! (unix || AMIGA) */
  780. #define  RMODE  "rb"
  781. #define  WMODE  "wb"
  782. #endif  /*    unix || AMIGA */
  783.  
  784. #if  defined(unix)
  785. static bool IsPopen = FALSE ;
  786. #endif  /* unix */
  787.  
  788. int nimages = 2 ;
  789.  
  790.  
  791. pixel_t ***
  792. ImgAlloc()
  793. {
  794.   int color ;
  795.   pixel_t ***img ;
  796.   pixel_t ***linep ;
  797.   pixel_t ***imgend ;
  798.  
  799.   noerr = TRUE ;
  800.   img = (pixel_t ***)
  801.         LINT_CAST(Emalloc((unsigned)Ysize * sizeof(pixel_t **))) ;
  802.   if (img == 0) return((pixel_t ***) 0) ;
  803.  
  804.   imgend = &img[Ysize] ;
  805.   for (linep = img; linep != imgend; ++linep)
  806.     {
  807.       *linep = (pixel_t **)
  808.                LINT_CAST(Emalloc((unsigned)colors * sizeof (pixel_t *))) ;
  809.       for (color = 0; color < colors; color++)
  810.         (*linep)[color] = (pixel_t *)
  811.                        LINT_CAST(Emalloc((unsigned)Xsize * sizeof (pixel_t))) ;
  812.     }
  813.  
  814.   if (!noerr)
  815.     {
  816.  
  817. /* Run out of memory; free what we have allocated */
  818.  
  819.       for (linep = img; linep != imgend; ++linep)
  820.         if (*linep)
  821.           for (color = 0; color < colors; color++)
  822.             {
  823.               if ((*linep)[color]) free((char *) (*linep)[color]) ;
  824.               free((char *) *linep) ;
  825.             }
  826.       return((pixel_t ***) 0) ;
  827.     }
  828.   return(img) ;
  829. }
  830.  
  831.  
  832. void
  833. ImgFree(img)
  834. struct SRC *img ;
  835. {
  836.   int color, y ;
  837.   pixel_t **p ;
  838.  
  839.   free(img->str) ;
  840.   img->str = (char *) 0 ;
  841.  
  842.   for (y = 0; y < Ysize; ++y)
  843.     {
  844.       p = img->pix[y] ;
  845.       for (color = 0; color < colors; color++)
  846.         free((char *) p[color]) ;
  847.       free((char *) p) ;
  848.     }
  849.  
  850.   free((char *) img->pix) ;
  851.   img->pix = (pixel_t ***) 0 ;
  852. }
  853.  
  854.  
  855. void
  856. Efclose(stream)
  857. FILE *stream ;
  858. {
  859. #ifdef  unix
  860.   if (IsPopen)
  861.     {
  862.       PCLOSE(stream) ;
  863.       IsPopen = FALSE ;
  864.     }
  865.   else
  866. #endif  /* unix */
  867.     FCLOSE(stream) ;
  868. }
  869.  
  870.  
  871. FILE *
  872. EfopenR(filename)
  873. char *filename ;
  874. {
  875.   FILE *istr ;
  876. #if unix
  877.   FILE *popen() ;
  878. #endif /* unix */
  879.  
  880.   DEBUG((Debug, "EfopenR(%s)\n", filename)) ;
  881.   if ((istr = fopen(filename, RMODE)) != NULL) return(istr) ;
  882.  
  883. #if  unix
  884.   if (errno == ENOENT)
  885.     {
  886.       char buf[MAXPATHLEN] ;
  887.  
  888. /* First see if the compressed file exists and is readable */
  889.  
  890.       SPRINTF(buf, "%s.Z", filename) ;
  891.       if ((istr = fopen(buf, "r")) != NULL)
  892.         {
  893.  
  894. /* OK - it's there */
  895.  
  896.           FCLOSE(istr) ;
  897.           SPRINTF(buf, "zcat %s", filename) ;
  898.           DEBUG((Debug, "popen(%s)\n", buf)) ;
  899.           if ((istr = popen(buf, "r")) != NULL)
  900.             {
  901.               IsPopen = TRUE ;
  902.               return(istr) ;
  903.             }
  904.         }
  905.     }
  906. #endif  /* unix */
  907.  
  908.   SPRINTF(ErrBuf, "Can't read file '%s'", filename) ;
  909.   error(ERR_SYS) ;
  910.   return(NULL) ;
  911. }
  912.  
  913.  
  914. FILE *
  915. EfopenW(filename)
  916. char *filename ;
  917. {
  918.   FILE *ostr ;
  919. #ifdef  unix
  920.   FILE *popen() ;
  921. #endif  /* unix */
  922.  
  923.   DEBUG((Debug, "EfopenW(%s)\n", filename)) ;
  924.  
  925. #ifdef  unix
  926.   if (*filename == '|')
  927.     {
  928.       ++filename ;
  929.  
  930.       if ((ostr = popen(filename, "w")) == NULL)
  931.         {
  932.           SPRINTF(ErrBuf, "Can't run command '%s'", filename) ;
  933.           error(ERR_SYS) ;
  934.         }
  935.       IsPopen = TRUE ;
  936.       return ostr ;
  937.     }
  938. #endif  /* unix */
  939.  
  940.   if ((ostr = fopen(filename, WMODE)) == NULL)
  941.     {
  942.       SPRINTF(ErrBuf, "Can't write file '%s'", filename) ;
  943.       error(ERR_SYS) ;
  944.     }
  945.   return(ostr) ;
  946. }
  947.  
  948.  
  949. void
  950. do_ioerror(fd, filename, direction, row)
  951. FILE *fd ;
  952. char *filename, *direction ;
  953. int row ;
  954. {
  955.   if (ferror(fd))
  956.     {
  957.       SPRINTF(ErrBuf, "File '%s' %s error on row %d",
  958.               filename, direction, row) ;
  959.       error(ERR_SYS) ;
  960.       FCLOSE(fd) ;
  961.       return ;
  962.     }
  963.  
  964.   SPRINTF(ErrBuf, "File '%s' insufficient data at row %d", filename, row) ;
  965.   error(0) ;
  966. }
  967.  
  968.  
  969. void
  970. getpix(filename, imgname)
  971. char *filename ;                      /* File name */
  972. char *imgname ;                       /* Image name */
  973. {
  974.   FILE       *fd ;
  975.   struct SRC *img ;                             /* Pointer into Images */
  976.   struct SRC *unused = (struct SRC *) 0 ;       /* First unused slot */
  977.   char       *p, *r, *g, *b ;
  978.   char       *rem ;
  979.   int        len ;
  980.   int        row ;
  981.   pixel_t    ***linep ;
  982.   pixel_t    ***imgend ;
  983.   int        x, mask ;
  984.  
  985.   extern int pm_iserror ;
  986.  
  987.   int        format ;
  988.   pixval     maxval ;
  989.   gray       *grayrow ;
  990.   pixel      *pixelrow ;
  991.  
  992.   len = strlen(filename) ;
  993.   if (len > 2 && !strncmp(&filename[len-2], ".Z", 2)) filename[len-2] = '\0' ;
  994.  
  995.   if ((fd = EfopenR(filename)) == NULL) return ;
  996.   pm_iserror  = FALSE ;
  997.   ppm_readppminit(fd, &Xsize, &Ysize, &maxval, &format) ;
  998.  
  999.   if (format == PBM_FORMAT || format == RPBM_FORMAT ||
  1000.       format == PGM_FORMAT || format == RPGM_FORMAT)
  1001.     {
  1002.       colors = 1 ;
  1003.       grayrow = pgm_allocrow(Xsize) ;
  1004.     }
  1005.   else if (format == PPM_FORMAT || format == RPPM_FORMAT)
  1006.     {
  1007.       colors = 3 ;
  1008.       pixelrow = ppm_allocrow(Xsize) ;
  1009.     }
  1010.   else if (format == OLD_POPI_FORMAT) colors = 1 ;
  1011.  
  1012.   if (imgname == 0 || *imgname == '\0')
  1013.     {
  1014.       imgname = filename ;
  1015.  
  1016. /*
  1017.  *  Use the basename of the filename for the image name. If this results in a
  1018.  *  non-valid image name, they'll just have to use the $n equivalent. It's not
  1019.  *  our business to go transforming names.
  1020.  */
  1021.  
  1022. /* Find last '/' in string */
  1023.  
  1024.       for (p = rem = imgname; *p; ++p)
  1025.         if (*p == '/' && p[1] != '\0') rem = p + 1 ;
  1026.  
  1027.       imgname = rem ;
  1028.     }
  1029.  
  1030. /* See if the named image already exists */
  1031.  
  1032.   for (img = Images; img != &Images[nimages]; ++img)
  1033.     {
  1034.       if (img->str && strcmp(img->str, imgname) == 0) break ;
  1035.  
  1036.       if (img->pix == (pixel_t ***) 0 && unused == (struct SRC *) 0)
  1037.         unused = img ;
  1038.     }
  1039.  
  1040.   if (img == &Images[nimages])
  1041.     {
  1042.  
  1043. /* Named image doesn't exist. Allocate a new image. */
  1044.  
  1045.       if (unused == (struct SRC *) 0) img = &Images[nimages++] ;
  1046.       else img = unused ;
  1047.  
  1048.       if ((img->pix = ImgAlloc()) == 0 ||
  1049.           (img->str = (char *)
  1050.                       Emalloc((unsigned int) (strlen(imgname)+1))) == 0)
  1051.         return ;
  1052.  
  1053.       STRCPY(img->str, imgname) ;
  1054.     }
  1055.  
  1056. /* Read in the image. */
  1057.  
  1058.   row = 0 ;
  1059.   imgend = &img->pix[Ysize] ;
  1060.   for (linep = img->pix; linep != imgend; ++linep)
  1061.     {
  1062.       mask = (signed_io) ? 0x80 : 0x00 ;
  1063.       if (format == PBM_FORMAT || format == RPBM_FORMAT ||
  1064.           format == PGM_FORMAT || format == RPGM_FORMAT)
  1065.         {
  1066.           pgm_readpgmrow(fd, grayrow, Xsize, maxval, format) ;
  1067.           if (pm_iserror == TRUE)
  1068.             {
  1069.               do_ioerror(fd, filename, "read", row) ;
  1070.               return ;
  1071.             }
  1072.           g = (char *) (*linep)[0] ;
  1073.           for (x = 0; x < Xsize; x++)
  1074.             g[x] = (char) (grayrow[x] ^ mask) ;
  1075.         }
  1076.       else if (format == PPM_FORMAT || format == RPPM_FORMAT) 
  1077.         {
  1078.           ppm_readppmrow(fd, pixelrow, Xsize, maxval, format) ;
  1079.           if (pm_iserror == TRUE)
  1080.             {
  1081.               do_ioerror(fd, filename, "read", row) ;
  1082.               return ;
  1083.             }
  1084.           r = (char *) (*linep)[0] ;
  1085.           g = (char *) (*linep)[1] ;
  1086.           b = (char *) (*linep)[2] ;
  1087.           for (x = 0; x < Xsize; x++)
  1088.             {
  1089.               r[x] = pixelrow[x].r ^ mask ;
  1090.               g[x] = pixelrow[x].g ^ mask ;
  1091.               b[x] = pixelrow[x].b ^ mask ;
  1092.             }
  1093.         }
  1094.       else if (format == OLD_POPI_FORMAT)
  1095.         {
  1096.           if (fread((char *) (*linep)[0], 1, Xsize, fd) <= 0)
  1097.             {
  1098.               do_ioerror(fd, filename, "read", row) ;
  1099.               return ;
  1100.             }
  1101.         }
  1102.       row++ ;
  1103.     }
  1104.  
  1105.        if (format == PGM_FORMAT || format == RPGM_FORMAT ||
  1106.            format == PGM_FORMAT || format == RPGM_FORMAT)
  1107.     pgm_freerow(grayrow) ;
  1108.   else if (format == PPM_FORMAT || format == RPPM_FORMAT)
  1109.     ppm_freerow(pixelrow) ;
  1110.   Efclose(fd) ;
  1111. }
  1112.  
  1113.  
  1114. void
  1115. putpix(into, filename)
  1116. struct SRC *into ;               /* Work buffer */
  1117. char *filename ;                 /* File name */
  1118. {
  1119.   FILE    *fd;
  1120.   pixel_t ***linep ;             /* Pointer to a scanline */
  1121.   pixel_t ***imgend ;            /* Pointer to just after end of image */
  1122.   int     row ;
  1123.   char    *r, *g, *b ;
  1124.   int     x, mask ;
  1125.  
  1126.   extern int pm_iserror ;
  1127.  
  1128.   int        format ;
  1129.   pixval     maxval ;
  1130.   gray       *grayrow ;
  1131.   pixel      *pixelrow ;
  1132.  
  1133.   if ((fd = EfopenW(filename)) == NULL) return ;
  1134.   pm_iserror  = FALSE ;
  1135.   maxval = 255 ;
  1136.   if (colors == 1)
  1137.     {
  1138.       format = RPGM_FORMAT ;
  1139.       if (oldfmt != TRUE) pgm_writepgminit(fd, Xsize, Ysize, maxval) ;
  1140.       grayrow = pgm_allocrow(Xsize) ;
  1141.     }
  1142.   else if (colors == 3)
  1143.     {
  1144.       format = RPPM_FORMAT ;
  1145.       ppm_writeppminit(fd, Xsize, Ysize, maxval) ;
  1146.       pixelrow = ppm_allocrow(Xsize) ;
  1147.     }
  1148.  
  1149. /* Write out the image. */
  1150.  
  1151.   row = 0 ;
  1152.   imgend = &into->pix[Ysize] ;
  1153.   for (linep = into->pix; linep != imgend; ++linep)
  1154.     {
  1155.       mask = (signed_io) ? 0x80 : 0x00 ;
  1156.       if (format == RPGM_FORMAT)
  1157.         {
  1158.           g = (char *) (*linep)[0] ;
  1159.           for (x = 0; x < Xsize; x++)
  1160.             grayrow[x] = g[x] ^ mask ;
  1161.           pgm_writepgmrow(fd, grayrow, Xsize, maxval) ;
  1162.           if (pm_iserror == TRUE)
  1163.             {
  1164.               do_ioerror(fd, filename, "write", row) ;
  1165.               return ;
  1166.             }
  1167.         }
  1168.       else if (format == RPPM_FORMAT)
  1169.         {
  1170.           r = (char *) (*linep)[0] ;
  1171.           g = (char *) (*linep)[1] ;
  1172.           b = (char *) (*linep)[2] ;
  1173.           for (x = 0; x < Xsize; x++)
  1174.             {
  1175.               pixelrow[x].r = r[x] ^ mask ;
  1176.               pixelrow[x].g = g[x] ^ mask ;
  1177.               pixelrow[x].b = b[x] ^ mask ;
  1178.             }
  1179.           ppm_writeppmrow(fd, pixelrow, Xsize, maxval) ;
  1180.           if (pm_iserror == TRUE)
  1181.             {
  1182.               do_ioerror(fd, filename, "write", row) ;
  1183.               return ;
  1184.             }
  1185.         }    
  1186.       row++ ;
  1187.     }
  1188.  
  1189.        if (format == RPGM_FORMAT) pgm_freerow(grayrow) ;
  1190.   else if (format == RPPM_FORMAT) ppm_freerow(pixelrow) ;
  1191.  
  1192.   Efclose(fd) ;
  1193. }
  1194.  
  1195.  
  1196. void
  1197. showfiles()
  1198. {
  1199.   struct SRC *img ;
  1200.   struct SRC *endimages ;
  1201.  
  1202.   for (img = &Images[2], endimages = &Images[nimages]; img != endimages; ++img)
  1203.     {
  1204.       if(img->str)
  1205.         {
  1206.           PRINTF("$%d = %s\n", img - Images - 1, img->str) ;
  1207.           if (LogStr)
  1208.             FPRINTF(LogStr, "$%d = %s\n", img - Images + 1, img->str) ;
  1209.         }
  1210.     }
  1211. }
  1212. Funky_Stuff
  1213. len=`wc -c < io.c`
  1214. if [ $len !=    10951 ] ; then
  1215. echo error: io.c was $len bytes long, should have been    10951
  1216. fi
  1217. fi # end of overwriting check
  1218. if [ -f lex.c ]
  1219. then
  1220. echo shar: will not over-write existing file lex.c
  1221. else
  1222. echo shar: extracting 'lex.c',     6952 characters
  1223. cat > lex.c <<'Funky_Stuff'
  1224.  
  1225. /*  @(#)lex.c 1.2 90/12/28
  1226.  *
  1227.  *  Lexical routines used by the popi program.
  1228.  *
  1229.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  1230.  *  This version is based on the code in his Prentice Hall book,
  1231.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  1232.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  1233.  *
  1234.  *  Permission is given to distribute these extensions, as long as these
  1235.  *  introductory messages are not removed, and no monies are exchanged.
  1236.  *
  1237.  *  No responsibility is taken for any errors or inaccuracies inherent
  1238.  *  either to the comments or the code of this program, but if reported
  1239.  *  (see README file) then an attempt will be made to fix them.
  1240.  */
  1241.  
  1242. #include <stdio.h>
  1243. #include <ctype.h>
  1244. #include <math.h>
  1245. #include "popi.h"
  1246. #include "lex.h"
  1247.  
  1248. /* Prototypes for local functions */
  1249. int Getch P((void)) ;
  1250. int getnumber P((int)) ;
  1251. int getstring P((int)) ;
  1252. int follow P((int, int, int)) ;
  1253.  
  1254. int CharPos = 0 ;     /* Current character pos on input line */
  1255. int OldPos = 0 ;      /* Previous character pos on input line */
  1256. int TokPos = 0 ;      /* Position of the beginning of the current token */
  1257. char ErrBuf[256] ;
  1258. double lexfract ;
  1259. FILE *InputStream = (FILE *) 0 ;
  1260.  
  1261. /* One level of character pushback on stdin to avoid disp_ungetc() */
  1262.  
  1263. char  SaveChar = '\0' ;
  1264.  
  1265.  
  1266. static int
  1267. Getch()
  1268. {
  1269.   int  c ;
  1270.  
  1271.   if (InputStream == (FILE *) 0)
  1272.     {
  1273.       if (SaveChar == '\0') c = disp_getchar() ;
  1274.       else
  1275.         {
  1276.           c = SaveChar;
  1277.           SaveChar = '\0';
  1278.         }
  1279.     }
  1280.   else c = getc(InputStream) ;
  1281.  
  1282.   OldPos = CharPos ;
  1283.  
  1284.        if (c == '\t') CharPos = (CharPos - 1) % 8 + 8 ;
  1285.   else if (c == '\n') CharPos = 0 ;
  1286.   else                ++CharPos ;
  1287.  
  1288.   DEBUG((Debug, "Getch() => '%c'\n", c)) ;
  1289.  
  1290.   if (LogStr && CharPos != OldPos) PUTC(c, LogStr) ;
  1291.  
  1292.   return(c) ;
  1293. }
  1294.  
  1295.  
  1296. void
  1297. Skip()          /* Skip to the end of the line */
  1298. {
  1299.   while (lat != '\n' && lat != EOF)
  1300.     lat = Getch() ;
  1301.   lat = '\n' ;
  1302. }
  1303.  
  1304.  
  1305. void
  1306. error(errtype)
  1307. int errtype ;
  1308. {
  1309.   DEBUG((Debug, "error: type %d, pos %d msg '%s'\n",
  1310.                  errtype, TokPos, ErrBuf)) ;
  1311.   if (!noerr) return ;                        /* Already printed a message */
  1312.   disp_error(errtype, TokPos) ;
  1313.   Skip() ;
  1314.   noerr = FALSE ;                             /* An error has occurred */
  1315.  
  1316.   if (LogStr) FPRINTF(LogStr, "Error: %s\n", ErrBuf) ;
  1317. }
  1318.  
  1319.  
  1320. static int
  1321. getnumber(first)
  1322. int first ;
  1323. {
  1324.   int c ;
  1325.  
  1326.   lexval = first - '0' ;
  1327.   lexfract = 0.0 ;
  1328.   while (isdigit(c = Getch()))
  1329.     lexval = 10 * lexval + c - '0' ;
  1330.  
  1331. /* Some of the special routines use floating values */
  1332.  
  1333.   if (c == '.')
  1334.     {
  1335.       double div = 10.0 ;
  1336.  
  1337.       while (isdigit(c = Getch()))
  1338.         {
  1339.           lexfract += (c - '0') / div ;
  1340.           div *= 10.0;
  1341.         }
  1342.     }
  1343.   pushback(c) ;
  1344.   return(T_VALUE) ;
  1345. }
  1346.  
  1347.  
  1348. static int
  1349. getstring(first)
  1350. int first ;
  1351. {
  1352.   int c = first ;
  1353.   char  *str = text ;
  1354.   struct SRC *img ;
  1355.   struct SRC *endimages ;
  1356.  
  1357.   do
  1358.     {
  1359.       *str++ = (char) c ;
  1360.       c = Getch() ;
  1361.     }
  1362.   while (isalpha(c) || c == '_' || isdigit(c)) ;
  1363.   *str = '\0' ;
  1364.   pushback(c) ;
  1365.  
  1366.        if (strcmp(text, "new")   == 0) return(T_NEW) ;
  1367.   else if (strcmp(text, "sin")   == 0) return(T_SIN) ;
  1368.   else if (strcmp(text, "cos")   == 0) return(T_COS) ;
  1369.   else if (strcmp(text, "atan")  == 0) return(T_ATAN) ;
  1370.   else if (strcmp(text, "hypot") == 0) return(T_HYPOT) ;
  1371.   else if (strcmp(text, "abs")   == 0) return(T_ABS) ;
  1372.   else if (strcmp(text, "log")   == 0) return(T_LOG) ;
  1373.   else if (strcmp(text, "sqrt")  == 0) return(T_SQRT) ;
  1374.   else if (strcmp(text, "rand")  == 0) return(T_RAND) ;
  1375.  
  1376.   for (img = Images, endimages = &Images[nimages]; img != endimages; ++img)
  1377.     {
  1378.       if (img->str && strcmp(img->str, text) == 0)
  1379.         {
  1380.           lexval = (int)(img - Images) ;
  1381.           return(T_INAME) ;
  1382.         }
  1383.     }
  1384.  
  1385.   if (strlen(text) > 1) return(T_NAME) ;
  1386.   return(first) ;
  1387. }
  1388.  
  1389.  
  1390. static int
  1391. follow(tok, ifyes, ifno)
  1392. int tok, ifyes, ifno ;
  1393. {
  1394.   int c ;
  1395.  
  1396.   if ((c = Getch()) == tok) return(ifyes) ;
  1397.   pushback(c) ;
  1398.   return(ifno) ;
  1399. }
  1400.  
  1401.  
  1402. void
  1403. lex()                  /* Set the global lookahead token "lat". */
  1404. {
  1405.   DEBUG((Debug, "lex():\n")) ;
  1406.  
  1407.   do                   /* Ignore white space */
  1408.     lat = Getch() ;
  1409.   while (lat == ' ' || lat == '\t') ;
  1410.  
  1411.   TokPos = CharPos ;
  1412.  
  1413.        if (isdigit(lat))               lat = getnumber(lat) ;
  1414.   else if (isalpha(lat) || lat == '_') lat = getstring(lat) ;
  1415.  
  1416.   switch (lat)
  1417.     {
  1418.       case '*' : lat = follow('*', T_POW, lat) ;
  1419.                  break ;
  1420.  
  1421.       case '>' : lat = follow('=', T_GE, lat) ;
  1422.                  lat = follow('>', T_RSHIFT, lat) ;
  1423.                  break ;
  1424.  
  1425.       case '<' : lat = follow('=', T_LE, lat) ;
  1426.                  lat = follow('<', T_LSHIFT, lat) ;
  1427.                  break ;
  1428.  
  1429.       case '!' : lat = follow('=', T_NE, lat) ;
  1430.                  break ;
  1431.  
  1432.       case '=' : lat = follow('=', T_EQ, lat) ;
  1433.                  break ;
  1434.  
  1435.       case '|' : lat = follow('|', T_OR, lat) ;
  1436.                  break ;
  1437.  
  1438.       case '&' : lat = follow('&', T_AND, lat) ;
  1439.                  break ;
  1440.  
  1441.       case 'Z' : lat = T_VALUE ;
  1442.                  lexval = Zmax ;
  1443.                  break ;
  1444.  
  1445.       case 'Y' : lat = T_VALUE ;
  1446.                  lexval = Ysize - 1 ;
  1447.                  break ;
  1448.  
  1449.       case 'X' : lat = T_VALUE ;
  1450.                  lexval = Xsize - 1 ;
  1451.                  break ;
  1452.  
  1453.       case 'R' : lat = T_VALUE ;
  1454.                  lexval = (int) hypot(Xsize / 2.0, Ysize / 2.0) ;
  1455.                  break ;
  1456.  
  1457.       case 'A' : lat = T_VALUE ;
  1458.                  lexval = 360 ;
  1459.                  break ;
  1460.  
  1461.       case '"' : {
  1462.                    char  *str ;
  1463.  
  1464.                    str = text ;
  1465.                    while ((lat = Getch()) != EOF && lat != '\n' && lat != '"')
  1466.                      *str++ = (char) lat ;
  1467.                    *str = '\0' ;
  1468.                    if (lat != '"')
  1469.                      {
  1470.                        SPRINTF(ErrBuf, "Expected matching '\"'") ;
  1471.                        error(ERR_PARSE) ;
  1472.                        return ;
  1473.                      }
  1474.                  }
  1475.                  lat = T_FNAME ;
  1476.                  break ;
  1477.  
  1478.       case ';' : Skip() ;        /* Comment to end of line */
  1479.                  lat = '\n' ;
  1480.                  break ;
  1481.  
  1482.       case '\\' :                /* Special meaning to next character */
  1483.                   switch (lat = Getch())
  1484.                     {
  1485.                       case '\n' : lex() ; /* Ignore newline - get next token */
  1486.                                   break ;
  1487.  
  1488.                                           /* May be other cases here later. */
  1489.                     }
  1490.                   break ;
  1491.  
  1492.       default  : break ;
  1493.     }
  1494.  
  1495.   if (Debug)
  1496.     {
  1497.       if (lat < 127 && isprint(lat))
  1498.         DEBUG((Debug, "lex() => '%c' (%d)\n", lat, lat)) ;
  1499.       else
  1500.         DEBUG((Debug, "lex() => (%d)\n", lat)) ;
  1501.     }
  1502. }
  1503.  
  1504.  
  1505. void
  1506. pushback(c)
  1507. int c ;
  1508. {
  1509.   DEBUG((Debug, "pushback('%c')\n", c)) ;
  1510.   if (InputStream == (FILE *) 0) SaveChar = c ;
  1511.   else
  1512.     UNGETC(c, InputStream) ;
  1513.   CharPos = OldPos ;
  1514. }
  1515. Funky_Stuff
  1516. len=`wc -c < lex.c`
  1517. if [ $len !=     6952 ] ; then
  1518. echo error: lex.c was $len bytes long, should have been     6952
  1519. fi
  1520. fi # end of overwriting check
  1521. if [ -f main.c ]
  1522. then
  1523. echo shar: will not over-write existing file main.c
  1524. else
  1525. echo shar: extracting 'main.c',     9932 characters
  1526. cat > main.c <<'Funky_Stuff'
  1527.  
  1528. /*  @(#)main.c 1.6 91/08/20
  1529.  *
  1530.  *  Main routine and declarations used by the popi program.
  1531.  *
  1532.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  1533.  *  This version is based on the code in his Prentice Hall book,
  1534.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  1535.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  1536.  *
  1537.  *  Permission is given to distribute these extensions, as long as these
  1538.  *  introductory messages are not removed, and no monies are exchanged.
  1539.  *
  1540.  *  No responsibility is taken for any errors or inaccuracies inherent
  1541.  *  either to the comments or the code of this program, but if reported
  1542.  *  (see README file) then an attempt will be made to fix them.
  1543.  */
  1544.  
  1545.  
  1546. #include <stdio.h>
  1547. #include <ctype.h>
  1548. #include "popi.h"
  1549. #include "patchlevel.h"
  1550.  
  1551. /* Prototypes for local functions */
  1552.  
  1553. void get_options P((int, char **[])) ;
  1554. void Usage P((int)) ;
  1555. int main P((int, char **)) ;
  1556.  
  1557. struct SRC Images[MAXIMG] ;     /* Array of images. */
  1558. struct SRC *CurOld ;            /* Pointer to "old" image */
  1559. struct SRC *CurNew ;            /* Pointer to "new" image */
  1560.  
  1561. pixel_t Zmax = DEF_ZSIZE - 1 ;  /* Max brightness level */
  1562.  
  1563. FILE *Debug = NULL ;            /* Debugging output stream */
  1564. FILE *LogStr = NULL ;           /* Logging output stream */
  1565.  
  1566. char text[512] ;                /* Value of string token */
  1567. char *ProgName ;                /* Program name (for err messages) */
  1568. char *LogFile = "popi.log" ;    /* Name of log file */
  1569. char geometry[MAXLINE] ;        /* X11 geometry information. */
  1570. char x11_display[MAXLINE] ;     /* X11 display information. */
  1571.  
  1572. int noerr = TRUE ;
  1573. int lexval ;                    /* Value of numerical token */
  1574. int BOXW ;                      /* Text box width */
  1575. int TXsize ;                    /* Total width */
  1576. int TYsize ;                    /* Total height */
  1577. int Xsize = DEF_X ;             /* Image width */
  1578. int Ysize = DEF_Y ;             /* Image height */
  1579. int Zsize = DEF_ZSIZE ;         /* No. brightness levels */
  1580. int disp_active = 1 ;           /* So we can turn off the display */
  1581. int colors = 1 ;                /* RGB color mode (default off) */
  1582. int signed_io = 0 ;             /* Signed I/O mode (default off) */
  1583. int Truncate = 0 ;              /* Truncate assignments instead of wrapping. */
  1584. int Verbose = 0 ;               /* Be chatty */
  1585. int iconic = 0 ;                /* Set if the window is in an iconic state. */
  1586. int oldfmt = 0 ;                /* Set to save images in old format. */
  1587. int tcache = 0 ;                /* Set to read/write cached trig info. */
  1588.  
  1589. #if       SEQPAR
  1590. int ncpus = 1 ;                 /* Default is single-tasking */
  1591. #endif /* SEQPAR */
  1592.  
  1593. static char *UsageMsg[] = {
  1594.   "\nvalid options:",
  1595.   "  -a[+-]       turn auto-display on (off)",
  1596.   "  -c[+-]       turn RGB color mode on (off)",
  1597.   "  -D[file]     enable debugging trace (default stderr)",
  1598.   "  -d disp      specify X11 display",
  1599.   "  -g geom      specify X11 geometry",
  1600.   "  -i           start window iconically",
  1601.   "  -l[file]     log all commands (default ./popi.log)",
  1602.   "  -o           save images to disk in old popi format",
  1603.   "  -p#          specify number of CPUs (if available)",
  1604.   "  -r[+-]       turn range checking on (off)",
  1605.   "  -s[+-]       turn signed I/O mode on (off)",
  1606.   "  -t[+-]       turn trig caching mode on (off)",
  1607.   "  -V           print version number",
  1608.   "  -v[+-]       turn verbose mode on (off)",
  1609.   "  -xWidth      specify image width (in pixels)",
  1610.   "  -yHeight     specify image height (in scanlines)",
  1611.   "  -zDepth      specify image depth (in levels)",
  1612.   (char *) 0
  1613. } ;
  1614.  
  1615.  
  1616. void
  1617. PrStrs(msg)
  1618. char *msg[] ;
  1619. {
  1620.   char **p ;
  1621.  
  1622.   for (p = msg; *p; ++p) FPRINTF(stderr, "%s\n", *p) ;
  1623. }
  1624.  
  1625.  
  1626. static void
  1627. Usage(status)
  1628. int status ;
  1629. {
  1630.   FPRINTF(stderr, "Usage: %s [options] [image-files]\n", ProgName) ;
  1631.   PrStrs(UsageMsg) ;
  1632.  
  1633. /* Also need a driver-specific usage message appended. */
  1634.  
  1635.   exit(status) ;
  1636. }
  1637.  
  1638.  
  1639. void
  1640. version()
  1641. {
  1642.   FPRINTF(stderr, "%s: version 3.1.%1d\n", ProgName, PATCHLEVEL) ;
  1643. }
  1644.  
  1645.  
  1646. static void
  1647. get_options(argc, argvp)           /* Read command line options. */
  1648. int argc ;
  1649. char **argvp[] ;
  1650. {
  1651.   char **argv ;
  1652.   char **new_argv ;
  1653.   char **nav ;
  1654.  
  1655.   argv = *argvp ;
  1656.   new_argv = (char **)
  1657.              LINT_CAST(Emalloc((unsigned) ((argc + 1) * sizeof (char *)))) ;
  1658.   nav = new_argv ;
  1659.   for (ProgName = *nav++ = *argv++; *argv && **argv == '-'; ++argv)
  1660.     {
  1661.       bool ArgRecognised ;
  1662.  
  1663.       ArgRecognised = TRUE ;
  1664.       switch (*++*argv)
  1665.         {
  1666.           case 'a' : if (*++*argv == '-')     /* Auto-display */
  1667.                        disp_active = 0 ;
  1668.                      else
  1669.                        disp_active = 1 ;
  1670.                      break ;
  1671.  
  1672.           case 'c' : if (*++*argv == '-')     /* RGB color mode */
  1673.                        colors = 1 ;
  1674.                      else
  1675.                        colors = 3 ;
  1676.                      break ;
  1677.  
  1678.           case 'D' : if (*++*argv)
  1679.                        {
  1680.                          if ((Debug = fopen(*argv, "w")) == NULL)
  1681.                            {
  1682.                              SPRINTF(ErrBuf,
  1683.                               "Can't open debug file '%s' - using stderr",
  1684.                               *argv) ;
  1685.                              error(ERR_SYS) ;
  1686.                              Debug = stderr ;
  1687.                            }
  1688.                        }    
  1689.                      else Debug = stderr ;
  1690.                      setbuf(Debug, (char *) NULL) ;    /**/
  1691.                      break ;
  1692.  
  1693.           case 'd' : ++argv ;                 /* X11 display information. */
  1694.                      if (*argv == NULL)
  1695.                        Usage(0) ;               /* Print usage message */
  1696.                        /*NOTREACHED*/
  1697.                      STRCPY(x11_display, *argv) ;
  1698.                      break ;
  1699.  
  1700.           case 'g' : ++argv ;                 /* X11 geometry information. */
  1701.                      if (*argv == NULL)
  1702.                        Usage(0) ;               /* Print usage message */
  1703.                        /*NOTREACHED*/
  1704.                      STRCPY(geometry, *argv) ;
  1705.                      break ;
  1706.  
  1707.           case 'i' : iconic = 1 ;             /* Start window iconically. */
  1708.                      break ;
  1709.  
  1710.           case 'l' : if (*++*argv)            /* Log all commands */
  1711.                        LogFile = *argv ;
  1712.                      OpenLog(&LogStr) ;
  1713.                      break ;
  1714.  
  1715.           case 'o' : oldfmt = 1 ;             /* Save images in old format. */
  1716.                      break ;
  1717.  
  1718.           case 'p' :                          /* No. cpus to use in parallel */
  1719.  
  1720.           /*  Still recognise the option on other machines,
  1721.        *  so scripts can use this option portably.
  1722.            */
  1723.  
  1724. #if       SEQPAR
  1725.                      if (*++*argv)
  1726.                        {
  1727.                          ncpus = atoi(*argv) ;
  1728.                          if (ncpus >= cpus_online()) ncpus = cpus_online() - 1 ;
  1729.                          if (ncpus < 0) ncpus = 0 ;
  1730.                        }
  1731.                      else ncpus = cpus_online() - 1 ;
  1732. #endif /* SEQPAR */
  1733.  
  1734.                      break ;
  1735.  
  1736.           case 'r' : if (*++*argv == '-')     /* Range checking */
  1737.                        RangeCheck = 0 ;
  1738.                      else
  1739.                        RangeCheck = 1 ;
  1740.                      break ;
  1741.  
  1742.           case 's' : if (*++*argv == '-')     /* Signed I/O mode */
  1743.                        signed_io = 0 ;
  1744.                      else
  1745.                        signed_io = 1 ;
  1746.                      break ;
  1747.  
  1748.           case 't' : if (*++*argv == '-')     /* Trig caching mode */
  1749.                        tcache = 0 ;
  1750.                      else
  1751.                        tcache = 1 ;
  1752.                      break ;
  1753.  
  1754.           case 'V' : version() ;              /* Print version number. */
  1755.                      exit(0) ;
  1756.                      /*NOTREACHED*/
  1757.  
  1758.           case 'v' : if (*++*argv == '-')     /* Verbose */
  1759.                        Verbose = 0 ;
  1760.                      else
  1761.                        ++Verbose ;
  1762.                      break ;
  1763.  
  1764.           case 'x' : Xsize = atoi(++*argv) ;
  1765.                      break ;
  1766.  
  1767.           case 'y' : Ysize = atoi(++*argv) ;
  1768.                      break ;
  1769.  
  1770.           case 'z' : Zsize = atoi(++*argv) ;
  1771.                      Zmax = (pixel_t) (Zsize - 1) ;
  1772.                      break ;
  1773.  
  1774.           case '?' : Usage(0) ;               /* Print usage message */
  1775.                      /*NOTREACHED*/
  1776.  
  1777. /*  Note: no error on default because drivers may interpret other options.
  1778.  *  It's up to them to give an error message if they can.
  1779.  */
  1780.  
  1781.           default  : ArgRecognised = FALSE ;
  1782.         }
  1783.  
  1784.       if (!ArgRecognised) *nav++ = *argv ;
  1785.     }
  1786.   *nav = (char *) 0 ;
  1787.  
  1788.   CurOld = &Images[0] ;
  1789.   CurNew = &Images[1] ;
  1790.   CurOld->pix = ImgAlloc() ;
  1791.   CurOld->str = "old" ;
  1792.   CurNew->pix = ImgAlloc() ;
  1793.   CurNew->str = "new" ;
  1794.  
  1795.   for (; *argv; ++argv) getpix(*argv, (char *) 0) ;
  1796. }
  1797.  
  1798.  
  1799. /*  We deliberately don't exit on error here.
  1800.  *  The user may have some picture that has taken ages to develop.
  1801.  *  If we run out of memory, they have a chance to save the
  1802.  *  image and exit themselves, which they should do as soon
  1803.  *  as possible.
  1804.  */
  1805.  
  1806. char *
  1807. Emalloc(n)
  1808. unsigned int n ;
  1809. {
  1810.   char *try ;
  1811.   static unsigned long TotalAllocated = 0L ;
  1812.  
  1813.   if ((try = malloc(n)) == NULL)
  1814.     {
  1815.       SPRINTF(ErrBuf,
  1816.               "Allocate %u bytes failed (total malloc=%ld",
  1817.               n, TotalAllocated) ;
  1818.       error(ERR_SYS) ;
  1819.     }
  1820.   TotalAllocated += n ;
  1821.   return(try) ;
  1822. }
  1823.  
  1824.  
  1825. void
  1826. Quit()
  1827. {
  1828.   disp_finish() ;
  1829.   exit(0) ;
  1830. }
  1831.  
  1832.  
  1833. main(argc, argv)
  1834. int argc ;
  1835. char **argv ;
  1836. {
  1837.   get_options(argc, &argv) ;          /* read the command line options. */
  1838.   TXsize = Xsize ;
  1839.   if (TXsize < TWIDTH) TXsize = TWIDTH ;
  1840.   TYsize = Ysize+100 ;
  1841.   BOXW   = TXsize-50 ;
  1842.  
  1843.   disp_init(argc, argv) ;
  1844.  
  1845. #if       SEQPAR
  1846.   m_set_procs(ncpus) ;
  1847. #endif /* SEQPAR */
  1848.  
  1849.   parse((FILE *) 0) ;
  1850.   Quit() ;
  1851.  
  1852.   return 0 ;         /* Shut up warning messages from some compilers */
  1853. /*NOTREACHED*/
  1854. }
  1855. Funky_Stuff
  1856. len=`wc -c < main.c`
  1857. if [ $len !=     9932 ] ; then
  1858. echo error: main.c was $len bytes long, should have been     9932
  1859. fi
  1860. fi # end of overwriting check
  1861. if [ -f polar.c ]
  1862. then
  1863. echo shar: will not over-write existing file polar.c
  1864. else
  1865. echo shar: extracting 'polar.c',     3529 characters
  1866. cat > polar.c <<'Funky_Stuff'
  1867.  
  1868. /*  @(#)polar.c 1.4 91/08/20
  1869.  *
  1870.  *  Polar coordinate handling routines used by the popi program.
  1871.  *
  1872.  *  Popi was originally written by Gerard J. Holzmann - AT&T Bell Labs.
  1873.  *  This version is based on the code in his Prentice Hall book,
  1874.  *  "Beyond Photography - the digital darkroom," ISBN 0-13-074410-7,
  1875.  *  which is copyright (c) 1988 by Bell Telephone Laboratories, Inc. 
  1876.  *
  1877.  *  Permission is given to distribute these extensions, as long as these
  1878.  *  introductory messages are not removed, and no monies are exchanged.
  1879.  *
  1880.  *  No responsibility is taken for any errors or inaccuracies inherent
  1881.  *  either to the comments or the code of this program, but if reported
  1882.  *  (see README file) then an attempt will be made to fix them.
  1883.  */
  1884.  
  1885. #include <fcntl.h>
  1886. #include <stdio.h>
  1887. #include "popi.h"
  1888.  
  1889. short *avals = 0 ;
  1890. short *rvals = 0 ;
  1891.  
  1892. #ifdef AMIGA
  1893. double
  1894. hypot(x, y)
  1895. double x, y;
  1896. {
  1897.   return(sqrt(x*x + y*y)) ;
  1898. }
  1899. #endif  /* AMIGA */
  1900.  
  1901. extern int tcache ;
  1902.  
  1903. void
  1904. MakePolar()
  1905. {
  1906.   char path[30] ;
  1907.   short *ap ;     /* Pointer to angle array */
  1908.   short *rp ;     /* Pointer into radius array */
  1909.   short *a1 ;     /* Tmp pointer to angle array */
  1910.   short *r1 ;     /* Tmp pointer to radius array */
  1911.   int fd ;
  1912.   int n ;
  1913.   int pct ;
  1914.   int pctl ;
  1915.   int size ;
  1916.   int x ;
  1917.   int y ;
  1918.   int xmin ;
  1919.   int xmax ;
  1920.   int ymin ;
  1921.   int ymax ;
  1922.   double xd;
  1923.   double yd;
  1924.  
  1925.   if (avals) return ;    /* Previously calculated */
  1926.  
  1927.   size  = Xsize * Ysize * sizeof(short) ;
  1928.   avals = (short *) LINT_CAST(Emalloc((unsigned) size)) ;
  1929.   rvals = (short *) LINT_CAST(Emalloc((unsigned) size)) ;
  1930.  
  1931.   if (tcache)
  1932.     {
  1933.       sprintf(path, "/usr/tmp/popi.%d.%d", Xsize, Ysize) ;
  1934.       if ((fd=open(path, O_RDONLY)) != -1)
  1935.         {
  1936.           n  = read(fd, avals, size) ;
  1937.           n += read(fd, rvals, size) ;
  1938.           close(fd) ;
  1939.           if (n == 2*size) return ;
  1940.         }
  1941.       /* else perror("polar open (read) error") ;    */
  1942.     }
  1943.  
  1944.   ymax =  Ysize / 2 ;
  1945.   ymin = -(Ysize - 1) / 2 ;
  1946.   xmin = -Xsize / 2 ;
  1947.   xmax =  (Xsize - 1) / 2 ;
  1948.  
  1949.   rp = rvals ;
  1950.   ap = avals ;
  1951.  
  1952.   FPRINTF(stderr, "Calculating trig tables\n") ;
  1953.   FFLUSH(stderr) ;
  1954.  
  1955.   /*        +y
  1956.    *         ^
  1957.    *       2 | 1
  1958.    * -x <----+----> +x
  1959.    *       3 | 4
  1960.    *         v
  1961.    *        -y
  1962.    */
  1963.  
  1964.   pctl = -1 ;
  1965.   for (y = ymax; y >= 0; --y)
  1966.     {
  1967.       pct = ((ymax-y) * 100) / ymax ;
  1968.       if (pct != pctl)
  1969.         disp_percentdone(pctl=pct) ;
  1970.       yd = y;
  1971.  
  1972. /* Quadrant 2 */
  1973.  
  1974.       for (x = xmin; x < 0; ++x)
  1975.         {
  1976.           xd = x;
  1977.           *ap++ = (short) (RtoD(atan2(yd, xd)) + 0.5) ;
  1978.           *rp++ = (short) hypot(yd, xd) ;
  1979.         }
  1980.       *ap++ = (y == 0) ? 0 : (short) (RtoD(atan2(yd, xd)) + 0.5) ;
  1981.       *rp++ = (y == 0) ? 0 : (short) hypot(yd, xd) ;
  1982.       ++x ;
  1983.  
  1984. /* Remember location just before the 0 value */
  1985.  
  1986.       r1 = rp - 2 ;
  1987.       a1 = ap - 2 ;
  1988.  
  1989. /* Quadrant 1 */
  1990.  
  1991.       for ( ; x <= xmax; ++x)
  1992.         {
  1993.           *ap++ = 180 - *a1-- ;
  1994.           *rp++ =       *r1-- ;
  1995.         }
  1996.     }
  1997.  
  1998.  
  1999. /* Quadrant 3, 4 */
  2000.  
  2001.   r1 = rp - Xsize - 1 ;
  2002.   a1 = ap - Xsize - 1 ;
  2003.   for ( ; y >= ymin; --y)
  2004.     {
  2005.  
  2006.       for (x = xmin; x <= xmax; ++x)
  2007.         {
  2008.           *rp++ = *r1--       ;
  2009.           *ap++ = *a1-- + 180 ;
  2010.         }
  2011.     }
  2012.   disp_percentdone(100) ;      /* Can rely on '100' to terminate */
  2013.  
  2014.   if (tcache)
  2015.     {
  2016.       if ((fd=open(path, O_WRONLY|O_CREAT, 0777)) != -1)
  2017.         {
  2018.           n  = write(fd, avals, size) ;
  2019.           n += write(fd, rvals, size) ;
  2020.           close(fd) ;
  2021.           if (n == 2*size) return ;
  2022.         }
  2023.       else perror("polar open (write) error") ;
  2024.     }
  2025. }
  2026. Funky_Stuff
  2027. len=`wc -c < polar.c`
  2028. if [ $len !=     3529 ] ; then
  2029. echo error: polar.c was $len bytes long, should have been     3529
  2030. fi
  2031. fi # end of overwriting check
  2032. exit 0 # Just in case...
  2033.