line completion and removal
[ansitris] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <termios.h>
8 #include <sys/stat.h>
9 #include <sys/select.h>
10 #include <sys/time.h>
11 #include "game.h"
12
13 int init(void);
14 void cleanup(void);
15 int parse_args(int argc, char **argv);
16 void print_usage(const char *argv0);
17 long get_msec(void);
18
19 static const char *termfile = "/dev/tty";
20 static struct termios saved_term;
21 static struct timeval tv0;
22
23 int main(int argc, char **argv)
24 {
25         int res, c;
26         long msec, next;
27         struct timeval tv;
28
29         if(parse_args(argc, argv) == -1) {
30                 return 1;
31         }
32
33         if(init() == -1) {
34                 return 1;
35         }
36
37         gettimeofday(&tv0, 0);
38
39         tv.tv_sec = tick_interval / 1000;
40         tv.tv_usec = (tick_interval % 1000) * 1000;
41
42         for(;;) {
43                 fd_set rdset;
44                 FD_ZERO(&rdset);
45                 FD_SET(0, &rdset);
46
47                 while((res = select(1, &rdset, 0, 0, &tv)) == -1 && errno == EINTR);
48
49                 if(res > 0 && FD_ISSET(0, &rdset)) {
50                         while((c = fgetc(stdin)) >= 0) {
51                                 game_input(c);
52                                 if(quit) goto end;
53                         }
54                 }
55
56                 msec = get_msec();
57                 next = update(msec);
58
59                 tv.tv_sec = next / 1000;
60                 tv.tv_usec = (next % 1000) * 1000;
61         }
62
63 end:
64         cleanup();
65         return 0;
66 }
67
68 int init(void)
69 {
70         int fd;
71         struct termios term;
72
73         if((fd = open(termfile, O_RDWR | O_NONBLOCK)) == -1) {
74                 fprintf(stderr, "failed to open terminal device: %s: %s\n", termfile, strerror(errno));
75                 return -1;
76         }
77
78         if(tcgetattr(fd, &term) == -1) {
79                 fprintf(stderr, "failed to get terminal attributes: %s\n", strerror(errno));
80                 return -1;
81         }
82         saved_term = term;
83         term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
84         term.c_oflag &= ~OPOST;
85         term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
86         term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8;
87
88         if(tcsetattr(fd, TCSAFLUSH, &term) == -1) {
89                 fprintf(stderr, "failed to change terminal attributes: %s\n", strerror(errno));
90                 return -1;
91         }
92
93         close(0);
94         close(1);
95         close(2);
96         dup(fd);
97         dup(fd);
98
99         umask(002);
100         open("ansitris.log", O_WRONLY | O_CREAT | O_TRUNC, 0664);
101
102
103         if(init_game() == -1) {
104                 return -1;
105         }
106
107         return 0;
108 }
109
110 void cleanup(void)
111 {
112         cleanup_game();
113         tcsetattr(0, TCSAFLUSH, &saved_term);
114 }
115
116 int parse_args(int argc, char **argv)
117 {
118         int i;
119
120         for(i=1; i<argc; i++) {
121                 if(argv[i][0] == '-') {
122                         if(argv[i][2] == 0) {
123                                 switch(argv[i][1]) {
124                                 case 't':
125                                         termfile = argv[++i];
126                                         break;
127
128                                 case 'b':
129                                         use_bell = 1;
130                                         break;
131
132                                 case 'h':
133                                         print_usage(argv[0]);
134                                         exit(0);
135
136                                 default:
137                                         fprintf(stderr, "invalid option: %s\n", argv[i]);
138                                         print_usage(argv[0]);
139                                         return -1;
140                                 }
141                         } else {
142                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
143                                 print_usage(argv[0]);
144                                 return -1;
145                         }
146                 } else {
147                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
148                         print_usage(argv[0]);
149                         return -1;
150                 }
151         }
152         return 0;
153 }
154
155 void print_usage(const char *argv0)
156 {
157         printf("Usage: %s [options]\n", argv0);
158         printf("Options:\n");
159         printf(" -t <dev>: terminal device (default: /dev/tty)\n");
160         printf(" -b: use bell for sound ques (default: off)\n");
161         printf(" -h: print usage information and exit\n");
162 }
163
164 long get_msec(void)
165 {
166         struct timeval tv;
167
168         gettimeofday(&tv, 0);
169
170         return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
171 }