source: trunk/core/script.c @ 524

Revision 524, 14.0 KB checked in by reyalp, 5 years ago (diff)
  • made ubasic eat up to 100 labels or REMs in one call to ubasic_run, rather than taking 10ms each
  • made script buffer dynamic, allocated when script is loaded
  • made some other script related memory dynamic

see http://chdk.setepontos.com/index.php/topic,688.msg21646.html#msg21646 for details

  • Property svn:eol-style set to native
Line 
1#include "stdlib.h"
2#include "keyboard.h"
3#include "platform.h"
4#include "core.h"
5#include "gui.h"
6#include "gui_draw.h"
7#include "conf.h"
8#include "script.h"
9
10//-------------------------------------------------------------------
11
12#define SCRIPT_CONSOLE_NUM_LINES    5
13#define SCRIPT_CONSOLE_LINE_LENGTH  25
14#define SCRIPT_CONSOLE_X            0
15#define SCRIPT_CONSOLE_Y            (14-SCRIPT_CONSOLE_NUM_LINES)
16
17//-------------------------------------------------------------------
18const char *state_ubasic_script;
19char cfg_name[100] = "\0";
20char cfg_set_name[100] = "\0";
21
22static const char *ubasic_script_default =
23#if 0
24    "@title Default script\n"
25    "@param a Shoot count\n"
26    "@default a 2\n"
27    "@param b Step\n"
28    "@default b 3\n"
29
30    "sleep 1000\n"
31
32    "if a<1 then let a=2\n"
33    "if b<1 then let b=3\n"
34
35    "for s=1 to a\n"
36      "shoot\n"
37      "for n=1 to b\n"
38        "click \"right\"\n"
39      "next n\n"
40    "next s\n"
41    "shoot\n"
42
43    "for n=1 to a*b\n"
44      "click \"left\"\n"
45    "next n\n"
46
47    "end\n";
48#else
49    "@title Default Script\n"
50    "@param a Times to Repeat\n"
51    "@default a 5\n"
52    "@param b Display Delay\n"
53    "@default b 3\n"
54
55    "if a<1 then let a=1\n"
56    "if b<1 then let b=1\n"
57
58    "for n=1 to a\n"
59        "if n>1 then print \"*****\"\n"
60        "print \"This is a default script.\"\n"
61        "sleep 1000\n"
62        "print \"Scripts run when shutter\"\n"
63        "sleep 1000\n"
64        "print \"is pressed in ALT mode.\"\n"
65        "sleep 1000\n"
66        "print \"Press shutter to exit.\"\n"
67        "sleep b*1000\n"
68    "next n\n"
69
70    "end\n";
71#endif
72
73char script_title[36];
74char script_params[SCRIPT_NUM_PARAMS][28];
75int script_param_order[SCRIPT_NUM_PARAMS];
76char script_params_update[SCRIPT_NUM_PARAMS];
77int script_loaded_params[SCRIPT_NUM_PARAMS];
78char script_console_buf[SCRIPT_CONSOLE_NUM_LINES][SCRIPT_CONSOLE_LINE_LENGTH+1];
79static int script_console_lines=0;
80//-------------------------------------------------------------------
81static void process_title(const char *title) {
82    register const char *ptr = title;
83    register int i=0;
84
85    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
86    while (i<(sizeof(script_title)-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
87        script_title[i]=ptr[i];
88        ++i;
89    }
90    script_title[i]=0;
91}
92
93//-------------------------------------------------------------------
94static int process_param(const char *param, int update) {
95    register const char *ptr = param;
96    register int n, i=0;
97
98    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
99    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
100        n=ptr[0]-'a';
101        ptr+=2;
102        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
103                script_params_update[n] = 1;
104        while (i<(sizeof(script_params[0])-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
105                        if (update)
106                        { if (script_params[n][i]!=ptr[i]) { script_params_update[n] = 0; break; }
107                        } else script_params[n][i]=ptr[i];
108            ++i;
109        }
110                if (!update) script_params[n][i]=0;
111        n++;
112    } else n=0; // ??? else produce error message   
113    return n; // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
114}
115
116//-------------------------------------------------------------------
117static void process_default(const char *param, char update) {
118    register const char *ptr = param;
119    register int n;
120
121    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
122    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
123        n=ptr[0]-'a';
124        ptr+=2;
125                if (!update || script_params_update[n])
126        {
127                        conf.ubasic_vars[n] = strtol(ptr, NULL, 0);
128            script_loaded_params[n] = conf.ubasic_vars[n];
129        }
130    } // ??? else produce error message
131}
132
133//-------------------------------------------------------------------
134static void script_scan(const char *fn, int update_vars) {
135    register const char *ptr = state_ubasic_script;
136    register int i, j=0, n;
137    char *c;
138
139    c=strrchr(fn, '/');
140    strncpy(script_title, (c)?c+1:fn, sizeof(script_title));
141    script_title[sizeof(script_title)-1]=0;
142    for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
143        script_params[i][0]=0;
144        script_param_order[i]=0;
145    }
146
147    while (ptr[0]) {
148        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
149        if (ptr[0]=='@') {
150            if (strncmp("@title", ptr, 6)==0) {
151                ptr+=6;
152                process_title(ptr);
153            } else if (strncmp("@param", ptr, 6)==0) {
154                ptr+=6;
155                n=process_param(ptr, 0); // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
156                if (n>0 && n<=SCRIPT_NUM_PARAMS) {
157                  script_param_order[j]=n;
158                  j++;
159                }
160            } else if (update_vars && strncmp("@default", ptr, 8)==0) {
161                ptr+=8;
162                process_default(ptr, 0);
163            }
164        }
165        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
166        if (ptr[0]) ++ptr;
167    }
168
169    /*for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
170        if (script_params[i][0]) break;
171    }
172    if (i==SCRIPT_NUM_PARAMS) { // there was no @param in script
173        for (i=0; i<3; ++i) {
174            strcpy(script_params[i], "Var. ? value");
175            script_params[i][5]='a'+i;
176        }
177    }*/
178}
179
180void set_params_values_name(const char *fn, int param_set)
181{
182        int shift;
183        register char *ptr = (param_set >= 0 ? cfg_set_name : cfg_name);
184        const char *name;
185       
186        if (fn == NULL || fn[0] == 0) { ptr[0] = 0; return; }
187       
188        strncpy(ptr, SCRIPT_DATA_PATH, 100); ptr[99]=0;
189        shift = strlen(SCRIPT_DATA_PATH);
190        name = strrchr(fn, '/');
191        if (name) name++; else name=fn;
192        strncpy(ptr+shift, name, 100-shift); ptr[99]=0;
193        shift = strlen(ptr); if (shift >= 100) shift=99;
194
195        if (param_set >= 0)
196                sprintf(ptr+shift-4, "_%d\0", param_set); else
197                strcpy(ptr+shift-3, "cfg\0");
198}
199
200//-------------------------------------------------------------------
201int load_params_values(const char *fn, int update_vars, int read_param_set)
202{
203        int i, fd=-1, rcnt;
204        register const char *ptr;       
205        struct stat st;
206        char *buf;
207       
208        if (fn == NULL || fn[0] == 0) return 0;
209        if (read_param_set)
210        {
211                set_params_values_name(fn, -1);
212                // find param set
213                fd = open(cfg_name, O_RDONLY, 0777);
214                if (fd >= 0)
215                {
216                        char s[16]; // plenty for one number
217                        rcnt = read(fd, s, sizeof(s)-1);
218                        s[rcnt] = 0;
219                        close(fd);
220                        conf.script_param_set = strtol(s, NULL, 0);
221                } else conf.script_param_set = 0;
222        }
223        set_params_values_name(fn, conf.script_param_set);
224        if (!update_vars) return 0;
225       
226        // open and read file
227        if (stat(cfg_set_name,&st) != 0)
228                return 0;
229        buf=malloc(st.st_size+1);
230        if(!buf)
231                return 0;
232        fd = open(cfg_set_name, O_RDONLY, 0777);
233        if (fd < 0) {
234                free(buf);
235                return 0;
236        }
237        rcnt = read(fd, buf, st.st_size);
238        buf[rcnt] = 0;
239        close(fd);
240
241        for(i = 0; i < SCRIPT_NUM_PARAMS; ++i) script_params_update[i]=0;
242    ptr = buf;
243
244    while (ptr[0])
245        {
246        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
247        if (ptr[0]=='@')
248                {
249            if (strncmp("@param", ptr, 6) == 0)
250                        {
251                ptr+=6;
252                                process_param(ptr, 1);
253            } else if (strncmp("@default", ptr, 8)==0) {
254                ptr+=8;
255                                process_default(ptr, 1);
256            }
257        }
258        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
259        if (ptr[0]) ++ptr;
260    }
261        free(buf);
262        return 1;
263}
264
265//-------------------------------------------------------------------
266void save_params_values(int unconditional)
267{
268        int i, n, fd, changed=0;
269        char *buf,*p;
270        for(i = 0; i < SCRIPT_NUM_PARAMS; i++)
271        {
272                if (script_loaded_params[i] != conf.ubasic_vars[i]) changed++;
273                script_loaded_params[i] = conf.ubasic_vars[i];
274        }
275        if (!unconditional && !changed) return;
276
277        if (cfg_name[0] == 0) set_params_values_name(conf.script_file, -1);
278        fd = open(cfg_name, O_WRONLY|O_CREAT, 0777);
279        if (fd >= 0)
280        {
281                char s[20];
282                sprintf(s, " %d\n", conf.script_param_set);
283                write(fd, s, strlen(s));
284                close(fd);
285        }
286       
287        // open and read file
288        set_params_values_name(conf.script_file, conf.script_param_set);
289
290        buf=malloc(SCRIPT_NUM_PARAMS*(28 + 20)); // max possible params * (param description + some extra for @default etc)
291        if(!buf)
292                return;
293
294        fd = open(cfg_set_name, O_WRONLY|O_CREAT, 0777);
295        if (fd < 0) {
296                free(buf);
297                return;
298        }
299        buf[0] = 0;
300        p=buf;
301        for(n = 0; n < SCRIPT_NUM_PARAMS; ++n)
302        {
303                if (script_params[n][0] != 0)
304                {
305                        p+=sprintf(p,"@param %c %s\n@default %c %d\n",'a'+n,script_params[n],'a'+n,conf.ubasic_vars[n]);
306                }
307        }
308        write(fd, buf, strlen(buf));
309        close(fd);
310        free(buf);
311}
312
313
314
315//-------------------------------------------------------------------
316void script_load(const char *fn, int saved_params) {
317    int fd=-1, i, update_vars;
318        struct stat st;
319   
320//    save_params_values(0);
321
322    if(state_ubasic_script && state_ubasic_script != ubasic_script_default)
323        free((void *)state_ubasic_script);
324
325    state_ubasic_script = ubasic_script_default;
326    update_vars = (strcmp(fn, conf.script_file) != 0) || !saved_params || (saved_params == 2);  // update if new file
327
328    if (!fn[0]) { // load internal script
329        if (!conf.script_file[0]) { // internal script was used last time
330            fd = open(SCRIPT_DEFAULT_FILENAME, O_RDONLY, 0777);
331            if (fd>=0) {
332                fn = SCRIPT_DEFAULT_FILENAME;
333                update_vars = 1;
334            }
335        }
336    } else {
337        fd = open(fn, O_RDONLY, 0777);
338        if (fd<0) {
339            conf.script_file[0]=0;
340            update_vars = 1;
341        }
342    }
343    // zero size = default script
344    if(stat(fn,&st) != 0 || st.st_size == 0) {
345        conf.script_file[0]=0;
346        update_vars = 1;
347        if(fd > 0) {
348            close(fd);
349            fd=-1;
350        }
351    }
352    if (fd>=0){
353        int rcnt;
354        char *buf;
355
356        buf = malloc(st.st_size+1);
357        if(!buf) {
358            close(fd);
359            return;
360        }
361
362        // TODO we could process the script here to reduce size
363        // or compile for lua
364        rcnt = read(fd, buf, st.st_size);
365        if (rcnt > 0){
366            buf[rcnt] = 0;
367            state_ubasic_script = buf;
368            strcpy(conf.script_file, fn);
369        }
370        else {
371            free(buf);
372        }
373        close(fd);
374    }
375
376    if (update_vars) {
377        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
378            conf.ubasic_vars[i] = 0;
379            script_loaded_params[i] = 0;
380        }
381    }
382    script_scan(conf.script_file, update_vars);
383    if (saved_params)
384        load_params_values(conf.script_file, update_vars, (saved_params!=2));   
385    gui_update_script_submenu();
386}
387
388//-------------------------------------------------------------------
389void script_console_clear() {
390    register int i;
391
392    for (i=0; i<SCRIPT_CONSOLE_NUM_LINES; ++i) {
393        script_console_buf[i][0]=0;
394    }
395    script_console_lines=0;
396    draw_restore();
397}
398
399//-------------------------------------------------------------------
400void script_console_draw() {
401    register int i, l;
402    static char buf[8];
403
404    for (i=0; i<script_console_lines; ++i) {
405        l=strlen(script_console_buf[i]);
406        draw_txt_string(SCRIPT_CONSOLE_X, SCRIPT_CONSOLE_Y+SCRIPT_CONSOLE_NUM_LINES-script_console_lines+i, script_console_buf[i], MAKE_COLOR(COLOR_BG, COLOR_FG));
407        for (; l<SCRIPT_CONSOLE_LINE_LENGTH; ++l)
408            draw_txt_char(SCRIPT_CONSOLE_X+l, SCRIPT_CONSOLE_Y+SCRIPT_CONSOLE_NUM_LINES-script_console_lines+i, ' ', MAKE_COLOR(COLOR_BG, COLOR_FG));
409    }
410
411}
412
413static int  print_screen_p;             // print_screen predicate: 0-off 1-on.
414static int  print_screen_d = -1;        // print_screen file descriptor.
415//static const char print_screen_file[] ="A/CHDK/SCRIPTS/PR_SCREEN.TXT";
416static const char print_screen_file_prefix[] = "A/CHDK/LOGS/LOG_";
417char print_screen_file[25];
418static const char extension_txt[] = ".TXT";
419
420void script_print_screen_init()
421{
422  print_screen_p = 0;
423  if (print_screen_d >= 0) {
424    close(print_screen_d);
425    print_screen_d = -1;
426  }
427}
428
429void script_print_screen_end()
430{
431  if (print_screen_d >= 0) {
432    close(print_screen_d);
433    print_screen_d = -1;
434    print_screen_p = 0;
435  }
436}
437
438void script_print_screen_statement(int val)
439{
440  print_screen_p = val;
441  if (val) {
442    if (print_screen_d>=0) close(print_screen_d);
443    int i=0;
444    int c=0;
445    static char file_number[5];
446    strcpy(print_screen_file, print_screen_file_prefix);
447    if (val<0) val = -val;
448    while (val > 9999) val += -10000;
449    for (i=10; i<=1000; i=i*10) { if (val<i) ++c; }
450    for (i=1; i<=c; ++i) { sprintf(file_number, "%d", 0); strcat(print_screen_file, file_number); }
451    sprintf(file_number, "%d", val);
452    strcat(print_screen_file, file_number);
453    strcat(print_screen_file, extension_txt);
454    print_screen_d = open(print_screen_file, O_WRONLY|O_CREAT|O_TRUNC, 0777);
455  }
456}
457
458//-------------------------------------------------------------------
459
460static void script_console_add_impl(const char *str) {
461    register int i;
462
463    if (script_console_lines == SCRIPT_CONSOLE_NUM_LINES ) {
464        for (i=1; i<SCRIPT_CONSOLE_NUM_LINES; ++i) {
465            strcpy(script_console_buf[i-1], script_console_buf[i]);
466        }
467        --script_console_lines;
468    }
469
470    if (strlen(str) > SCRIPT_CONSOLE_LINE_LENGTH) {
471      // let overlong lines wrap to the next line
472      memcpy(script_console_buf[script_console_lines], str, SCRIPT_CONSOLE_LINE_LENGTH);
473      script_console_buf[script_console_lines][SCRIPT_CONSOLE_LINE_LENGTH]=0;
474      ++script_console_lines;
475      script_console_add_impl(str+SCRIPT_CONSOLE_LINE_LENGTH);
476      return;
477    }
478    else
479      strcpy(script_console_buf[script_console_lines], str);
480   
481    ++script_console_lines;
482}
483
484void script_console_add_line(const char *str) {
485    script_console_add_impl(str);
486
487    if (print_screen_p && print_screen_d>=0) {
488      char nl = '\n';
489      write(print_screen_d, str, strlen(str) );
490      write(print_screen_d, &nl, 1);
491    }
492
493    script_console_draw();
494}
495
496//-------------------------------------------------------------------
497//-------------------------------------------------------------------
498//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.