1 /*
2 * npc.c -- animation counter main routine
3 *
4 * Copyright (c) 1995-1997 by nir@mxa.meshnet.or.jp
5 *
6 * This file is part of npc.cgi source tree.
7 * npc.cgi is free software; you can redistribute it and/or modify it
8 * for any purpose.
9 *
10 * @(#)$Id: npc.c,v 2.9 1997/12/11 14:07:34 nir Rel $
11 */
12
13 /*
14 * $Log: npc.c,v $
15 * Revision 2.9 1997/12/11 14:07:34 nir
16 * Add left, top and disposal_method elements to struct IMAGE.
17 * In the GIF animation mode, only the rewriting digit(s) is output.
18 *
19 * Revision 2.8 1997/11/10 16:19:05 nir
20 * Modify error_out() message.
21 *
22 * Revision 2.7 1997/11/06 19:51:52 nir
23 * Add MODE initialization.
24 *
25 * Revision 2.6 1997/11/05 12:09:15 nir
26 * Add Copyright, Id and Log.
27 * Change animation mode default from server push to 89aGIF animation.
28 *
29 */
30
31 #include "npc.h"
32
33 INTERN void initialize(void);
34 INTERN void select_num(void);
35 INTERN void set_num(void);
36 INTERN void arg2num(char *str);
37 INTERN void number_out(DIGITS *digits, int increment);
38 INTERN void gif_animation_out(DIGITS *digits, int width);
39 INTERN void server_push_out(DIGITS *digits, int width);
40 INTERN void static_set(DIGITS *digits, int width, int add_lines);
41 INTERN void msleep(int msec);
42 INTERN void set_image(int row, int top);
43 INTERN void global_save(void);
44 INTERN void local_save(void);
45 INTERN void header_save(void);
46 INTERN void logical_screen_save(void);
47 INTERN void global_palette_save(void);
48 INTERN void graphic_control_extension_save(void);
49 INTERN void image_descriptor_save(void);
50 INTERN void image_data_save(void);
51 INTERN void scale_out(unsigned int line);
52 INTERN void trailer_save(void);
53
54 GLOBAL IMAGE image;
55 GLOBAL IMAGE numbers;
56 GLOBAL GCONTROL gcontrol;
57 GLOBAL ENV env;
58
59
main(int argc,char ** argv)60 int main(int argc, char **argv) {
61 FILE *index_file;
62
63 initialize();
64 get_environ(argc, argv);
65 index_file = open_index();
66 get_config(index_file);
67 if (gcontrol.restriction > 1)
68 error_out("No Permission To Use This Counter");
69 get_param();
70 update_count(index_file);
71 fclose(index_file);
72 select_num();
73 set_num();
74 return(0);
75 }
76
77
initialize(void)78 INTERN void initialize(void) {
79 env.index_dir = INDEX_DIR;
80 env.index = INDEX_FILE;
81 gcontrol.random = NO;
82 gcontrol.progress = NO;
83 gcontrol.gif_animation = YES;
84 gcontrol.width = DEFAULT_WIDTH;
85 gcontrol.unit = 0;
86 gcontrol.offset = 0;
87 gcontrol.number = BAD;
88 gcontrol.increment = 1;
89 gcontrol.restriction = 0;
90 gcontrol.mode = 0;
91 gcontrol.digits = 0;
92 gcontrol.initial = 1;
93 gcontrol.transparent = BAD;
94 gcontrol.delay[0] = gcontrol.delay[1] = 0;
95 gcontrol.color[0] = gcontrol.color[1] = (long)BAD;
96 gcontrol.location = NULL;
97 srand(time(NULL));
98 #if defined(_WIN32)
99 _setmode(fileno(stdout), _O_BINARY);
100 #endif
101 }
102
103
select_num(void)104 INTERN void select_num(void) {
105 unsigned char color[2][3];
106 unsigned char *p;
107 int i, j, n;
108 long l;
109
110 memcpy(&numbers, get_digits(gcontrol.digits), sizeof(IMAGE));
111 if ((gcontrol.transparent >= 0)
112 && (! numbers.transparent_color_flag)) {
113 numbers.version = GIF89A;
114 numbers.transparent_color_flag = YES;
115 numbers.transparent_color = gcontrol.transparent;
116 }
117 if (gcontrol.color[0] < 0L)
118 return;
119 for (i = 0; i < 2; i++) {
120 l = gcontrol.color[i];
121 for (j = 2; j >= 0; j--) {
122 color[i][j] = (unsigned char)(l & 0xFF);
123 l >>= 8;
124 }
125 }
126 for (n = 0; n < (2 << numbers.p_size); n++) {
127 p = numbers.color_table + 3 * n;
128 i = ((int)p[0] * 77
129 + (int)p[1] * 151
130 + (int)p[2] * 29) / 0x100; /* i = 0 .. 255 */
131 for (j = 0; j < 3; j++) {
132 p[j] = (color[0][j] * i + color[1][j] * (255 - i)) / 255;
133 }
134 }
135 }
136
137
set_num(void)138 INTERN void set_num(void) {
139 DIGITS digits[MAX_WIDTH];
140 int c, n, number, previous, increment;
141
142 if (gcontrol.random) {
143 number = rand();
144 } else if (gcontrol.number < 0) {
145 error_out("INTERNAL ERROR: set_num: No Number Setting");
146 } else {
147 number = gcontrol.number;
148 }
149 increment = (gcontrol.progress) ? gcontrol.increment : 0;
150 previous = number - increment;
151 for (n = 0; n < MAX_WIDTH; n++) {
152 digits[n].number = c = previous % 10;
153 digits[n].increment = (c == number % 10) ? 0 : increment;
154 number /= 10;
155 previous /= 10;
156 }
157 number_out(digits, increment);
158 }
159
160
number_out(DIGITS * digits,int increment)161 INTERN void number_out(DIGITS *digits, int increment) {
162 int width;
163
164 width = gcontrol.width;
165 if (width <= 0)
166 width = 1;
167 if (width > MAX_WIDTH)
168 width = MAX_WIDTH;
169 memcpy(&image, &numbers, sizeof(IMAGE));
170 image.left = image.top = 0;
171 image.width = numbers.width * width;
172 image.height = (gcontrol.unit > 0) ? gcontrol.unit : numbers.height / 10;
173 image.interlace_flag = NO;
174 image.disposal_method = 2; /* Restore to background color */
175 if ((image.pixel = (unsigned char *)malloc(image.width * image.height)) == NULL)
176 error_out("number_out: Cannot Allocate Memory");
177 memset(image.pixel, image.background, image.width * image.height);
178 if (increment == 0) {
179 static_set(digits, width, 0);
180 save_main();
181 } else if (gcontrol.gif_animation) {
182 gif_animation_out(digits, width);
183 } else {
184 server_push_out(digits, width);
185 }
186 free(image.pixel);
187 }
188
189
gif_animation_out(DIGITS * digits,int width)190 INTERN void gif_animation_out(DIGITS *digits, int width) {
191 unsigned int line;
192 int n;
193
194 image.version = GIF89A;
195 header_save();
196 global_save();
197 static_set(digits, width, 0);
198 image.delay = 0;
199 image.disposal_method = 0;
200 local_save();
201 for (n = 1; n < width; n++) {
202 if (digits[n].increment == 0)
203 break;
204 }
205 image.left = numbers.width * (width - n);
206 image.width = numbers.width * n;
207 image.disposal_method = 2;
208 for (line = 0; line <= numbers.height / 10; line++) {
209 static_set(digits, n, line);
210 image.delay = gcontrol.delay[(line == 0) ? 0 : 1] / 10;
211 local_save();
212 }
213 trailer_save();
214 }
215
216
server_push_out(DIGITS * digits,int width)217 INTERN void server_push_out(DIGITS *digits, int width) {
218 unsigned int line, msec;
219
220 if (env.nph)
221 fputs("HTTP/1.0 200 OK\n", stdout);
222 printf("Content-type: multipart/x-mixed-replace;boundary=%s\n\n", BOUNDARY);
223 for (line = 0; line <= numbers.height / 10; line++) {
224 printf("--%s\n", BOUNDARY);
225 static_set(digits, width, line);
226 save_main();
227 msec = gcontrol.delay[(line == 0) ? 0 : 1];
228 fputs("\n", stdout);
229 if (msec > 0) {
230 fflush(stdout);
231 msleep(msec);
232 }
233 }
234 printf("--%s--\n", BOUNDARY);
235 }
236
237
msleep(int msec)238 INTERN void msleep(int msec) {
239 #if defined(_WIN32)
240 Sleep(msec);
241 #else
242 struct timeval timeout;
243
244 timeout.tv_sec = msec / 1000;
245 timeout.tv_usec = (msec % 1000) * 1000;
246 select(0, 0, 0, 0, &timeout);
247 #endif
248 }
249
250
static_set(DIGITS * digits,int width,int add_lines)251 INTERN void static_set(DIGITS *digits, int width, int add_lines) {
252 int n;
253
254 for (n = 0; n < width; n++) {
255 set_image(width - n - 1,
256 digits[n].number * numbers.height / 10
257 + digits[n].increment * add_lines
258 + gcontrol.offset);
259 }
260 }
261
262
set_image(int row,int top)263 INTERN void set_image(int row, int top) {
264 unsigned int y;
265
266 for (y = 0; y < image.height; y++) {
267 memcpy(image.pixel
268 + numbers.width * row
269 + image.width * y,
270 numbers.pixel
271 + numbers.width
272 * ((top + y + numbers.height) % numbers.height),
273 numbers.width);
274 }
275 }
276
277
save_main(void)278 void save_main(void) {
279 header_save();
280 global_save();
281 local_save();
282 trailer_save();
283 }
284
285
global_save(void)286 INTERN void global_save(void) {
287 logical_screen_save();
288 global_palette_save();
289 }
290
291
local_save(void)292 INTERN void local_save(void) {
293 graphic_control_extension_save();
294 image_descriptor_save();
295 image_data_save();
296 }
297
298
header_save(void)299 INTERN void header_save(void) {
300 if (env.nph)
301 fputs("HTTP/1.0 200 OK\n", stdout);
302 fputs("Content-type: image/gif\n\n", stdout);
303
304 gwrite((unsigned char *)((image.version == GIF87A) ? "GIF87a" : "GIF89a"), 6);
305 }
306
307
logical_screen_save(void)308 INTERN void logical_screen_save(void) {
309 int bits;
310
311 gputw(image.width);
312 gputw(image.height);
313 bits = 0x00;
314 if (image.color_table_flag)
315 bits |= 0x80;
316 bits |= (image.s_size << 4);
317 if (image.sort_flag)
318 bits |= 0x08;
319 bits |= image.p_size;
320 gputc(bits);
321 gputc((image.transparent_color_flag) ? image.transparent_color : image.background);
322 gputc(image.aspect);
323 }
324
325
global_palette_save(void)326 INTERN void global_palette_save(void) {
327 gwrite(image.color_table, 3 * (2 << image.p_size));
328 }
329
330
graphic_control_extension_save(void)331 INTERN void graphic_control_extension_save(void) {
332 if ((image.version == GIF87A)
333 || ((image.transparent_color_flag == NO) && (image.delay == 0)))
334 return;
335 gputc(CODE_EXT);
336 gputc(CODE_CTRL_EXT);
337 gputc(4); /* block size after this field */
338 gputc((image.disposal_method << 2) + image.transparent_color_flag);
339 /* packed field */
340 gputw(image.delay); /* delay time */
341 gputc(image.transparent_color); /* transparent color index */
342 gputc(0); /* block terminator */
343 }
344
345
image_descriptor_save(void)346 INTERN void image_descriptor_save(void) {
347 gputc(CODE_IMAGE);
348 gputw(image.left);
349 gputw(image.top);
350 gputw(image.width);
351 gputw(image.height);
352 gputc(image.interlace_flag << 6);
353 }
354
355
image_data_save(void)356 INTERN void image_data_save(void) {
357 gputc(image.s_size + 1);
358 convert(image.s_size + 1, image.pixel, image.width * image.height);
359 }
360
361
trailer_save(void)362 INTERN void trailer_save(void) {
363 gputc(CODE_TRAILER);
364 }
365
366