/* * npc.c -- animation counter main routine * * Copyright (c) 1995-2000 by nir@mvg.biglobe.ne.jp * * This file is part of npc.cgi source tree. * npc.cgi is free software; you can redistribute it and/or modify it * for any purpose. * * @(#)$Id: npc.c,v 2.11 2000/11/14 11:17:31 nir Exp $ */ /* * $Log: npc.c,v $ * Revision 2.11 2000/11/14 11:17:31 nir * Return at the present time in Last-Modified response header. * * Revision 2.10 2000/03/25 08:45:45 nir * Fix HTTP response header newline code to CRLF insted of LF. * * Revision 2.9 1997/12/11 14:07:34 nir * Add left, top and disposal_method elements to struct IMAGE. * In the GIF animation mode, only the rewriting digit(s) is output. * * Revision 2.8 1997/11/10 16:19:05 nir * Modify error_out() message. * * Revision 2.7 1997/11/06 19:51:52 nir * Add MODE initialization. * * Revision 2.6 1997/11/05 12:09:15 nir * Add Copyright, Id and Log. * Change animation mode default from server push to 89aGIF animation. * */ #include "npc.h" INTERN void initialize(void); INTERN void select_num(void); INTERN void set_num(void); INTERN void arg2num(char *str); INTERN void number_out(DIGITS *digits, int increment); INTERN void gif_animation_out(DIGITS *digits, int width); INTERN void server_push_out(DIGITS *digits, int width); INTERN void static_set(DIGITS *digits, int width, int add_lines); INTERN void msleep(int msec); INTERN void set_image(int row, int top); INTERN void global_save(void); INTERN void local_save(void); INTERN void header_save(void); INTERN void logical_screen_save(void); INTERN void global_palette_save(void); INTERN void graphic_control_extension_save(void); INTERN void image_descriptor_save(void); INTERN void image_data_save(void); INTERN void scale_out(unsigned int line); INTERN void trailer_save(void); GLOBAL IMAGE image; GLOBAL IMAGE numbers; GLOBAL GCONTROL gcontrol; GLOBAL ENV env; int main(int argc, char **argv) { FILE *index_file; initialize(); get_environ(argc, argv); index_file = open_index(); get_config(index_file); if (gcontrol.restriction > 1) error_out("No Permission To Use This Counter"); get_param(); update_count(index_file); fclose(index_file); select_num(); set_num(); return(0); } INTERN void initialize(void) { env.index_dir = INDEX_DIR; env.index = INDEX_FILE; gcontrol.random = NO; gcontrol.progress = NO; gcontrol.gif_animation = YES; gcontrol.width = DEFAULT_WIDTH; gcontrol.unit = 0; gcontrol.offset = 0; gcontrol.number = BAD; gcontrol.increment = 1; gcontrol.restriction = 0; gcontrol.mode = 0; gcontrol.digits = 0; gcontrol.initial = 1; gcontrol.transparent = BAD; gcontrol.delay[0] = gcontrol.delay[1] = 0; gcontrol.color[0] = gcontrol.color[1] = (long)BAD; gcontrol.location = NULL; srand(time(NULL)); #if defined(_WIN32) _setmode(fileno(stdout), _O_BINARY); #endif } INTERN void select_num(void) { unsigned char color[2][3]; unsigned char *p; int i, j, n; long l; memcpy(&numbers, get_digits(gcontrol.digits), sizeof(IMAGE)); if ((gcontrol.transparent >= 0) && (! numbers.transparent_color_flag)) { numbers.version = GIF89A; numbers.transparent_color_flag = YES; numbers.transparent_color = gcontrol.transparent; } if (gcontrol.color[0] < 0L) return; for (i = 0; i < 2; i++) { l = gcontrol.color[i]; for (j = 2; j >= 0; j--) { color[i][j] = (unsigned char)(l & 0xFF); l >>= 8; } } for (n = 0; n < (2 << numbers.p_size); n++) { p = numbers.color_table + 3 * n; i = ((int)p[0] * 77 + (int)p[1] * 151 + (int)p[2] * 29) / 0x100; /* i = 0 .. 255 */ for (j = 0; j < 3; j++) { p[j] = (color[0][j] * i + color[1][j] * (255 - i)) / 255; } } } INTERN void set_num(void) { DIGITS digits[MAX_WIDTH]; int c, n, number, previous, increment; if (gcontrol.random) { number = rand(); } else if (gcontrol.number < 0) { error_out("INTERNAL ERROR: set_num: No Number Setting"); } else { number = gcontrol.number; } increment = (gcontrol.progress) ? gcontrol.increment : 0; previous = number - increment; for (n = 0; n < MAX_WIDTH; n++) { digits[n].number = c = previous % 10; digits[n].increment = (c == number % 10) ? 0 : increment; number /= 10; previous /= 10; } number_out(digits, increment); } INTERN void number_out(DIGITS *digits, int increment) { int width; width = gcontrol.width; if (width <= 0) width = 1; if (width > MAX_WIDTH) width = MAX_WIDTH; memcpy(&image, &numbers, sizeof(IMAGE)); image.left = image.top = 0; image.width = numbers.width * width; image.height = (gcontrol.unit > 0) ? gcontrol.unit : numbers.height / 10; image.interlace_flag = NO; image.disposal_method = 2; /* Restore to background color */ if ((image.pixel = (unsigned char *)malloc(image.width * image.height)) == NULL) error_out("number_out: Cannot Allocate Memory"); memset(image.pixel, image.background, image.width * image.height); if (increment == 0) { static_set(digits, width, 0); save_main(); } else if (gcontrol.gif_animation) { gif_animation_out(digits, width); } else { server_push_out(digits, width); } free(image.pixel); } INTERN void gif_animation_out(DIGITS *digits, int width) { unsigned int line; int n; image.version = GIF89A; header_save(); global_save(); static_set(digits, width, 0); image.delay = 0; image.disposal_method = 0; local_save(); for (n = 1; n < width; n++) { if (digits[n].increment == 0) break; } image.left = numbers.width * (width - n); image.width = numbers.width * n; image.disposal_method = 2; for (line = 0; line <= numbers.height / 10; line++) { static_set(digits, n, line); image.delay = gcontrol.delay[(line == 0) ? 0 : 1] / 10; local_save(); } trailer_save(); } INTERN void server_push_out(DIGITS *digits, int width) { unsigned int line, msec; if (env.nph) fputs("HTTP/1.0 200 OK\r\n", stdout); printf("Content-Type: multipart/x-mixed-replace;boundary=%s\r\n\r\n", BOUNDARY); for (line = 0; line <= numbers.height / 10; line++) { printf("--%s\r\n", BOUNDARY); static_set(digits, width, line); save_main(); msec = gcontrol.delay[(line == 0) ? 0 : 1]; fputs("\r\n", stdout); if (msec > 0) { fflush(stdout); msleep(msec); } } printf("--%s--\r\n", BOUNDARY); } INTERN void msleep(int msec) { #if defined(_WIN32) Sleep(msec); #else struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; select(0, 0, 0, 0, &timeout); #endif } INTERN void static_set(DIGITS *digits, int width, int add_lines) { int n; for (n = 0; n < width; n++) { set_image(width - n - 1, digits[n].number * numbers.height / 10 + digits[n].increment * add_lines + gcontrol.offset); } } INTERN void set_image(int row, int top) { unsigned int y; for (y = 0; y < image.height; y++) { memcpy(image.pixel + numbers.width * row + image.width * y, numbers.pixel + numbers.width * ((top + y + numbers.height) % numbers.height), numbers.width); } } void save_main(void) { header_save(); global_save(); local_save(); trailer_save(); } INTERN void global_save(void) { logical_screen_save(); global_palette_save(); } INTERN void local_save(void) { graphic_control_extension_save(); image_descriptor_save(); image_data_save(); } INTERN void header_save(void) { time_t timer; char *buf; if (env.nph) fputs("HTTP/1.0 200 OK\r\n", stdout); fputs("Content-Type: image/gif\r\n", stdout); timer = time(NULL); buf = asctime(gmtime(&timer)); buf[3] = buf[7] = buf[10] = buf[19] = buf[24] = EOS; printf("Last-Modified: %s, %s %s %s %s GMT\r\n", buf, buf + 8, buf + 4, buf + 20, buf + 11); fputs("\r\n", stdout); gwrite((unsigned char *)((image.version == GIF87A) ? "GIF87a" : "GIF89a"), 6); } INTERN void logical_screen_save(void) { int bits; gputw(image.width); gputw(image.height); bits = 0x00; if (image.color_table_flag) bits |= 0x80; bits |= (image.s_size << 4); if (image.sort_flag) bits |= 0x08; bits |= image.p_size; gputc(bits); gputc((image.transparent_color_flag) ? image.transparent_color : image.background); gputc(image.aspect); } INTERN void global_palette_save(void) { gwrite(image.color_table, 3 * (2 << image.p_size)); } INTERN void graphic_control_extension_save(void) { if ((image.version == GIF87A) || ((image.transparent_color_flag == NO) && (image.delay == 0))) return; gputc(CODE_EXT); gputc(CODE_CTRL_EXT); gputc(4); /* block size after this field */ gputc((image.disposal_method << 2) + image.transparent_color_flag); /* packed field */ gputw(image.delay); /* delay time */ gputc(image.transparent_color); /* transparent color index */ gputc(0); /* block terminator */ } INTERN void image_descriptor_save(void) { gputc(CODE_IMAGE); gputw(image.left); gputw(image.top); gputw(image.width); gputw(image.height); gputc(image.interlace_flag << 6); } INTERN void image_data_save(void) { gputc(image.s_size + 1); convert(image.s_size + 1, image.pixel, image.width * image.height); } INTERN void trailer_save(void) { gputc(CODE_TRAILER); }