1 /*
2    TERMatrix 0.2
3    Copyright 2006 Flavio Chierichetti
4    Licence GPL 2
5 */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12 #include <signal.h>
13 #include <fcntl.h>
14 #include <termios.h>
15 #include <sys/time.h>
16 #include <sys/ioctl.h>
17 
18 #define TERMINAL_DEVICE "/dev/tty"
19 
20 #define min(x, y) ((x) < (y) ? (x) : (y))
21 
22 #define termCursorOff() printf("\x1b[?25l");
23 #define termMoveTo(r, c) printf("\x1b[%d;%dH", r + 1, c + 1)
24 #define termSetAttr(fore, back, attr) printf("\x1b[%d;%d;%dm", attr, fore + 30, back + 40)
25 #define termPutChar(c) printf("%c", c)
26 #define termErase() printf("\x1b[2J")
27 #define termReset() printf("\x1b%c", 'c')
28 
29 typedef struct s {
30   int start, end, n, speed, counter;
31   char last;
32   struct s *next;
33 } seq;
34 
35 enum { usecDelay = 8000, speedMin = 3 , speedMax = 8 , darkProb = 75 , newSeqProb = 20 , letterChangeProb = 25 };
36 
37 enum { black = 0, red, green, yellow, blue, magenta, cyan, white };
38 enum { normalAttr = 1 , boldAttr = 22 };
39 
40 void initTerm(int signum);
41 void initSigActions();
42 void print(int signum);
43 void end(int signum);
44 
45 char *V = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz<>()[]{}.,:;!@#$%^&*-_=+|?/`~'\"\\";
46 int Length, R, C;
47 seq **S;
48 
49 char *quotes[] = {
50   "Wake up, Neo.",
51   "There is no spoon.",
52   "Follow the white rabbit.",
53   "What is the matrix?",
54   "Welcome to the real world.",
55   "Don't think you are. Know you are.",
56   "It is inevitable.",
57   "Only human.",
58   "Deja vu...",
59   NULL
60 };
61 
main()62 int main() {
63   initTerm(0);
64 
65   srand(time(NULL) % RAND_MAX);
66 
67   Length = strlen(V);
68 
69   initSigActions();
70 
71   while (1)
72     pause();
73 
74   return 0;
75 }
76 
initTerm(int signum)77 void initTerm(int signum) {
78   int fd;
79   struct winsize ws;
80   int i;
81 
82   if ( (fd = open(TERMINAL_DEVICE, O_RDWR)) == -1 )
83     exit(1);
84 
85   if ( ioctl(fd, TIOCGWINSZ, &ws) != 0 )
86     exit(1);
87 
88   close(fd);
89 
90   R = ws.ws_row;
91   C = ws.ws_col;
92 
93   /* If this function is called more than once, there would be a little memory leak here */
94 
95   S = (seq**) calloc (C, sizeof(seq*));
96 
97   for ( i = 0 ; i < C ; i++ )
98     S[i] = NULL;
99 
100   termCursorOff();
101   termSetAttr(green, black, normalAttr);
102   termErase();
103 }
104 
initSigActions()105 void initSigActions() {
106   struct sigaction sigintAction, sigalrmAction, sigwinchAction;
107   struct itimerval timer;
108 
109   sigfillset(&sigwinchAction.sa_mask);
110   sigwinchAction.sa_flags = 0;
111   sigwinchAction.sa_handler = initTerm;
112   sigaction(SIGWINCH, &sigwinchAction, NULL);
113 
114   sigfillset(&sigalrmAction.sa_mask);
115   sigalrmAction.sa_flags = 0;
116   sigalrmAction.sa_handler = print;
117   sigaction(SIGALRM, &sigalrmAction, NULL);
118 
119   sigfillset(&sigintAction.sa_mask);
120   sigintAction.sa_flags = 0;
121   sigintAction.sa_handler = end;
122   sigaction(SIGINT, &sigintAction, NULL);
123 
124   timer.it_interval.tv_sec = timer.it_value.tv_sec = 0;
125   timer.it_interval.tv_usec = timer.it_value.tv_usec = usecDelay;
126   setitimer(ITIMER_REAL, &timer, NULL);
127 }
128 
print(int signum)129 void print(int signum) {
130   int c, r;
131 
132   for ( c = 0 ; c < C ; c++ )
133     if ( S[c] ) {
134       S[c]->counter = (S[c]->counter + 1) % S[c]->speed;
135       if ( S[c]->counter == 0 ) {
136 	for ( r = S[c]->start ; r < min(R, S[c]->end) ; r++ )
137 	  if ( rand() % 100 < letterChangeProb || r == S[c]->end - 1 ) {
138 	    if ( rand() % 100 < darkProb )
139 	      termSetAttr(green, black, boldAttr);
140 	    else
141 	      termSetAttr(green, black, normalAttr);
142 
143 	    termMoveTo(r, c);
144 	    termPutChar(V[rand() % Length]);
145 	  }
146 
147 	if ( S[c]->end == R )
148 	  S[c]->end++;
149 
150 	if ( S[c]->n == 0 ) {
151 	  termMoveTo(S[c]->start, c);
152 	  termPutChar(' ');
153 
154 	  S[c]->start++;
155 	}
156 
157 	if ( S[c]->end < R ) {
158 	  S[c]->last = V[rand() % Length];
159 
160 	  termSetAttr(white, black, normalAttr);
161 	  termMoveTo(S[c]->end, c);
162 	  termPutChar(S[c]->last);
163 
164 	  S[c]->end++;
165 	}
166 
167 	if ( S[c]->n > 0 )
168 	  S[c]->n--;
169 
170 	if ( S[c]->start == S[c]->end ) {
171 	  free(S[c]);
172 	  S[c] = NULL;
173 	}
174       }
175     } else
176       if ( rand() % 100 < newSeqProb ) {
177 	S[c] = (seq*) malloc ( sizeof(seq) );
178 
179 	S[c]->start = 0;
180 	S[c]->end = 0;
181 	S[c]->speed = rand() % (speedMax - speedMin + 1) + speedMin;
182 	S[c]->counter = 0;
183 	S[c]->n = rand() % R + 1;
184 
185 	S[c]->last = 0;
186       }
187 
188   fflush(stdout);
189 }
190 
end(int signum)191 void end(int signum) {
192   int i;
193 
194   termReset();
195 
196   for ( i = 0 ; quotes[i] != NULL ; i++ );
197   i = rand() % i;
198 
199   printf("%s\n", quotes[i]);
200 
201   exit(0);
202 }
203