Command line options with getopt_long

This commit is contained in:
Kevin Lange 2012-03-23 17:55:13 -05:00
parent 022782ce09
commit 672b3abae0
1 changed files with 193 additions and 145 deletions

View File

@ -59,6 +59,7 @@
#include <time.h> #include <time.h>
#include <setjmp.h> #include <setjmp.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <getopt.h>
#ifndef TIOCGWINSZ #ifndef TIOCGWINSZ
#include <termios.h> #include <termios.h>
@ -236,6 +237,17 @@ void send_command(int cmd, int opt) {
} }
} }
void usage(char * argv[]) {
printf(
"Terminal Nyancat\n"
"\n"
"usage: %s [-h] [-t] [-i] \n"
"\n"
" -i --intro \033[3mShow the introduction / about informaiton at startup.\033[0m\n"
" -t --telnet \033[3mTelnet mode.\033[0m\n",
" -h --help \033[3mShow this help message.\033[0m\n",
argv[0]);
}
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
@ -249,126 +261,160 @@ int main(int argc, char ** argv) {
char sb[1024] = {0}; char sb[1024] = {0};
char sb_len = 0; char sb_len = 0;
if (argc > 1) { char show_intro = 0;
if (!strcmp(argv[1], "-t")) {
/* Yes, I know, lame way to get arguments, whatever, we only want one of them. */
telnet = 1;
/* Set the default options */ /* Long option names */
set_options(); static struct option long_opts[] = {
{"help", no_argument, 0, 'h'},
{"telnet", no_argument, 0, 't'},
{"intro", no_argument, 0, 'i'},
{0,0,0,0}
};
/* Let the client know what we're using */ /* Process arguments */
for (option = 0; option < 256; option++) { int index, c;
if (telnet_options[option]) { while ((c = getopt_long(argc, argv, "hit", long_opts, &index)) != -1) {
send_command(telnet_options[option], option); if (!c) {
fflush(stdout); if (long_opts[index].flag == 0) {
} c = long_opts[index].val;
} }
for (option = 0; option < 256; option++) { }
if (telnet_willack[option]) { switch (c) {
send_command(telnet_willack[option], option); case 'i': /* Show introduction */
fflush(stdout); show_intro = 1;
} break;
case 't': /* Expect telnet bits */
telnet = 1;
break;
case 'h': /* Show help and exit */
usage(argv);
exit(0);
break;
default:
break;
}
}
if (telnet) {
/* Telnet mode */
/* Intro is implied by telnet mode, so override whatever was asked for. */
show_intro = 1;
/* Set the default options */
set_options();
/* Let the client know what we're using */
for (option = 0; option < 256; option++) {
if (telnet_options[option]) {
send_command(telnet_options[option], option);
fflush(stdout);
} }
}
for (option = 0; option < 256; option++) {
if (telnet_willack[option]) {
send_command(telnet_willack[option], option);
fflush(stdout);
}
}
/* Set the alarm handler to execute the longjmp */ /* Set the alarm handler to execute the longjmp */
signal(SIGALRM, SIGALRM_handler); signal(SIGALRM, SIGALRM_handler);
/* Negotiate options */ /* Negotiate options */
if (!setjmp(environment)) { if (!setjmp(environment)) {
/* We will stop handling options after one second */ /* We will stop handling options after one second */
alarm(1); alarm(1);
/* Let's do this */ /* Let's do this */
while (!feof(stdin) && done < 2) { while (!feof(stdin) && done < 2) {
/* Get either IAC (start command) or a regular character (break, unless in SB mode) */ /* Get either IAC (start command) or a regular character (break, unless in SB mode) */
unsigned char i = getchar(); unsigned char i = getchar();
unsigned char opt = 0; unsigned char opt = 0;
if (i == IAC) { if (i == IAC) {
/* If IAC, get the command */ /* If IAC, get the command */
i = getchar(); i = getchar();
switch (i) { switch (i) {
case SE: case SE:
/* End of extended option mode */ /* End of extended option mode */
sb_mode = 0; sb_mode = 0;
if (sb[0] == TTYPE) { if (sb[0] == TTYPE) {
/* This was a response to the TTYPE command, meaning /* This was a response to the TTYPE command, meaning
* that this should be a terminal type */ * that this should be a terminal type */
alarm(0); alarm(0);
strcpy(term, &sb[2]); strcpy(term, &sb[2]);
done++; done++;
} }
else if (sb[0] == NAWS) { else if (sb[0] == NAWS) {
/* This was a response to the NAWS command, meaning /* This was a response to the NAWS command, meaning
* that this should be a window size */ * that this should be a window size */
alarm(0); alarm(0);
terminal_width = sb[2]; terminal_width = sb[2];
done++; done++;
} }
break; break;
case NOP: case NOP:
/* No Op */ /* No Op */
send_command(NOP, 0); send_command(NOP, 0);
fflush(stdout);
break;
case WILL:
case WONT:
/* Will / Won't Negotiation */
opt = getchar();
if (!telnet_willack[opt]) {
/* We default to WONT */
telnet_willack[opt] = WONT;
}
send_command(telnet_willack[opt], opt);
fflush(stdout);
if ((i == WILL) && (opt == TTYPE)) {
/* WILL TTYPE? Great, let's do that now! */
printf("%c%c%c%c%c%c", IAC, SB, TTYPE, SEND, IAC, SE);
fflush(stdout); fflush(stdout);
break; }
case WILL: break;
case WONT: case DO:
/* Will / Won't Negotiation */ case DONT:
opt = getchar(); /* Do / Don't Negotation */
if (!telnet_willack[opt]) { opt = getchar();
/* We default to WONT */ if (!telnet_options[opt]) {
telnet_willack[opt] = WONT; /* We default to DONT */
} telnet_options[opt] = DONT;
send_command(telnet_willack[opt], opt); }
fflush(stdout); send_command(telnet_options[opt], opt);
if ((i == WILL) && (opt == TTYPE)) { if (opt == ECHO) {
/* WILL TTYPE? Great, let's do that now! */ /* We don't really need this, as we don't accept input, but,
printf("%c%c%c%c%c%c", IAC, SB, TTYPE, SEND, IAC, SE); * in case we do in the future, set our echo mode */
fflush(stdout); do_echo = (i == DO);
} }
break; fflush(stdout);
case DO: break;
case DONT: case SB:
/* Do / Don't Negotation */ /* Begin Extended Option Mode */
opt = getchar(); sb_mode = 1;
if (!telnet_options[opt]) { sb_len = 0;
/* We default to DONT */ memset(sb, 0, 1024);
telnet_options[opt] = DONT; break;
} case IAC:
send_command(telnet_options[opt], opt); /* IAC IAC? That's probably not right. */
if (opt == ECHO) { done = 2;
/* We don't really need this, as we don't accept input, but, break;
* in case we do in the future, set our echo mode */ default:
do_echo = (i == DO); break;
} }
fflush(stdout); } else if (sb_mode) {
break; /* Extended Option Mode -> Accept character */
case SB: if (sb_len < 1023) {
/* Begin Extended Option Mode */ /* Append this character to the SB string,
sb_mode = 1; * but only if it doesn't put us over
sb_len = 0; * our limit; honestly, we shouldn't hit
memset(sb, 0, 1024); * the limit, as we're only collecting characters
break; * for a terminal type or window size, but better safe than
case IAC: * sorry (and vulernable).
/* IAC IAC? That's probably not right. */ */
done = 2; sb[sb_len] = i;
break; sb_len++;
default:
break;
}
} else if (sb_mode) {
/* Extended Option Mode -> Accept character */
if (sb_len < 1023) {
/* Append this character to the SB string,
* but only if it doesn't put us over
* our limit; honestly, we shouldn't hit
* the limit, as we're only collecting characters
* for a terminal type or window size, but better safe than
* sorry (and vulernable).
*/
sb[sb_len] = i;
sb_len++;
}
} }
} }
} }
@ -379,7 +425,7 @@ int main(int argc, char ** argv) {
char * nterm = getenv("TERM"); char * nterm = getenv("TERM");
if (nterm) if (nterm)
strcpy(term, nterm); strcpy(term, nterm);
/* Also get the number of columns */ /* Also get the number of columns */
struct winsize w; struct winsize w;
ioctl(0, TIOCGWINSZ, &w); ioctl(0, TIOCGWINSZ, &w);
@ -390,7 +436,7 @@ int main(int argc, char ** argv) {
for (k = 0; k < strlen(term); ++k) { for (k = 0; k < strlen(term); ++k) {
term[k] = tolower(term[k]); term[k] = tolower(term[k]);
} }
/* We don't want terminals wider than 80 columns */ /* We don't want terminals wider than 80 columns */
if(terminal_width > 80) terminal_width = 80; if(terminal_width > 80) terminal_width = 80;
@ -548,40 +594,42 @@ int main(int argc, char ** argv) {
/* Clear the screen */ /* Clear the screen */
printf("\033[H\033[2J\033[?25l"); printf("\033[H\033[2J\033[?25l");
/* Display the MOTD */ if (show_intro) {
int countdown_clock = 5; /* Display the MOTD */
for (k = 0; k < countdown_clock; ++k) { int countdown_clock = 5;
newline(3); for (k = 0; k < countdown_clock; ++k) {
printf(" \033[1mNyancat Telnet Server\033[0m"); newline(3);
newline(2); printf(" \033[1mNyancat Telnet Server\033[0m");
printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m"); newline(2);
newline(2); printf(" written and run by \033[1;32mKevin Lange\033[1;34m @kevinlange\033[0m");
printf(" If things don't look right, try:"); newline(2);
newline(1); printf(" If things don't look right, try:");
printf(" TERM=fallback telnet ..."); newline(1);
newline(2); printf(" TERM=fallback telnet ...");
printf(" Or on Windows:"); newline(2);
newline(1); printf(" Or on Windows:");
printf(" telnet -t vtnt ..."); newline(1);
newline(2); printf(" telnet -t vtnt ...");
printf(" Problems? I am also a webserver:"); newline(2);
newline(1); printf(" Problems? I am also a webserver:");
printf(" \033[1;34mhttp://miku.acm.uiuc.edu\033[0m"); newline(1);
newline(2); printf(" \033[1;34mhttp://miku.acm.uiuc.edu\033[0m");
printf(" This is a telnet server, remember your escape keys!"); newline(2);
newline(1); printf(" This is a telnet server, remember your escape keys!");
printf(" \033[1;31m^]quit\033[0m to exit"); newline(1);
newline(2); printf(" \033[1;31m^]quit\033[0m to exit");
printf(" Starting in %d... \n", countdown_clock-k); newline(2);
printf(" Starting in %d... \n", countdown_clock-k);
fflush(stdout); fflush(stdout);
usleep(400000); usleep(400000);
printf("\033[H"); /* Reset cursor */ printf("\033[H"); /* Reset cursor */
}
/* Clear the screen again */
printf("\033[H\033[2J\033[?25l");
} }
/* Clear the screen again */
printf("\033[H\033[2J\033[?25l");
/* Store the start time */ /* Store the start time */
time_t start, current; time_t start, current;
time(&start); time(&start);