/*
* 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
* */
프로그래밍에 문외한이라 어떤 언어인지좀 알려주라 그리고 이거 실행하려면 어떻게 해야돼?
gcc
그리고 웬간한건 구글링 하는 연습해... 사회 나가면 아무도 안알려줘... 사수도 없다고 봐야돼... 웬마한 회사 아니고서는..
c네 해더파일만 보면 바로 나오잔냐.....리눅스환경인가보구만