/* * Copyright (c) 2003-2004, Jilles Tjoelker * All rights reserved. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the * following conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or * other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ /* * playttyrec 1.0 * An improved ttyrec player, conceived for NetHack playback. * Some keys are available during playback: * s - pause playback until key pressed * q - quit * space - abort current delay and continue immediately * b - go to previous screen clear * f - go to next screen clear * . - toggle no-delay playback (*very* fast) * / - search for a string (screen may mess up a little) * g - go to beginning * m<letter> - mark a position * '<letter> - go to mark */ /* * Compilation: * The program has been tested on FreeBSD, Linux and Solaris. * FreeBSD/Linux: * Simply compile with something like 'make playttyrec' or * 'gcc -W -Wall -o playttyrec playttyrec.c'. * Solaris: * You need some implementation of err() and similar functions. * I compile with 'cc playttyrec.c -o playttyrec * -I/usr/local/include -L/usr/local/lib -lbsderr' where * /usr/local/lib/libbsderr.a is an err implementation taken from * NetBSD pkgsrc ftp (pkgtools/libnbcompat was not tried). * Both gcc and Sun cc work. */ #include <sys/types.h> #include <sys/time.h> #include <ctype.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <termios.h> #include <unistd.h> struct termios origT, progT; void fatal_signal(int sig); void cleanup_term(char *message); void fatal_signal(int sig) { (void)sig; cleanup_term("Signal\n"); } void cleanup_term(char *message) { char *e; write(STDOUT_FILENO, "\017\033[H\033[J", 7); if (message != NULL && *message != '\0') { if (*message == '@') { message++; write(STDOUT_FILENO, message, strlen(message)); e = strerror(errno); write(STDOUT_FILENO, e, strlen(e)); write(STDOUT_FILENO, "\n", 1); } else write(STDOUT_FILENO, message, strlen(message)); } tcsetattr(STDOUT_FILENO, TCSANOW, &origT); exit(message != NULL ? 1 : 0); } int inputstr(char *buf, int buflen) { int n = 0; char c; for (;;) { if (read(STDOUT_FILENO, &c, 1) != 1) return 0; if (c == 8 || c == 127) { if (n > 0) { n--; write(STDOUT_FILENO, "\010 \010", 3); } else return 0; buf[n] = 0; } else if (c == 21 || c == 24) { while (n > 0) { n--; write(STDOUT_FILENO, "\010 \010", 3); } buf[n] = 0; } else if (c == 10 || c == 13) { /* Erase on display */ while (n > 0) { n--; write(STDOUT_FILENO, "\010 \010", 3); } /* Tricky, keep old string if Enter pressed as first char */ return 1; } else if (isprint(c) && n < buflen) { buf[n] = c; n++; buf[n] = '\0'; write(STDOUT_FILENO, &c, 1); } } return 0; } int main(int argc, char *argv[]) { unsigned char buf[12]; char data[65536]; FILE *input; int n,r; struct timeval prev, cur, diff, thres; int first = 1; int do_delay = 1, do_output = 1, do_search = 0, wait_for_next_screen = 0; int isclrscr, had_to_output; int marknum; char c; char searchstr[256] = ""; off_t o = 0, *clrscroffsets, marks[26] = { 0 }, quick_until = -1; int clrscroffsetallocated = 1000, cscount = 0, cscur = 0; fd_set FRFDS, RFDS; thres.tv_sec = 60; thres.tv_usec = 0; clrscroffsets = malloc(clrscroffsetallocated * sizeof(*clrscroffsets)); if (clrscroffsets == NULL) err(1, "malloc"); if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); return 1; } input = fopen(argv[1], "r"); if (input == NULL) err(1, "cannot open %s", argv[1]); if (!isatty(STDOUT_FILENO)) errx(1, "stdout must be a terminal"); if (tcgetattr(STDOUT_FILENO, &origT) == -1) err(1, "tcgetattr"); signal(SIGINT, fatal_signal); signal(SIGTERM, fatal_signal); progT = origT; progT.c_lflag &= ~(ECHO | ICANON); progT.c_cc[VMIN] = 1; /* Solaris box I tested on has 4 by default. */ progT.c_cc[VTIME] = 0; if (tcsetattr(STDOUT_FILENO, TCSANOW, &progT) == -1) err(1, "tcsetattr"); FD_ZERO(&FRFDS); FD_SET(STDOUT_FILENO, &FRFDS); while ((errno = 0), (r = fread(buf, 1, 12, input)) >= 0) { if (r == 12) { cur.tv_sec = (((((buf[3] << 8) | buf[2]) << 8) | buf[1]) << 8) | buf[0]; cur.tv_usec = (((((buf[7] << 8) | buf[6]) << 8) | buf[5]) << 8) | buf[4]; if (first) { first = 0; } else { diff.tv_sec = cur.tv_sec - prev.tv_sec; diff.tv_usec = cur.tv_usec - prev.tv_usec; if (diff.tv_usec < 0) { diff.tv_usec += 1000000; diff.tv_sec--; } /*if (timercmp(&diff, &thres, >)) diff = thres;*/ } prev = cur; n = (((((buf[11] << 8) | buf[10]) << 8) | buf[9]) << 8) | buf[8]; if ((unsigned int)n >= sizeof(data)) /* keep space for '\0' */ cleanup_term("h->len too big\n"); r = fread(data, 1, n, input); if (n != r) cleanup_term("@read input: "); data[r] = '\0'; isclrscr = o == 0 || strstr(data, "\033[2J") != NULL; if (cscount == 0 || (o > clrscroffsets[cscount - 1] && isclrscr)) { if (cscount > clrscroffsetallocated) { clrscroffsetallocated *= 2; clrscroffsets = realloc(clrscroffsets, clrscroffsetallocated * sizeof(*clrscroffsets)); if (clrscroffsets == NULL) /* forget about dangling memory */ cleanup_term("realloc failed"); } clrscroffsets[cscount++] = o; } o += 12 + r; had_to_output = do_output; if (do_search && strstr(data, searchstr) != NULL) { quick_until = o; cscur = cscount - 1; while (o <= clrscroffsets[cscur] && cscur > 0) cscur--; o = clrscroffsets[cscur]; fseeko(input, o, SEEK_SET); do_search = 0; do_output = 1; do_delay = 0; diff.tv_sec = diff.tv_usec = 0; } if (wait_for_next_screen && isclrscr) { wait_for_next_screen = 0; do_delay = do_output = had_to_output = 1; diff.tv_sec = diff.tv_usec = 0; } if (quick_until != -1 && o >= quick_until) { quick_until = -1; diff.tv_sec = diff.tv_usec = 0; do_delay = 1; } } else if (r != 0) break; else { write(STDOUT_FILENO, "[EOF]", 5); clearerr(input); } RFDS = FRFDS; if (!do_delay) diff.tv_sec = diff.tv_usec = 0; if (select(STDOUT_FILENO + 1, &RFDS, NULL, NULL, r == 0 ? NULL : &diff) == 1) { read(STDOUT_FILENO, &c, 1); switch (c) { case 'q': case 'Q': cleanup_term(NULL); exit(0); break; case 's': case 'S': read(STDOUT_FILENO, &c, 1); do_search = 0; do_delay = do_output = 1; /*do_search = delay_on_next_screen = 0;*/ break; case ' ': break; case '.': do_delay = !do_delay; do_search = wait_for_next_screen = 0; break; case 'f': case 'F': do_delay = do_search = do_output = 0; wait_for_next_screen = 1; break; case 'b': case 'B': cscur = cscount - 1; o -= 12 + r; if (o < 0) o = 0; while (o <= clrscroffsets[cscur] && cscur > 0) cscur--; if (cscur > 0) cscur--; o = clrscroffsets[cscur]; fseeko(input, o, SEEK_SET); break; case '/': write(STDOUT_FILENO, "/", 1); if (inputstr(searchstr, sizeof searchstr - 1) && *searchstr != '\0') { do_delay = 0; do_search = 1; do_output = 0; had_to_output = 0; } write(STDOUT_FILENO, "\010 \010", 3); break; case 'g': o = 0; fseeko(input, 0, SEEK_SET); do_search = 0; do_delay = do_output = 1; had_to_output = 0; break; case 'm': read(STDOUT_FILENO, &c, 1); if (c >= 'a' && c <= 'z') marknum = c - 'a'; else if (c >= 'A' && c <= 'Z') marknum = c - 'A'; else { write(STDOUT_FILENO, "\a", 1); break; } marks[marknum] = o - 12 - r; if (marks[marknum] < 0) marks[marknum] = 0; break; case '\'': case '`': read(STDOUT_FILENO, &c, 1); if (c >= 'a' && c <= 'z') marknum = c - 'a'; else if (c >= 'A' && c <= 'Z') marknum = c - 'A'; else { write(STDOUT_FILENO, "\a", 1); break; } o = marks[marknum]; cscur = cscount - 1; while (o <= clrscroffsets[cscur] && cscur > 0) cscur--; o = clrscroffsets[cscur]; fseeko(input, o, SEEK_SET); quick_until = marks[marknum]; do_delay = do_search = 0; do_output = 1; break; default: write(STDOUT_FILENO, "\a", 1); } } if (had_to_output) if (write(STDOUT_FILENO, data, r) != r) cleanup_term("@write stdout: "); } if (errno != 0) cleanup_term("@read input: "); return 0; } /* vim:ts=8:cin:sw=4 * */



프로그래밍에 문외한이라 어떤 언어인지좀 알려주라 그리고 이거 실행하려면 어떻게 해야돼?