home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / rot / rot.c < prev   
Encoding:
C/C++ Source or Header  |  1991-05-19  |  10.4 KB  |  529 lines

  1. /*
  2.  * Revision History:
  3.  *
  4.  * Original source from:
  5.  *  Peter da Silva (ihnp4!shell!neuro1!{hyd-ptd,datafact,baylor}!peter)
  6.  *
  7.  * Changes for padding added by:
  8.  *  Andrew Scott Beals ({ucbvax,decwrl}!amdcad!bandy or bandy@amdcad.amd.com)
  9.  *  20 April 1987
  10.  *
  11.  * Additional changes for padding, fix for computation of tglen,
  12.  * increase max lines, improve termlib handling, add System V #ifdefs.
  13.  *  Bill Randle (billr@tekred.TEK.COM)
  14.  *  21 April 1987
  15.  *
  16.  * Some long-standing 8-bit bugs fixed, and more randomness added.
  17.  *  Peter da Silva <peter@sugar.hackercorp.com> Dec 1 1989.
  18.  *
  19.  * ((char *)0) de-referencing removed. [Caused SEGV core dumps on Sun-3's]
  20.  *  Andrew Scott Beals <bandy@toad.com> 7 May 1990
  21.  *
  22.  * "PG" emulation added Dec '90 by Peter da Silva, in a fit of boredom.
  23.  * Now "rot" acts like a pager, only dumping the screen if you wait too long.
  24.  */
  25.  
  26. #include <stdio.h>
  27.  
  28. #ifdef SYSV
  29. # include <termio.h>
  30. #else
  31. # include <sgtty.h>
  32. #endif
  33.  
  34. #include <signal.h>
  35.  
  36. /*        -- Miscellaneous defines --                     */
  37. #define FALSE 0
  38. #define TRUE 1
  39. #define MAXCOL 80
  40. #define MAXLI 34
  41. #define SLEEPFACTOR 2    /* Assumed reading speed, lines per second */
  42. #define COLRATIO 8    /* For delays, amount to discount columns by */
  43.  
  44. extern char *tgetstr();
  45.  
  46. int lastx, lasty;
  47. struct _c {
  48.     struct _c *c_next;
  49.     int c_line, c_column;
  50.     char c_mark;
  51. } *clist;
  52.  
  53. /*        -- Global variables --                         */
  54. char *tent;                                               /* Pointer to tbuf */
  55. extern char PC;                                             /* Pad character */
  56. extern char *UP, *BC;                         /* Upline, backsapce character */
  57. extern short ospeed;                                /* Terminal output speed */
  58. int tglen;
  59.  
  60. char *cm,                                                   /* Cursor motion */
  61.      *cl,                                                    /* Clear screen */
  62.      *ti,                            /* Init terminal */
  63.      *te;                           /* Reset terminal */
  64. int  li,                                                  /* lines on screen */
  65.      co;                                                    /* columns ditto */
  66. char screen[MAXLI+1][MAXCOL];
  67. char newscreen[MAXLI+1][MAXCOL];
  68. char *me;                             /* program name */
  69.  
  70. /* Options */
  71. int packflag = 0;
  72.  
  73. main(ac, av)
  74. int ac;
  75. char **av;
  76. {
  77.     /* set ospeed so padding works correctly */
  78. #ifdef SYSV
  79.     struct termio    p;
  80.  
  81.     if(ioctl(1, TCGETA, &p) != -1)
  82.         ospeed=p.c_cflag & CBAUD;
  83. #else
  84.     struct sgttyb    p;
  85.  
  86.     if(ioctl(1, TIOCGETP, &p) != -1)
  87.         ospeed=p.sg_ospeed;
  88. #endif
  89.  
  90.     me = *av;
  91.  
  92.     srand(getpid());
  93.     tinit(getenv("TERM"));
  94.     while(ac > 1 && av[1][0]=='-') {
  95.         while(av[1][1]) {
  96.             switch(av[1][1]) {
  97.                 case 'p': packflag=1; break;
  98.                 default: fprintf(stderr, "%s [-p] [file]...\n", me);
  99.             }
  100.             av[1]++;
  101.         }
  102.         av++;
  103.         ac--;
  104.     }
  105.     if(ac > 1)
  106.         while(*++av)
  107.             dropf(*av);
  108.     else
  109.         fdropf(stdin);
  110.     tend();
  111. }
  112.  
  113. at(x, y, c)
  114. int x, y;
  115. char c;
  116. {
  117. #ifdef DEBUG
  118.     _at(x, y);
  119. #else
  120.     if(y==lasty) {
  121.         if(x!=lastx) {
  122.             if(x<lastx && lastx-x<tglen)
  123.                 while(x<lastx) {
  124.                     putchar('\b');
  125.                     lastx--;
  126.                 }
  127.             else if(x>lastx && x-lastx<tglen)
  128.                 while(x>lastx) {
  129.                     putchar(0x7F&newscreen[lasty][lastx]);
  130.                     lastx++;
  131.                 }
  132.             else
  133.                 _at(x, y);
  134.         }
  135.     } else
  136.         _at(x, y);
  137. #endif
  138.     c &= 0x7F;
  139.     putchar(c);
  140.     if(c >= ' ' && c != '\177')
  141.         lastx++;
  142.     if(lastx>=co) {
  143.         lastx -= co;
  144.         lasty++;
  145.     }
  146. }
  147.  
  148. _at(x, y)
  149. int x, y;
  150. {
  151.     extern void    outc();
  152.  
  153.     tputs(tgoto(cm, x, y), 1, outc);     /* handle padding */
  154.     lastx = x;
  155.     lasty = y;
  156. }
  157.  
  158. void
  159. outc(c)
  160. register c;
  161. {
  162.     putc(c&0x7F, stdout);
  163. }
  164.  
  165. tinit(name)
  166. char *name;
  167. {
  168.     static char junkbuf[1024], *junkptr;
  169.     char tbuf[1024];
  170.     int  intr();
  171.  
  172.     junkptr = junkbuf;
  173.  
  174.     tgetent(tbuf, name);
  175.  
  176.     if (!tgetflag("bs"))        /* is backspace not used? */
  177.         BC = tgetstr("bc",&junkptr);    /* find out what is */
  178.     else
  179.         BC = "\b";        /* make a backspace handy */
  180.     if (tgetstr("pc", &junkptr) != NULL)
  181.         PC = *junkptr;  /* set pad character */
  182.     else
  183.         PC = '\0';
  184.     UP = tgetstr("up", &junkptr);
  185.     cm = tgetstr("cm", &junkptr);
  186.     if (cm == NULL) {
  187.         printf("Can't rot on dumb terminals.\n");
  188.         exit(1);
  189.     }
  190.     cl = tgetstr("cl", &junkptr);
  191.     ti = tgetstr("ti", &junkptr);
  192.     te = tgetstr("te", &junkptr);
  193.     li = min(tgetnum("li"), MAXLI);
  194.     if (li == -1)
  195.         li = 24;
  196.     co = min(tgetnum("co"), MAXCOL);
  197.     if (co == -1)
  198.         co = 80;
  199.     tglen = strlen(tgoto(cm, co-1, li-1));
  200. }
  201.  
  202. tend()
  203. {
  204.     if(te != NULL) outs(te);
  205.     _at(0, li-1);
  206.     putchar('\n');
  207.     fflush(stdout);
  208. }
  209.  
  210. readscreen(fp)
  211. FILE *fp;
  212. {
  213.     int line, column, p;
  214.     char tmp[256];
  215.  
  216.     for(line=0; line<li; line++)
  217.         for(column=0; column<co; column++)
  218.             {
  219.             newscreen[line][column] = screen[line][column] = ' ';
  220.             }
  221.     strncpy(&newscreen[li-1][0], "--Hit CR--", 10);
  222.     for(column=0; column<co; column++)
  223.         newscreen[li][column] = screen[li][column] = '*';
  224.     line=0;
  225.     while(line<li-1) {
  226.         if(!fgets(tmp, 256, fp))
  227.             return(max(line,column/COLRATIO));
  228.  
  229.         for(column=0, p=0; tmp[p]; p++) {
  230.             tmp[p] &= ~0200;
  231.             if(tmp[p] < ' ' || tmp[p] == 127)
  232.                 switch(tmp[p]) {
  233.                     case '\t':
  234.                         while(++column % 8)
  235.                             continue;
  236.                         break;
  237.                     case '\n':
  238.                         column = 0;
  239.                         line++;
  240.                         break;
  241.                     default:
  242.                         newscreen[line][column] = '^';
  243.                         column++;
  244.                         if(column>=co) {
  245.                             column -= co;
  246.                             line++;
  247.                         }
  248.                         newscreen[line][column] =
  249.                             (tmp[p]+'@') & 127;
  250.                         column++;
  251.                         break;
  252.                 }
  253.             else {
  254.                 newscreen[line][column] = tmp[p];
  255.                 column++;
  256.             }
  257.             if(column >= co) {
  258.                 column -= co;
  259.                 line++;
  260.             }
  261.             if(line >= li)
  262.                 break;
  263.         }
  264.     }
  265.     for(column=0; column<co; column++)
  266.         newscreen[li][column] = screen[li][column] = '*';
  267.     return(max(line,column/COLRATIO));
  268. }
  269.  
  270. drawscreen()
  271. {
  272.     lastx = lasty = 0;
  273.     outs(cl);
  274.     update();
  275. }
  276.  
  277. update() /* copy new screen back to old screen */
  278. {
  279.     int l, c;
  280.  
  281.     for(l=0; l<li; l++)
  282.         for(c=0; c<co; c++)
  283.             if(screen[l][c] != newscreen[l][c]) {
  284.                 if((screen[l][c] & ~0200) !=
  285.                    (newscreen[l][c] & ~0200))
  286.                     at(c, l, newscreen[l][c]);
  287.                 screen[l][c] = newscreen[l][c];
  288.             }
  289. }
  290.  
  291. drop(line, column)
  292. int line, column;
  293. {
  294.     struct _c *hold, *temp;
  295.  
  296.     if(line<0 || line>=li || column<0 || column>=co ||
  297.        (line>=li-2 && column >= co-1) || /* scroll potential */
  298.        screen[line][column]==' ' || /* empty */
  299.        screen[line][column] & 0200) /* already in list */
  300.         return;
  301.     if(screen[line+1][column]!=' ' &&
  302.        (column==co-1 ||screen[line+1][column+1]!=' ') &&
  303.        (column==0 ||screen[line+1][column-1]!=' '))
  304.         return;
  305.  
  306.     hold = (struct _c *) malloc(sizeof(struct _c));
  307.     hold -> c_next;
  308.     hold -> c_column = column;
  309.     hold -> c_line = line;
  310.     hold -> c_mark = 0;
  311.     screen[line][column] |= 0200;
  312.  
  313.     for(temp = clist; temp && temp->c_next; temp=temp->c_next)
  314.         if(!(rand()&1111))
  315.             break;
  316.     if(temp) {
  317.         hold->c_next = temp->c_next;
  318.         temp->c_next = hold;
  319.     } else {
  320.         hold->c_next = clist;
  321.         clist = hold;
  322.     }
  323. }
  324.  
  325. drops()
  326. {
  327.     int l, c;
  328.     struct _c *hold;
  329.     for(hold = clist; hold; hold=hold->c_next) {
  330.         int line = hold->c_line, column=hold->c_column;
  331.         if(line>= li-2 && column>=co-1) {
  332.             newscreen[line][column] &= ~0200;
  333.             screen[line][column] &= ~0200;
  334.             hold->c_mark = 1;
  335.             continue;
  336.         }
  337.         if(newscreen[line+1][column+1] == ' ' &&
  338.            newscreen[line+1][column-1] == ' ')
  339.             drop(line+1, column);
  340.         drop(line, column+1);
  341.         drop(line-1, column);
  342.         drop(line, column-1);
  343.         if(newscreen[line+1][column]==' ' ||
  344.            (packflag &&
  345.             newscreen[line+1][column]==(screen[line][column]&~0200)
  346.            )
  347.           ) {
  348.             newscreen[line+1][column] = screen[line][column];
  349.             newscreen[line][column] = ' ';
  350.             line++;
  351.         } else if(rand()&01000) {
  352.             if(column>0 && newscreen[line][column-1] == ' ' &&
  353.                 newscreen[line+1][column-1]==' ') {
  354.                 newscreen[line][column-1] =
  355.                     screen[line][column];
  356.                 newscreen[line][column] = ' ';
  357.                 column--;
  358.             }
  359.             else if(column<co-1 &&
  360.                 newscreen[line][column+1] == ' ' &&
  361.                 newscreen[line+1][column+1]==' ') {
  362.                     newscreen[line][column+1] =
  363.                         screen[line][column];
  364.                     newscreen[line][column] = ' ';
  365.                     column++;
  366.             }
  367.             else {
  368.                 screen[line][column] &= ~0200;
  369.                 newscreen[line][column] &= ~0200;
  370.                 hold -> c_mark = 1;
  371.             }
  372.         } else {
  373.             if(column<co-1 && newscreen[line][column+1] == ' ' &&
  374.                 newscreen[line+1][column+1]==' ') {
  375.                 newscreen[line][column+1] =
  376.                     screen[line][column];
  377.                 newscreen[line][column] = ' ';
  378.                 column++;
  379.             }
  380.             else if(column>0 && newscreen[line][column-1] == ' ' &&
  381.                 newscreen[line+1][column-1]==' ') {
  382.                 newscreen[line][column-1] =
  383.                     screen[line][column];
  384.                 newscreen[line][column] = ' ';
  385.                 column--;
  386.             }
  387.             else {
  388.                 newscreen[line][column] &= ~0200;
  389.                 screen[line][column] &= ~0200;
  390.                 hold -> c_mark = 1;
  391.             }
  392.         }
  393.         hold -> c_column = column;
  394.         hold -> c_line = line;
  395.         fflush(stdout);
  396.     }
  397.  
  398.     while(clist && clist->c_mark) {
  399.         struct _c *p = clist;
  400.         clist = clist -> c_next;
  401.         free(p);
  402.     }
  403.     hold = clist;
  404.     while(hold && hold->c_next)
  405.         if(hold->c_next->c_mark) {
  406.             struct _c *p = hold->c_next;
  407.             hold->c_next = p->c_next;
  408.             free(p);
  409.         } else
  410.             hold=hold->c_next;
  411. }
  412.  
  413. droplet(line, column)
  414. int line, column;
  415. {
  416.     int ret;
  417.     if(line==li-1)
  418.         return 0;
  419.     while(column>=0 &&
  420.           screen[line][column]!=' ' &&
  421.           screen[line+1][column]==' ')
  422.         column--;
  423.     column++;
  424.     while(column<co &&
  425.           screen[line][column]!=' ' &&
  426.           screen[line+1][column]==' ')
  427.         drop(line, column++);
  428.     ret = clist != 0;
  429.     while(clist) {
  430.         drops();
  431.         update();
  432.     }
  433.     return ret;
  434. }
  435.  
  436. dropscreen()
  437. {
  438.     int column, line;
  439.     int rubbish = 0, count = 0;
  440.  
  441.     do {
  442.         int start, limit, incr;
  443.         count++;
  444.         rubbish = 0;
  445.         if(count&1) { start=li-2; limit=0; incr = -1; }
  446.         else { start=0; limit=li-2; incr=1; }
  447.         for(line=start; line!=limit && !rubbish; line+=incr) {
  448.             if(line&1)
  449.                 for(column=0; column<co && !rubbish; column++)
  450.                     rubbish += droplet(line, column);
  451.             else
  452.                 for(column=co-1; column>=0 && !rubbish; column--)
  453.                     rubbish += droplet(line, column);
  454.         }
  455.     } while(rubbish);
  456. }
  457.  
  458. dropf(file)
  459. char *file;
  460. {
  461.     FILE *fp;
  462.  
  463.     if(!(fp = fopen(file, "r"))) {
  464.         perror(file);
  465.         return -1;
  466.     }
  467.     fdropf(fp);
  468. }
  469.  
  470. fdropf(fp)
  471. FILE *fp;
  472. {
  473.     int i,lines;
  474.  
  475.     while(!feof(fp)) {
  476.         lines=readscreen(fp);
  477.         drawscreen();
  478.         fflush(stdout);
  479.         if(more(lines) == 0) { /* Timed out */
  480.             for(i=0; i<20; i++)
  481.                 droplet((rand()>>4) % (li-1), (rand()>>4) % co);
  482.             dropscreen();
  483.         }
  484.     }
  485. }
  486.  
  487. char timed_out;
  488.  
  489. int tmo()
  490. {
  491.     timed_out = 1;
  492. }
  493.  
  494. more(lines)
  495. int lines;
  496. {
  497.     char c;
  498.  
  499.     timed_out = 0;
  500.     signal(SIGALRM, tmo);
  501.     alarm(max(lines/SLEEPFACTOR,1));
  502.     while(!timed_out) {
  503.         read(0, &c, 1);
  504.         if(c=='\n' || c=='\r') break;
  505.     }
  506.     alarm(0);
  507.     return !timed_out;
  508. }
  509.  
  510. outs(s)
  511. char *s;
  512. {
  513.     fputs(s, stdout);
  514. }
  515.  
  516. min(a, b)
  517. int a, b;
  518. {
  519.     if(a<b) return a;
  520.     return b;
  521. }
  522.  
  523. max(a, b)
  524. int a, b;
  525. {
  526.     if(a>b) return a;
  527.     return b;
  528. }
  529.