added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / dsys / script.c
1 /*
2 This file is part of the 3dengfx demo system.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program demo is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21
22 #include "3dengfx_config.h"
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <ctype.h>
28 #include <assert.h>
29 #include "script.h"
30
31 #define NEED_COMMAND_STRINGS
32 #include "cmd.h"
33
34 #define BUF_LEN         1024
35
36 static char *cmd_symb[] = {COMMANDS, 0};
37
38 DemoScript *open_script(const char *fname) {
39         DemoScript *script = malloc(sizeof(DemoScript));
40         
41         if(!(script->file = fopen(fname, "r"))) {
42                 free(script);
43                 return 0;
44         }               
45         script->fname = malloc(strlen(fname)+1);
46         strcpy(script->fname, fname);
47
48         script->line_buffer = malloc(BUF_LEN);
49         script->line_buffer[0] = 0;
50
51         script->line = 0;
52
53         return script;
54 }
55
56 void close_script(DemoScript *ds) {
57         fclose(ds->file);
58         free(ds->fname);
59         free(ds);
60 }
61
62
63 static char *skip_spaces(char *ptr) {
64         while(*ptr && *ptr != '\n' && isspace(*ptr)) ptr++;
65         return ptr;
66 }
67
68 int get_next_command(DemoScript *ds, DemoCommand *cmd, unsigned long time) {
69         char *ptr;
70         char *cmd_tok;
71         int i;
72         
73         /* get next line if one is available */
74         if(ds->line_buffer[0] == 0) {
75                 if(!fgets(ds->line_buffer, BUF_LEN, ds->file)) {
76                         return EOF;
77                 }
78                 ds->line++;
79         }
80
81         ptr = skip_spaces(ds->line_buffer);
82
83         /* skip comments and empty lines */
84         if(*ptr == '#' || *ptr == '\n') {
85                 ds->line_buffer[0] = 0;
86                 return get_next_command(ds, cmd, time);
87         }
88
89         /* retrieve command time */
90         cmd->time = atoi(ptr);
91         
92         /* skip timestamp and following whitespace */
93         while(*ptr && *ptr != '\n' && (isdigit(*ptr) || isspace(*ptr) || (isdigit(*(ptr-1)) && *ptr == 's'))) {
94                 if(*ptr == 's') cmd->time *= 1000;
95                 ptr++;
96         }
97         if(!*ptr || *ptr == '\n') {
98                 fprintf(stderr, "Skipping invalid line %ld: %s\n", ds->line, ds->line_buffer);
99                 ds->line_buffer[0] = 0;
100                 return get_next_command(ds, cmd, time);
101         }
102         
103         if(cmd->time > time) {
104                 return 1;       /* time is in the future */
105         }
106
107         /* seperate command name substring (cmd_tok), ptr keeps the rest */
108         cmd_tok = ptr;
109         while(*ptr && !isspace(*ptr)) ptr++;
110         *ptr++ = 0;
111
112         /* make the command name upper-case */
113         for(i=0; cmd_tok[i]; i++) {
114                 cmd_tok[i] = toupper(cmd_tok[i]);
115         }
116
117         /* match the command string with the available commands */
118         cmd->type = (CommandType)UINT_MAX;
119         for(i=0; cmd_symb[i]; i++) {
120                 if(!strcmp(cmd_tok, cmd_symb[i])) {
121                         cmd->type = i;
122                         break;
123                 }
124         }
125         
126         if(cmd->type == (CommandType)UINT_MAX) {
127                 fprintf(stderr, "Skipping invalid line %ld: Unrecognized command %s\n", ds->line, cmd_tok);
128                 ds->line_buffer[0] = 0;
129                 return get_next_command(ds, cmd, time);
130         }
131
132         /* tokenize the rest of the arguments and put them into argv */
133         cmd_tok = ptr = skip_spaces(ptr);
134         cmd->argc = *ptr ? 1 : 0;
135
136         while(*ptr && *ptr != '\n') {
137                 if(isspace(*ptr)) {
138                         ptr = skip_spaces(ptr);
139                         if(*ptr && *ptr != '\n') cmd->argc++;
140                 } else {
141                         ptr++;
142                 }
143         }
144         
145         cmd->argv = malloc((cmd->argc + 1) * sizeof(char*));
146         for(i=0; i<cmd->argc; i++) {
147                 ptr = strtok(i ? 0 : cmd_tok, " \t\n");
148                 assert(ptr);
149
150                 cmd->argv[i] = malloc(strlen(ptr) + 1);
151                 strcpy((char*)cmd->argv[i], ptr);
152         }
153         cmd->argv[i] = 0;
154         
155         /*
156         if(!*ptr || *ptr == '\n') {
157                 cmd->args = 0;
158         } else {
159                 unsigned int len = strlen(ptr);
160                 cmd->args = malloc(len + 1);
161                 strcpy(cmd->args, ptr);
162                 if(cmd->args[len - 1] == '\n') {
163                         cmd->args[len - 1] = 0;
164                 }
165         }
166         */
167         ds->line_buffer[0] = 0;
168         
169         return 0;
170 }
171
172 void free_command(DemoCommand *cmd) {
173         int i;
174         for(i=0; i<cmd->argc; i++) {
175                 free((void*)cmd->argv[i]);
176         }
177         free(cmd->argv);
178 }
179
180 long str_to_time(const char *str) {
181         long time;
182         
183         if(!isdigit(*str)) return -1;
184
185         time = atol(str);
186
187         while(isdigit(*str)) str++;
188         
189         return *str == 's' ? time * 1000 : time;
190 }