LMMS
Loading...
Searching...
No Matches
ports.cpp
Go to the documentation of this file.
1#include "../ports.h"
2#include "../rtosc.h"
3#include "../pretty-format.h"
4
5#include <cinttypes>
6#include <ostream>
7#include <cassert>
8#include <limits>
9#include <cstring>
10#include <string>
11
12/* Compatibility with non-clang compilers */
13#ifndef __has_feature
14# define __has_feature(x) 0
15#endif
16#ifndef __has_extension
17# define __has_extension __has_feature
18#endif
19
20/* Check for C++11 support */
21#if defined(HAVE_CPP11_SUPPORT)
22# if HAVE_CPP11_SUPPORT
23# define DISTRHO_PROPER_CPP11_SUPPORT
24# endif
25#elif __cplusplus >= 201103L || (defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405) || __has_extension(cxx_noexcept)
26# define DISTRHO_PROPER_CPP11_SUPPORT
27# if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) < 407 && ! defined(__clang__)) || (defined(__clang__) && ! __has_extension(cxx_override_control))
28# define override // gcc4.7+ only
29# define final // gcc4.7+ only
30# endif
31#endif
32
33using namespace rtosc;
34
35static inline void scat(char *dest, const char *src)
36{
37 while(*dest) dest++;
38 while(*src && *src!=':') *dest++ = *src++;
39 *dest = 0;
40}
41
44{
45 for(int i=0; i<(int)(sizeof(idx)/sizeof(int)); ++i)
46 idx[i] = 0;
47}
48
49void RtData::push_index(int ind)
50{
51 for(int i=1; i<(int)(sizeof(idx)/sizeof(int)); ++i)
52 idx[i] = idx[i-1];
53 idx[0] = ind;
54}
55
57{
58 int n = sizeof(idx)/sizeof(int);
59 for(int i=n-2; i >= 0; --i)
60 idx[i] = idx[i+1];
61 idx[n-1] = 0;
62}
63
64void RtData::replyArray(const char *path, const char *args,
65 rtosc_arg_t *vals)
66{
67 (void) path;
68 (void) args;
69 (void) vals;
70}
71void RtData::reply(const char *path, const char *args, ...)
72{
73 va_list va;
74 va_start(va,args);
75 char buffer[1024];
76 rtosc_vmessage(buffer,1024,path,args,va);
77 reply(buffer);
78 va_end(va);
79}
80void RtData::reply(const char *msg)
81{(void)msg;}
82void RtData::chain(const char *path, const char *args, ...)
83{
84 (void) path;
85 (void) args;
86}
87
88void RtData::chain(const char *msg)
89{
90 (void) msg;
91}
92void RtData::chainArray(const char *path, const char *args,
93 rtosc_arg_t *vals)
94{
95 (void) path;
96 (void) args;
97 (void) vals;
98};
99void RtData::broadcast(const char *path, const char *args, ...)
100{
101 va_list va;
102 va_start(va,args);
103 char buffer[1024];
104 rtosc_vmessage(buffer,1024,path,args,va);
105 broadcast(buffer);
106 va_end(va);
107}
108void RtData::broadcast(const char *msg)
109{reply(msg);};
110void RtData::broadcastArray(const char *path, const char *args,
111 rtosc_arg_t *vals)
112{
113 (void) path;
114 (void) args;
115 (void) vals;
116}
117
118void RtData::forward(const char *rational)
119{
120 (void) rational;
121}
122
123void metaiterator_advance(const char *&title, const char *&value)
124{
125 if(!title || !*title) {
126 value = NULL;
127 return;
128 }
129
130 //Try to find "\0=" after title string
131 value = title;
132 while(*value)
133 ++value;
134 if(*++value != '=')
135 value = NULL;
136 else
137 value++;
138}
139
145
147{
148 if(!title || !*title) {
149 title = NULL;
150 return *this;
151 }
152 //search for next parameter start
153 //aka "\0:" unless "\0\0" is seen
154 char prev = 0;
155 while(prev || (*title && *title != ':'))
156 prev = *title++;
157
158 if(!*title)
159 title = NULL;
160 else
161 ++title;
162
164 return *this;
165}
166
167Port::MetaIterator::operator bool(void) const
168{
169 return title;
170}
171
173:str_ptr(str_)
174{}
175
177{
178 if(str_ptr && *str_ptr == ':')
179 return Port::MetaIterator(str_ptr+1);
180 else
182}
183
188
190{
191 for(const auto x : *this)
192 if(!strcmp(x.title, str))
193 return x;
194 return NULL;
195}
196
198{
199 if(!str_ptr || !*str_ptr)
200 return 0;
201 char prev = 0;
202 const char *itr = str_ptr;
203 while(prev || *itr)
204 prev = *itr++;
205 return 2+(itr-str_ptr);
206}
207
208const char *Port::MetaContainer::operator[](const char *str) const
209{
210 for(const auto x : *this)
211 if(!strcmp(x.title, str))
212 return x.value;
213 return NULL;
214}
215//Match the arg string or fail
216inline bool arg_matcher(const char *pattern, const char *args)
217{
218 //match anything if now arg restriction is present (ie the ':')
219 if(*pattern++ != ':')
220 return true;
221
222 const char *arg_str = args;
223 bool arg_match = *pattern || *pattern == *arg_str;
224
225 while(*pattern && *pattern != ':')
226 arg_match &= (*pattern++==*arg_str++);
227
228 if(*pattern==':') {
229 if(arg_match && !*arg_str)
230 return true;
231 else
232 return arg_matcher(pattern, args); //retry
233 }
234
235 return arg_match;
236}
237
238inline bool scmp(const char *a, const char *b)
239{
240 while(*a && *a == *b) a++, b++;
241 return a[0] == b[0];
242}
243
244typedef std::vector<std::string> words_t;
245typedef std::vector<std::string> svec_t;
246typedef std::vector<const char *> cvec_t;
247typedef std::vector<int> ivec_t;
248typedef std::vector<int> tuple_t;
249typedef std::vector<tuple_t> tvec_t;
250
251namespace rtosc{
253{
254 public:
255 bool *enump;
261
262 bool rtosc_match_args(const char *pattern, const char *msg)
263 {
264 //match anything if no arg restriction is present
265 //(ie the ':')
266 if(*pattern++ != ':')
267 return true;
268
269 const char *arg_str = rtosc_argument_string(msg);
270 bool arg_match = *pattern || *pattern == *arg_str;
271
272 while(*pattern && *pattern != ':')
273 arg_match &= (*pattern++==*arg_str++);
274
275 if(*pattern==':') {
276 if(arg_match && !*arg_str)
277 return true;
278 else
279 return rtosc_match_args(pattern, msg); //retry
280 }
281
282 return arg_match;
283 }
284
285 bool hard_match(int i, const char *msg)
286 {
287 if(strncmp(msg, fixed[i].c_str(), fixed[i].length()))
288 return false;
289 if(arg_spec[i])
290 return rtosc_match_args(arg_spec[i], msg);
291 else
292 return true;
293 }
294};
295
296}
297
298
299tvec_t do_hash(const words_t &strs, const ivec_t &pos)
300{
301 tvec_t tvec;
302 for(auto &s:strs) {
303 tuple_t tuple;
304 tuple.push_back(s.length());
305 for(const auto &p:pos)
306 if(p < (int)s.size())
307 tuple.push_back(s[p]);
308 tvec.push_back(std::move(tuple));
309 }
310 return tvec;
311}
312
313template<class T>
314int count_dups(std::vector<T> &t)
315{
316 int dups = 0;
317 int N = t.size();
318 bool mark[t.size()];
319 memset(mark, 0, N);
320 for(int i=0; i<N; ++i) {
321 if(mark[i])
322 continue;
323 for(int j=i+1; j<N; ++j) {
324 if(t[i] == t[j]) {
325 dups++;
326 mark[j] = true;
327 }
328 }
329 }
330 return dups;
331}
332
333template<class T, class Z>
334bool has(T &t, Z&z)
335{
336 for(auto tt:t)
337 if(tt==z)
338 return true;
339 return false;
340}
341
342static int int_max(int a, int b) { return a<b?b:a;}
343
345{
346 ivec_t pos;
347 int current_dups = strs.size();
348 int N = 0;
349 for(auto w:strs)
350 N = int_max(N,w.length());
351
352 int pos_best = -1;
353 int pos_best_val = std::numeric_limits<int>::max();
354 while(true)
355 {
356 for(int i=0; i<N; ++i) {
357 ivec_t npos = pos;
358 if(has(pos, i))
359 continue;
360 npos.push_back(i);
361 auto hashed = do_hash(strs, npos);
362 int d = count_dups(hashed);
363 if(d < pos_best_val) {
364 pos_best_val = d;
365 pos_best = i;
366 }
367 }
368 if(pos_best_val >= current_dups)
369 break;
370 current_dups = pos_best_val;
371 pos.push_back(pos_best);
372 }
373 auto hashed = do_hash(strs, pos);
374 int d = count_dups(hashed);
375 //printf("Total Dups: %d\n", d);
376 if(d != 0)
377 pos.clear();
378 return pos;
379}
380
381static ivec_t do_hash(const words_t &strs, const ivec_t &pos, const ivec_t &assoc)
382{
383 ivec_t ivec;
384 ivec.reserve(strs.size());
385 for(auto &s:strs) {
386 int t = s.length();
387 for(auto p:pos)
388 if(p < (int)s.size())
389 t += assoc[s[p]];
390 ivec.push_back(t);
391 }
392 return ivec;
393}
394
395static ivec_t find_assoc(const words_t &strs, const ivec_t &pos)
396{
397 ivec_t assoc;
398 int current_dups = strs.size();
399 int N = 127;
400 std::vector<char> useful_chars;
401 for(auto w:strs)
402 for(auto c:w)
403 if(!has(useful_chars, c))
404 useful_chars.push_back(c);
405
406 for(int i=0; i<N; ++i)
407 assoc.push_back(0);
408
409 int assoc_best = -1;
410 int assoc_best_val = std::numeric_limits<int>::max();;
411 for(int k=0; k<4; ++k)
412 {
413 for(int i:useful_chars) {
414 assoc_best_val = std::numeric_limits<int>::max();
415 for(int j=0; j<100; ++j) {
416 //printf(".");
417 assoc[i] = j;
418 auto hashed = do_hash(strs, pos, assoc);
419 //for(int i=0; i<hashed.size(); ++i)
420 // printf("%d ", hashed[i]);
421 //printf("\n");
422 int d = count_dups(hashed);
423 //printf("dup %d\n",d);
424 if(d < assoc_best_val) {
425 assoc_best_val = d;
426 assoc_best = j;
427 }
428 }
429 assoc[i] = assoc_best;
430 }
431 if(assoc_best_val >= current_dups)
432 break;
433 current_dups = assoc_best_val;
434 }
435 auto hashed = do_hash(strs, pos, assoc);
436 //int d = count_dups(hashed);
437 //printf("Total Dups Assoc: %d\n", d);
438 return assoc;
439}
440
441static ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
442{
443 ivec_t remap;
444 auto hashed = do_hash(strs, pos, assoc);
445 //for(int i=0; i<strs.size(); ++i)
446 // printf("%d) '%s'\n", hashed[i], strs[i].c_str());
447 int N = 0;
448 for(auto h:hashed)
449 N = int_max(N,h+1);
450 for(int i=0; i<N; ++i)
451 remap.push_back(0);
452 for(int i=0; i<(int)hashed.size(); ++i)
453 remap[hashed[i]] = i;
454
455 return remap;
456}
457
458static void generate_minimal_hash(std::vector<std::string> str, Port_Matcher &pm)
459{
460 if(str.empty())
461 return;
462 pm.pos = find_pos(str);
463 if(pm.pos.empty()) {
464 fprintf(stderr, "rtosc: Failed to generate minimal hash\n");
465 return;
466 }
467 pm.assoc = find_assoc(str, pm.pos);
468 pm.remap = find_remap(str, pm.pos, pm.assoc);
469}
470
472{
473 svec_t keys;
474 cvec_t args;
475
476 bool enump = false;
477 for(unsigned i=0; i<p.ports.size(); ++i)
478 if(strchr(p.ports[i].name, '#'))
479 enump = true;
480 if(enump)
481 return;
482 for(unsigned i=0; i<p.ports.size(); ++i)
483 {
484 std::string tmp = p.ports[i].name;
485 const char *arg = NULL;
486 int idx = tmp.find(':');
487 if(idx > 0) {
488 arg = p.ports[i].name+idx;
489 tmp = tmp.substr(0,idx);
490 }
491 keys.push_back(tmp);
492 args.push_back(arg);
493
494 }
495 pm.fixed = keys;
496 pm.arg_spec = args;
497
498 generate_minimal_hash(keys, pm);
499}
500
501Ports::Ports(std::initializer_list<Port> l)
502 :ports(l), impl(NULL)
503{
504 refreshMagic();
505}
506
508{
509 delete []impl->enump;
510 delete impl;
511}
512
513#if !defined(__GNUC__)
514#define __builtin_expect(a,b) a
515#endif
516
517void Ports::dispatch(const char *m, rtosc::RtData &d, bool base_dispatch) const
518{
519 if(!strcmp(m, "pointer"))
520 {
521 // rRecur*Cb have already set d.loc to the pointer we need,
522 // so we just return
523 return;
524 }
525
526 void *obj = d.obj;
527
528 //handle the first dispatch layer
529 if(base_dispatch) {
530 d.matches = 0;
531 d.message = m;
532 if(m && *m == '/')
533 m++;
534 if(d.loc)
535 d.loc[0] = 0;
536 }
537
538 //simple case
539 if(!d.loc || !d.loc_size) {
540 for(const Port &port: ports) {
541 if(rtosc_match(port.name,m, NULL))
542 d.port = &port, port.cb(m,d), d.obj = obj;
543 }
544 } else {
545
546 //TODO this function is certainly buggy at the moment, some tests
547 //are needed to make it clean
548 //XXX buffer_size is not properly handled yet
549 if(__builtin_expect(d.loc[0] == 0, 0)) {
550 memset(d.loc, 0, d.loc_size);
551 d.loc[0] = '/';
552 }
553
554 char *old_end = d.loc;
555 while(*old_end) ++old_end;
556
557 if(impl->pos.empty()) { //No perfect minimal hash function
558 for(unsigned i=0; i<elms; ++i) {
559 const Port &port = ports[i];
560 const char* m_end;
561 if(!rtosc_match(port.name, m, &m_end))
562 continue;
563 if(!port.ports)
564 d.matches++;
565
566 //Append the path
567 if(strchr(port.name,'#')) {
568 const char *msg = m;
569 char *pos = old_end;
570 while(*msg && msg != m_end)
571 *pos++ = *msg++;
572 *pos = '\0';
573 } else
574 scat(d.loc, port.name);
575
576 d.port = &port;
577
578 //Apply callback
579 port.cb(m,d), d.obj = obj;
580
581 //Remove the rest of the path
582 char *tmp = old_end;
583 while(*tmp) *tmp++=0;
584 }
585 } else {
586
587 //Define string to be hashed
588 unsigned len=0;
589 const char *tmp = m;
590
591 while(*tmp && *tmp != '/')
592 tmp++;
593 if(*tmp == '/')
594 tmp++;
595 len = tmp-m;
596
597 //Compute the hash
598 int t = len;
599 for(auto p:impl->pos)
600 if(p < (int)len)
601 t += impl->assoc[m[p]];
602 if(t >= (int)impl->remap.size() && !default_handler)
603 return;
604 else if(t >= (int)impl->remap.size() && default_handler) {
605 d.matches++;
606 default_handler(m,d), d.obj = obj;
607 return;
608 }
609
610 int port_num = impl->remap[t];
611
612 //Verify the chosen port is correct
613 if(__builtin_expect(impl->hard_match(port_num, m), 1)) {
614 const Port &port = ports[impl->remap[t]];
615 if(!port.ports)
616 d.matches++;
617
618 //Append the path
619 if(impl->enump[port_num]) {
620 const char *msg = m;
621 char *pos = old_end;
622 while(*msg && *msg != '/')
623 *pos++ = *msg++;
624 if(strchr(port.name, '/'))
625 *pos++ = '/';
626 *pos = '\0';
627 } else
628 memcpy(old_end, impl->fixed[port_num].c_str(),
629 impl->fixed[port_num].length()+1);
630
631 d.port = &port;
632
633 //Apply callback
634 port.cb(m,d), d.obj = obj;
635
636 //Remove the rest of the path
637 old_end[0] = '\0';
638 } else if(default_handler) {
639 d.matches++;
640 default_handler(m,d), d.obj = obj;
641 }
642 }
643 }
644}
645
646/*
647 * Returning values from runtime
648 */
649
652class CapturePretty : public RtData
653{
654 char* buffer;
655 std::size_t buffersize;
657
658 void reply(const char *) override { assert(false); }
659
660/* void replyArray(const char*, const char *args,
661 rtosc_arg_t *vals)
662 {
663 size_t cur_idx = 0;
664 for(const char* ptr = args; *ptr; ++ptr, ++cur_idx)
665 {
666 assert(cur_idx < max_args);
667 arg_vals[cur_idx].type = *ptr;
668 arg_vals[cur_idx].val = vals[cur_idx];
669 }
670
671 // TODO: refactor code, also with Capture ?
672 size_t wrt = rtosc_print_arg_vals(arg_vals, cur_idx,
673 buffer, buffersize, NULL,
674 cols_used);
675 assert(wrt);
676 }*/
677
678 void reply(const char *, const char *args, ...) override
679 {
680 va_list va;
681 va_start(va,args);
682
683 size_t nargs = strlen(args);
684 rtosc_arg_val_t arg_vals[nargs];
685
686 rtosc_v2argvals(arg_vals, nargs, args, va);
687
688 size_t wrt = rtosc_print_arg_vals(arg_vals, nargs,
690 cols_used);
691 (void) wrt;
692 va_end(va);
693 assert(wrt);
694 }
695
696public:
698 const char* value() const { return buffer; }
701};
702
710static const char* get_value_from_runtime(void* runtime,
711 const Ports& ports,
712 size_t loc_size,
713 char* loc,
714 char* buffer_with_port,
715 std::size_t buffersize,
716 int cols_used)
717{
718 std::size_t addr_len = strlen(buffer_with_port);
719
720 // use the port buffer to print the result, but do not overwrite the
721 // port name
722 CapturePretty d(buffer_with_port + addr_len, buffersize - addr_len,
723 cols_used);
724 d.obj = runtime;
725 d.loc_size = loc_size;
726 d.loc = loc;
727 d.matches = 0;
728
729 // does the message at least fit the arguments?
730 assert(buffersize - addr_len >= 8);
731 // append type
732 memset(buffer_with_port + addr_len, 0, 8); // cover string end and arguments
733 buffer_with_port[addr_len + (4-addr_len%4)] = ',';
734
735 d.message = buffer_with_port;
736
737 // buffer_with_port is a message in this call:
738 ports.dispatch(buffer_with_port, d, false);
739
740 return d.value();
741}
742
744class Capture : public RtData
745{
746 size_t max_args;
748 int nargs;
749
750 void chain(const char *path, const char *args, ...) override
751 {
752 nargs = 0;
753 }
754
755 void chain(const char *msg) override
756 {
757 nargs = 0;
758 }
759
760 void reply(const char *) override { assert(false); }
761
762 void replyArray(const char*, const char *args,
763 rtosc_arg_t *vals) override
764 {
765 size_t cur_idx = 0;
766 for(const char* ptr = args; *ptr; ++ptr, ++cur_idx)
767 {
768 assert(cur_idx < max_args);
769 arg_vals[cur_idx].type = *ptr;
770 arg_vals[cur_idx].val = vals[cur_idx];
771 }
772 nargs = cur_idx;
773 }
774
775 void reply(const char *, const char *args, ...) override
776 {
777 va_list va;
778 va_start(va,args);
779
780 nargs = strlen(args);
781 assert((size_t)nargs <= max_args);
782
783 rtosc_v2argvals(arg_vals, nargs, args, va);
784
785 va_end(va);
786 }
787public:
789 int size() const { return nargs; }
792};
793
812static size_t get_value_from_runtime(void* runtime,
813 const Port& port,
814 size_t loc_size,
815 char* loc,
816 const char* portname_from_base,
817 char* buffer_with_port,
818 std::size_t buffersize,
819 std::size_t max_args,
820 rtosc_arg_val_t* arg_vals)
821{
822 strncpy(buffer_with_port, portname_from_base, buffersize);
823 std::size_t addr_len = strlen(buffer_with_port);
824
825 Capture d(max_args, arg_vals);
826 d.obj = runtime;
827 d.loc_size = loc_size;
828 d.loc = loc;
829 d.port = &port;
830 d.matches = 0;
831 assert(*loc);
832
833 // does the message at least fit the arguments?
834 assert(buffersize - addr_len >= 8);
835 // append type
836 memset(buffer_with_port + addr_len, 0, 8); // cover string end and arguments
837 buffer_with_port[addr_len + (4-addr_len%4)] = ',';
838
839 // TODO? code duplication
840
841 // buffer_with_port is a message in this call:
842 d.message = buffer_with_port;
843 port.cb(buffer_with_port, d);
844
845 assert(d.size() >= 0);
846 return d.size();
847}
848
849/*
850 * default values
851 */
852
853const char* rtosc::get_default_value(const char* port_name, const Ports& ports,
854 void* runtime, const Port* port_hint,
855 int32_t idx, int recursive)
856{
857 constexpr std::size_t buffersize = 1024;
858 char buffer[buffersize];
859 char loc[buffersize] = "";
860
861 assert(recursive >= 0); // forbid recursing twice
862
863 char default_annotation[20] = "default";
864// if(idx > 0)
865// snprintf(default_annotation + 7, 13, "[%" PRId32 "]", idx);
866 const char* const dependent_annotation = "default depends";
867 const char* return_value = nullptr;
868
869 if(!port_hint)
870 port_hint = ports.apropos(port_name);
871 assert(port_hint); // port must be found
872 const Port::MetaContainer metadata = port_hint->meta();
873
874 // Let complex cases depend upon a marker variable
875 // If the runtime is available the exact preset number can be found
876 // This generalizes to envelope types nicely if envelopes have a read
877 // only port which indicates if they're amplitude/frequency/etc
878 const char* dependent = metadata[dependent_annotation];
879 if(dependent)
880 {
881 char* dependent_port = buffer;
882 *dependent_port = 0;
883
884 assert(strlen(port_name) + strlen(dependent_port) + 5 < buffersize);
885 strncat(dependent_port, port_name,
886 buffersize - strlen(dependent_port) - 1);
887 strncat(dependent_port, "/../",
888 buffersize - strlen(dependent_port) - 1);
889 strncat(dependent_port, dependent,
890 buffersize - strlen(dependent_port) - 1);
891 dependent_port = Ports::collapsePath(dependent_port);
892
893 // TODO: collapsePath bug?
894 // Relative paths should not start with a slash after collapsing ...
895 if(*dependent_port == '/')
896 ++dependent_port;
897
898 const char* dependent_value =
899 runtime
900 ? get_value_from_runtime(runtime, ports,
901 buffersize, loc,
902 dependent_port,
903 buffersize-1, 0)
904 : get_default_value(dependent_port, ports,
905 runtime, NULL, recursive-1);
906
907 assert(strlen(dependent_value) < 16); // must be an int
908
909 char* default_variant = buffer;
910 *default_variant = 0;
911 assert(strlen(default_annotation) + 1 + 16 < buffersize);
912 strncat(default_variant, default_annotation,
913 buffersize - strlen(default_variant));
914 strncat(default_variant, " ", buffersize - strlen(default_variant));
915 strncat(default_variant, dependent_value,
916 buffersize - strlen(default_variant));
917
918 return_value = metadata[default_variant];
919 }
920
921 // If return_value is NULL, this can have two meanings:
922 // 1. there was no depedent annotation
923 // => check for a direct (non-dependent) default value
924 // (a non existing direct default value is OK)
925 // 2. there was a dependent annotation, but the dependent value has no
926 // mapping (mapping for default_variant was NULL)
927 // => check for the direct default value, which acts as a default
928 // mapping for all presets; a missing default value indicates an
929 // error in the metadata
930 if(!return_value)
931 {
932 return_value = metadata[default_annotation];
933 assert(!dependent || return_value);
934 }
935
936 return return_value;
937}
938
940 const char* port_args,
942{
943 const char* first = port_args;
944 int errors_found = 0;
945
946 for( ; *first && (*first == ':' || *first == '[' || *first == ']');
947 ++first) ;
948
949 for(size_t i = 0; i < n; ++i, ++first, ++av)
950 {
951 for( ; *first && (*first == '[' || *first == ']'); ++first) ;
952
953 if(!*first || *first == ':')
954 {
955 // (n-i) arguments left, but we have no recipe to convert them
956 return n-i;
957 }
958
959 if(av->type == 'S' && *first == 'i')
960 {
961 int val = enum_key(meta, av->val.s);
962 if(val == std::numeric_limits<int>::min())
963 ++errors_found;
964 else
965 {
966 av->type = 'i';
967 av->val.i = val;
968 }
969 }
970 }
971 return errors_found;
972}
973
976{
977 char mapbuf[20] = "map ";
978
979 for(size_t i = 0; i < n; ++i, ++av)
980 {
981 if(av->type == 'i')
982 {
983 snprintf(mapbuf + 4, 16, "%d", av->val.i);
984 const char* val = meta[mapbuf];
985 if(val)
986 {
987 av->type = 'S';
988 av->val.s = val;
989 }
990 }
991 }
992}
993
994int rtosc::get_default_value(const char* port_name, const char* port_args,
995 const Ports& ports,
996 void* runtime, const Port* port_hint,
997 int32_t idx,
998 size_t n, rtosc_arg_val_t* res,
999 char* strbuf, size_t strbufsize)
1000{
1001 const char* pretty = get_default_value(port_name, ports, runtime, port_hint,
1002 idx, 0);
1003
1004 int nargs;
1005 if(pretty)
1006 {
1007 nargs = rtosc_count_printed_arg_vals(pretty);
1008 assert(nargs > 0); // parse error => error in the metadata?
1009 assert((size_t)nargs < n);
1010
1011 rtosc_scan_arg_vals(pretty, res, nargs, strbuf, strbufsize);
1012
1013 {
1014 int errs_found = canonicalize_arg_vals(res,
1015 nargs,
1016 port_args,
1017 port_hint->meta());
1018 if(errs_found)
1019 fprintf(stderr, "Could not canonicalize %s\n", pretty);
1020 assert(!errs_found); // error in the metadata?
1021 }
1022 }
1023 else
1024 nargs = -1;
1025
1026 return nargs;
1027}
1028
1029std::string rtosc::get_changed_values(const Ports& ports, void* runtime)
1030{
1031 std::string res;
1032 constexpr std::size_t buffersize = 1024;
1033 char port_buffer[buffersize];
1034 memset(port_buffer, 0, buffersize); // requirement for walk_ports
1035
1036 const size_t max_arg_vals = 256;
1037
1038 auto on_reach_port =
1039 [](const Port* p, const char* port_buffer,
1040 const char* port_from_base, const Ports& base,
1041 void* data, void* runtime)
1042 {
1043 assert(runtime);
1044 const Port::MetaContainer meta = p->meta();
1045
1046 if((p->name[strlen(p->name)-1] != ':' && !strstr(p->name, "::"))
1047 || meta.find("parameter") == meta.end())
1048 {
1049 // runtime information can not be retrieved,
1050 // thus, it can not be compared with the default value
1051 return;
1052 }
1053
1054 char loc[buffersize] = "";
1055 rtosc_arg_val_t arg_vals_default[max_arg_vals];
1056 rtosc_arg_val_t arg_vals_runtime[max_arg_vals];
1057 char buffer_with_port[buffersize];
1058 char cur_value_pretty[buffersize] = " ";
1059 char strbuf[buffersize]; // temporary string buffer for pretty-printing
1060
1061 std::string* res = (std::string*)data;
1062 assert(strlen(port_buffer) + 1 < buffersize);
1063 strncpy(loc, port_buffer, buffersize); // TODO: +-1?
1064
1065 strncpy(buffer_with_port, port_from_base, buffersize);
1066 const char* portargs = strchr(p->name, ':');
1067 if(!portargs)
1068 portargs = p->name + strlen(p->name);
1069
1070#if 0 // debugging stuff
1071 if(!strncmp(port_buffer, "/part1/Penabled", 5) &&
1072 !strncmp(port_buffer+6, "/Penabled", 9))
1073 {
1074 printf("runtime: %ld\n", (long int)runtime);
1075 }
1076#endif
1077// TODO: p->name: duplicate to p
1078 int nargs_default = get_default_value(p->name,
1079 portargs,
1080 base,
1081 runtime,
1082 p,
1083 -1,
1084 max_arg_vals,
1085 arg_vals_default,
1086 strbuf,
1087 buffersize);
1088 size_t nargs_runtime = get_value_from_runtime(runtime,
1089 *p,
1090 buffersize, loc,
1091 port_from_base,
1092 buffer_with_port,
1093 buffersize,
1094 max_arg_vals,
1095 arg_vals_runtime);
1096
1097 if(nargs_default == (int) nargs_runtime)
1098 {
1099 canonicalize_arg_vals(arg_vals_default, nargs_default,
1100 strchr(p->name, ':'), meta);
1101 if(!rtosc_arg_vals_eq(arg_vals_default,
1102 arg_vals_runtime,
1103 nargs_default,
1104 nargs_runtime,
1105 NULL))
1106 {
1107 map_arg_vals(arg_vals_runtime, nargs_runtime, meta);
1108 rtosc_print_arg_vals(arg_vals_runtime, nargs_runtime,
1109 cur_value_pretty + 1, buffersize - 1,
1110 NULL, strlen(port_buffer) + 1);
1111
1112 *res += port_buffer;
1113 *res += cur_value_pretty;
1114 *res += "\n";
1115 }
1116 }
1117 };
1118
1119 walk_ports(&ports, port_buffer, buffersize, &res, on_reach_port,
1120 runtime);
1121
1122 if(res.length()) // remove trailing newline
1123 res.resize(res.length()-1);
1124 return res;
1125}
1126
1128{
1129 *loc = 0;
1130 RtData d;
1131 d.obj = runtime;
1132 d.loc = loc; // we're always dispatching at the base
1133 d.loc_size = 1024;
1134 ports->dispatch(msg, d, true);
1135}
1136
1138 bool first_round,
1140 dependency)
1141{
1142 // default implementation:
1143 // no dependencies => round 0,
1144 // has dependencies => round 1,
1145 // not specified => both rounds
1146 return (dependency == not_specified
1147 || !(dependency ^ first_round))
1148 ? nargs // argument number is not changed
1149 : (int)discard;
1150}
1151
1153 size_t, size_t nargs,
1155 bool round2,
1156 dependency_t dependency)
1157{
1158 return default_response(nargs, round2, dependency);
1159}
1160
1161int rtosc::dispatch_printed_messages(const char* messages,
1162 const Ports& ports, void* runtime,
1164{
1165 constexpr std::size_t buffersize = 1024;
1166 char portname[buffersize], message[buffersize], strbuf[buffersize];
1167 int rd, rd_total = 0;
1168 int nargs;
1169 int msgs_read = 0;
1170
1171 savefile_dispatcher_t dummy_dispatcher;
1172 if(!dispatcher)
1173 dispatcher = &dummy_dispatcher;
1174 dispatcher->ports = &ports;
1175 dispatcher->runtime = runtime;
1176
1177 // scan all messages twice:
1178 // * in the second round, only dispatch those with ports that depend on
1179 // other ports
1180 // * in the first round, only dispatch all others
1181 for(int round = 0; round < 2 && msgs_read >= 0; ++round)
1182 {
1183 msgs_read = 0;
1184 rd_total = 0;
1185 const char* msg_ptr = messages;
1186 while(*msg_ptr && (msgs_read >= 0))
1187 {
1188 nargs = rtosc_count_printed_arg_vals_of_msg(msg_ptr);
1189 if(nargs >= 0)
1190 {
1191 // 16 is usually too much, but it allows the user to add
1192 // arguments if necessary
1193 size_t maxargs = 16;
1194 rtosc_arg_val_t arg_vals[maxargs];
1195 rd = rtosc_scan_message(msg_ptr, portname, buffersize,
1196 arg_vals, nargs, strbuf, buffersize);
1197 rd_total += rd;
1198
1199 const Port* port = ports.apropos(portname);
1202 (port
1203 ? !!port->meta()["default depends"]
1205
1206 // let the user modify the message and the args
1207 // the argument number may have changed, or the user
1208 // wants to discard the message or abort the savefile loading
1209 nargs = dispatcher->on_dispatch(buffersize, portname,
1210 maxargs, nargs, arg_vals,
1211 round, dependency);
1212
1213 if(nargs == savefile_dispatcher_t::abort)
1214 msgs_read = -rd_total-1; // => causes abort
1215 else
1216 {
1218 {
1219 rtosc_arg_t vals[nargs];
1220 char argstr[nargs+1];
1221 for(int i = 0; i < nargs; ++i) {
1222 vals[i] = arg_vals[i].val;
1223 argstr[i] = arg_vals[i].type;
1224 }
1225 argstr[nargs] = 0;
1226
1227 rtosc_amessage(message, buffersize, portname,
1228 argstr, vals);
1229
1230 (*dispatcher)(message);
1231 }
1232 }
1233
1234 msg_ptr += rd;
1235 ++msgs_read;
1236 }
1237 else if(nargs == std::numeric_limits<int>::min())
1238 {
1239 // this means the (rest of the) file is whitespace only
1240 // => don't increase msgs_read
1241 while(*++msg_ptr) ;
1242 }
1243 else {
1244 // overwrite meaning of msgs_read in order to
1245 // inform the user where the read error occurred
1246 msgs_read = -rd_total-1;
1247 }
1248 }
1249 }
1250 return msgs_read;
1251}
1252
1253std::string rtosc::save_to_file(const Ports &ports, void *runtime,
1254 const char *appname, rtosc_version appver)
1255{
1256 std::string res;
1257 char rtosc_vbuf[12], app_vbuf[12];
1258
1259 {
1261 rtosc_version_print_to_12byte_str(&rtoscver, rtosc_vbuf);
1262 rtosc_version_print_to_12byte_str(&appver, app_vbuf);
1263 }
1264
1265 res += "% RT OSC v"; res += rtosc_vbuf; res += " savefile\n"
1266 "% "; res += appname; res += " v"; res += app_vbuf; res += "\n";
1267 res += get_changed_values(ports, runtime);
1268
1269 return res;
1270}
1271
1272int rtosc::load_from_file(const char* file_content,
1273 const Ports& ports, void* runtime,
1274 const char* appname,
1275 rtosc_version appver,
1277{
1278 char appbuf[128];
1279 int bytes_read = 0;
1280
1281 if(dispatcher)
1282 {
1283 dispatcher->app_curver = appver;
1284 dispatcher->rtosc_curver = rtosc_current_version();
1285 }
1286
1287 unsigned vma, vmi, vre;
1288 int n = 0;
1289
1290 sscanf(file_content,
1291 "%% RT OSC v%u.%u.%u savefile%n ", &vma, &vmi, &vre, &n);
1292 if(n <= 0 || vma > 255 || vmi > 255 || vre > 255)
1293 return -bytes_read-1;
1294 if(dispatcher)
1295 {
1296 dispatcher->rtosc_filever.major = vma;
1297 dispatcher->rtosc_filever.minor = vmi;
1298 dispatcher->rtosc_filever.revision = vre;
1299 }
1300 file_content += n;
1301 bytes_read += n;
1302 n = 0;
1303
1304 sscanf(file_content,
1305 "%% %128s v%u.%u.%u%n ", appbuf, &vma, &vmi, &vre, &n);
1306 if(n <= 0 || strcmp(appbuf, appname) || vma > 255 || vmi > 255 || vre > 255)
1307 return -bytes_read-1;
1308
1309 if(dispatcher)
1310 {
1311 dispatcher->app_filever.major = vma;
1312 dispatcher->app_filever.minor = vmi;
1313 dispatcher->app_filever.revision = vre;
1314 }
1315 file_content += n;
1316 bytes_read += n;
1317 n = 0;
1318
1319 int rval = dispatch_printed_messages(file_content,
1320 ports, runtime, dispatcher);
1321 return (rval < 0) ? (rval-bytes_read) : rval;
1322}
1323
1324/*
1325 * Miscellaneous
1326 */
1327
1328const Port *Ports::operator[](const char *name) const
1329{
1330 for(const Port &port:ports) {
1331 const char *_needle = name,
1332 *_haystack = port.name;
1333 while(*_needle && *_needle==*_haystack)_needle++,_haystack++;
1334
1335 if(*_needle == 0 && (*_haystack == ':' || *_haystack == '\0')) {
1336 return &port;
1337 }
1338 }
1339 return NULL;
1340}
1341
1343{
1344 while(*m && *m != '/') ++m;
1345 return m+1;
1346}
1347
1348const Port *Ports::apropos(const char *path) const
1349{
1350 if(path && path[0] == '/')
1351 ++path;
1352
1353 for(const Port &port: ports)
1354 if(strchr(port.name,'/') && rtosc_match_path(port.name,path, NULL))
1355 return (strchr(path,'/')[1]==0) ? &port :
1356 port.ports->apropos(snip(path));
1357
1358 //This is the lowest level, now find the best port
1359 for(const Port &port: ports)
1360 if(*path && (strstr(port.name, path)==port.name ||
1361 rtosc_match_path(port.name, path, NULL)))
1362 return &port;
1363
1364 return NULL;
1365}
1366
1367static bool parent_path_p(char *read, char *start)
1368{
1369 if(read-start<2)
1370 return false;
1371 return read[0]=='.' && read[-1]=='.' && read[-2]=='/';
1372}
1373
1374static void read_path(char *&r, char *start)
1375{
1376 while(1)
1377 {
1378 if(r<start)
1379 break;
1380 bool doBreak = *r=='/';
1381 r--;
1382 if(doBreak)
1383 break;
1384 }
1385}
1386
1387static void move_path(char *&r, char *&w, char *start)
1388{
1389 while(1)
1390 {
1391 if(r<start)
1392 break;
1393 bool doBreak = *r=='/';
1394 *w-- = *r--;
1395 if(doBreak)
1396 break;
1397 }
1398}
1399
1400
1402{
1403 //obtain the pointer to the last non-null char
1404 char *p_end = p;
1405 while(*p_end) p_end++;
1406 p_end--;
1407
1408 //number of subpaths to consume
1409 int consuming = 0;
1410
1411 char *write_pos = p_end;
1412 char *read_pos = p_end;
1413 while(read_pos >= p) {
1414 //per path chunk either
1415 //(1) find a parent ref and inc consuming
1416 //(2) find a normal ref and consume
1417 //(3) find a normal ref and write through
1418 bool ppath = parent_path_p(read_pos, p);
1419 if(ppath) {
1420 read_path(read_pos, p);
1421 consuming++;
1422 } else if(consuming) {
1423 read_path(read_pos, p);
1424 consuming--;
1425 } else
1426 move_path(read_pos, write_pos, p);
1427 }
1428 //return last written location, not next to write
1429 return write_pos+1;
1430};
1431
1433{
1434 if (impl)
1435 delete []impl->enump;
1436 delete impl;
1437 impl = new Port_Matcher;
1438 generate_minimal_hash(*this, *impl);
1439 impl->enump = new bool[ports.size()];
1440 for(int i=0; i<(int)ports.size(); ++i)
1441 impl->enump[i] = strchr(ports[i].name, '#');
1442
1443 elms = ports.size();
1444}
1445
1447 std::initializer_list<ClonePort> c)
1448 :Ports({})
1449{
1450 for(auto &to_clone:c) {
1451 const Port *clone_port = NULL;
1452 for(auto &p:ports_.ports)
1453 if(!strcmp(p.name, to_clone.name))
1454 clone_port = &p;
1455 if(!clone_port && strcmp("*", to_clone.name)) {
1456 fprintf(stderr, "Cannot find a clone port for '%s'\n",to_clone.name);
1457 assert(false);
1458 }
1459
1460 if(clone_port) {
1461 ports.push_back({clone_port->name, clone_port->metadata,
1462 clone_port->ports, to_clone.cb});
1463 } else {
1464 default_handler = to_clone.cb;
1465 }
1466 }
1467
1468 refreshMagic();
1469}
1470MergePorts::MergePorts(std::initializer_list<const rtosc::Ports*> c)
1471 :Ports({})
1472{
1473 //XXX TODO remove duplicates in some sane and documented way
1474 //e.g. repeated ports override and remove older ones
1475 for(auto *to_clone:c) {
1476 assert(to_clone);
1477 for(auto &p:to_clone->ports) {
1478 bool already_there = false;
1479 for(auto &pp:ports)
1480 if(!strcmp(pp.name, p.name))
1481 already_there = true;
1482
1483 if(!already_there)
1484 ports.push_back(p);
1485 }
1486 }
1487
1488 refreshMagic();
1489}
1490
1500bool port_is_enabled(const Port* port, char* loc, size_t loc_size,
1501 const Ports& base, void *runtime)
1502{
1503 if(port && runtime)
1504 {
1505 const char* enable_port = port->meta()["enabled by"];
1506 if(enable_port)
1507 {
1508 /*
1509 find out which Ports object to dispatch at
1510 (the current one or its child?)
1511 */
1512 const char* n = port->name;
1513 const char* e = enable_port;
1514 for( ; *n && (*n == *e) && *n != '/' && *e != '/'; ++n, ++e) ;
1515
1516 bool subport = (*e == '/' && *n == '/');
1517
1518 const char* ask_port_str = subport
1519 ? e+1
1520 : enable_port;
1521
1522 const Ports& ask_ports = subport ? *base[port->name]->ports
1523 : base;
1524
1525 assert(!strchr(ask_port_str, '/'));
1526 const Port* ask_port = ask_ports[ask_port_str];
1527 assert(ask_port);
1528
1529 rtosc_arg_val_t rval;
1530
1531 /*
1532 concatenate the location string
1533 */
1534 if(subport)
1535 strncat(loc, "/../", loc_size - strlen(loc) - 1);
1536 strncat(loc, enable_port, loc_size - strlen(loc) - 1);
1537
1538 char* collapsed_loc = Ports::collapsePath(loc);
1539 loc_size -= (collapsed_loc - loc);
1540
1541// TODO: collapse, use .. only in one case
1542 /*
1543 receive the "enabled" property
1544 */
1545 char buf[loc_size];
1546#ifdef NEW_CODE
1547 strncpy(buf, collapsed_loc, loc_size);
1548#else
1549 // TODO: try to use portname_from_base, since Ports might
1550 // also be of type a#N/b
1551 const char* last_slash = strrchr(collapsed_loc, '/');
1552 strncpy(buf,
1553 last_slash ? last_slash + 1 : collapsed_loc,
1554 loc_size);
1555#endif
1556 get_value_from_runtime(runtime, *ask_port,
1557 loc_size, collapsed_loc, ask_port_str,
1558 buf, 0, 1, &rval);
1559 assert(rval.type == 'T' || rval.type == 'F');
1560 return rval.val.T == 'T';
1561 }
1562 else // Port has no "enabled" property, so it is always enabled
1563 return true;
1564 }
1565 else // no runtime provided, so run statically through all subports
1566 return true;
1567}
1568
1569// TODO: copy the changes into walk_ports_2
1570void rtosc::walk_ports(const Ports *base,
1571 char *name_buffer,
1572 size_t buffer_size,
1573 void *data,
1574 port_walker_t walker,
1575 void* runtime)
1576{
1577 auto walk_ports_recurse = [](const Port& p, char* name_buffer,
1578 size_t buffer_size, const Ports& base,
1579 void* data, port_walker_t walker,
1580 void* runtime, const char* old_end)
1581 {
1582 // TODO: all/most of these checks must also be done for the
1583 // first, non-recursive call
1584 bool enabled = true;
1585 if(runtime)
1586 {
1587 enabled = (p.meta().find("no walk") == p.meta().end());
1588 if(enabled)
1589 {
1590 // get child runtime and check if it's NULL
1591 RtData r;
1592 r.obj = runtime;
1593 r.port = &p;
1594
1595 char buf[1024];
1596 strncpy(buf, old_end, 1024);
1597 strncat(buf, "pointer", 1024 - strlen(buf) - 1);
1598 assert(1024 - strlen(buf) >= 8);
1599 strncpy(buf + strlen(buf) + 1, ",", 2);
1600
1601 p.cb(buf, r);
1602 runtime = r.obj; // callback has stored the child pointer here
1603 // if there is runtime information, but the pointer is NULL,
1604 // the port is not enabled
1605 enabled = (bool) runtime;
1606 if(enabled)
1607 {
1608 // check if the port is disabled by a switch
1609 enabled = port_is_enabled(&p, name_buffer, buffer_size,
1610 base, runtime);
1611 }
1612 }
1613 }
1614 if(enabled)
1615 rtosc::walk_ports(p.ports, name_buffer, buffer_size,
1616 data, walker, runtime);
1617 };
1618
1619 //only walk valid ports
1620 if(!base)
1621 return;
1622
1623 assert(name_buffer);
1624 //XXX buffer_size is not properly handled yet
1625 if(name_buffer[0] == 0)
1626 name_buffer[0] = '/';
1627
1628 char *old_end = name_buffer;
1629 while(*old_end) ++old_end;
1630
1631 if(port_is_enabled((*base)["self:"], name_buffer, buffer_size, *base,
1632 runtime))
1633 for(const Port &p: *base) {
1634 //if(strchr(p.name, '/')) {//it is another tree
1635 if(p.ports) {//it is another tree
1636 if(strchr(p.name,'#')) {
1637 const char *name = p.name;
1638 char *pos = old_end;
1639 while(*name != '#') *pos++ = *name++;
1640 const unsigned max = atoi(name+1);
1641
1642 for(unsigned i=0; i<max; ++i)
1643 {
1644 sprintf(pos,"%d",i);
1645
1646 //Ensure the result is a path
1647 if(strrchr(name_buffer, '/')[1] != '/')
1648 strcat(name_buffer, "/");
1649
1650 //Recurse
1651 walk_ports_recurse(p, name_buffer, buffer_size,
1652 *base, data, walker, runtime, old_end);
1653 }
1654 } else {
1655 //Append the path
1656 const char* old_end = name_buffer + strlen(name_buffer);
1657 scat(name_buffer, p.name);
1658
1659 //Recurse
1660 walk_ports_recurse(p, name_buffer, buffer_size,
1661 *base, data, walker, runtime, old_end);
1662 }
1663 } else {
1664 if(strchr(p.name,'#')) {
1665 const char *name = p.name;
1666 char *pos = old_end;
1667 while(*name != '#') *pos++ = *name++;
1668 const unsigned max = atoi(name+1);
1669 while(isdigit(*++name)) ;
1670
1671 for(unsigned i=0; i<max; ++i)
1672 {
1673 char* pos_after_num = pos + sprintf(pos,"%d",i);
1674 const char* name2_2 = name;
1675
1676 // append everything behind the '#' (for cases like a#N/b)
1677 while(*name2_2 && *name2_2 != ':')
1678 *pos_after_num++ = *name2_2++;
1679
1680 //Apply walker function
1681 walker(&p, name_buffer, old_end, *base, data, runtime);
1682 }
1683 } else {
1684 //Append the path
1685 scat(name_buffer, p.name);
1686
1687 //Apply walker function
1688 walker(&p, name_buffer, old_end, *base, data, runtime);
1689 }
1690 }
1691
1692 //Remove the rest of the path
1693 char *tmp = old_end;
1694 while(*tmp) *tmp++=0;
1695 }
1696}
1697
1698void walk_ports2(const rtosc::Ports *base,
1699 char *name_buffer,
1700 size_t buffer_size,
1701 void *data,
1702 rtosc::port_walker_t walker)
1703{
1704 if(!base)
1705 return;
1706
1707 assert(name_buffer);
1708 //XXX buffer_size is not properly handled yet
1709 if(name_buffer[0] == 0)
1710 name_buffer[0] = '/';
1711
1712 char *old_end = name_buffer;
1713 while(*old_end) ++old_end;
1714
1715 for(const rtosc::Port &p: *base) {
1716 if(strchr(p.name, '/')) {//it is another tree
1717 if(strchr(p.name,'#')) {
1718 const char *name = p.name;
1719 char *pos = old_end;
1720 while(*name != '#') *pos++ = *name++;
1721 const unsigned max = atoi(name+1);
1722
1723 //for(unsigned i=0; i<max; ++i)
1724 {
1725 sprintf(pos,"[0,%d]",max-1);
1726
1727 //Ensure the result is a path
1728 if(strrchr(name_buffer, '/')[1] != '/')
1729 strcat(name_buffer, "/");
1730
1731 //Recurse
1732 walk_ports2(p.ports, name_buffer, buffer_size,
1733 data, walker);
1734 }
1735 } else {
1736 //Append the path
1737 scat(name_buffer, p.name);
1738
1739 //Recurse
1740 walk_ports2(p.ports, name_buffer, buffer_size,
1741 data, walker);
1742 }
1743 } else {
1744 if(strchr(p.name,'#')) {
1745 const char *name = p.name;
1746 char *pos = old_end;
1747 while(*name != '#') *pos++ = *name++;
1748 const unsigned max = atoi(name+1);
1749
1750 //for(unsigned i=0; i<max; ++i)
1751 {
1752 sprintf(pos,"[0,%d]",max-1);
1753
1754 //Apply walker function
1755 walker(&p, name_buffer, old_end, *base, data, nullptr);
1756 }
1757 } else {
1758 //Append the path
1759 scat(name_buffer, p.name);
1760
1761 //Apply walker function
1762 walker(&p, name_buffer, old_end, *base, data, nullptr);
1763 }
1764 }
1765
1766 //Remove the rest of the path
1767 char *tmp = old_end;
1768 while(*tmp) *tmp++=0;
1769 }
1770}
1771
1772static void units(std::ostream &o, const char *u)
1773{
1774 if(!u)
1775 return;
1776 o << " units=\"" << u << "\"";
1777}
1778
1779using std::ostream;
1780using std::string;
1782{
1783 int min = 0;
1784 for(auto m:meta)
1785 if(strstr(m.title, "map "))
1786 min = atoi(m.title+4);
1787
1788 for(auto m:meta)
1789 if(strstr(m.title, "map "))
1790 min = min>atoi(m.title+4) ? atoi(m.title+4) : min;
1791
1792 return min;
1793}
1794
1796{
1797 int max = 0;
1798 for(auto m:meta)
1799 if(strstr(m.title, "map "))
1800 max = atoi(m.title+4);
1801
1802 for(auto m:meta)
1803 if(strstr(m.title, "map "))
1804 max = max<atoi(m.title+4) ? atoi(m.title+4) : max;
1805
1806 return max;
1807}
1808
1810{
1811 int result = std::numeric_limits<int>::min();
1812
1813 for(auto m:meta)
1814 if(strstr(m.title, "map "))
1815 if(!strcmp(m.value, value))
1816 {
1817 result = atoi(m.title+4);
1818 break;
1819 }
1820
1821 return result;
1822}
1823
1824static ostream &add_options(ostream &o, Port::MetaContainer meta)
1825{
1826 string sym_names = "xyzabcdefghijklmnopqrstuvw";
1827 int sym_idx = 0;
1828 bool has_options = false;
1829 for(auto m:meta)
1830 if(strstr(m.title, "map "))
1831 has_options = true;
1832 for(auto m:meta)
1833 if(strcmp(m.title, "documentation") &&
1834 strcmp(m.title, "parameter") &&
1835 strcmp(m.title, "max") &&
1836 strcmp(m.title, "min"))
1837 printf("m.title = <%s>\n", m.title);
1838
1839 if(!has_options)
1840 return o;
1841
1842 o << " <hints>\n";
1843 for(auto m:meta) {
1844 if(strstr(m.title, "map ")) {
1845 o << " <point symbol=\"" << sym_names[sym_idx++] << "\" value=\"";
1846 o << m.title+4 << "\">" << m.value << "</point>\n";
1847 }
1848 }
1849 o << " </hints>\n";
1850
1851 return o;
1852}
1853static ostream &dump_t_f_port(ostream &o, string name, string doc)
1854{
1855 o << " <message_in pattern=\"" << name << "\" typetag=\"T\">\n";
1856 o << " <desc>Enable " << doc << "</desc>\n";
1857 o << " <param_T symbol=\"x\"/>\n";
1858 o << " </message_in>\n";
1859 o << " <message_in pattern=\"" << name << "\" typetag=\"F\">\n";
1860 o << " <desc>Disable " << doc << "</desc>\n";
1861 o << " <param_F symbol=\"x\"/>\n";
1862 o << " </message_in>\n";
1863 o << " <message_in pattern=\"" << name << "\" typetag=\"\">\n";
1864 o << " <desc>Get state of " << doc << "</desc>\n";
1865 o << " </message_in>\n";
1866 o << " <message_out pattern=\"" << name << "\" typetag=\"T\">\n";
1867 o << " <desc>Value of " << doc << "</desc>\n";
1868 o << " <param_T symbol=\"x\"/>";
1869 o << " </message_out>\n";
1870 o << " <message_out pattern=\"" << name << "\" typetag=\"F\">\n";
1871 o << " <desc>Value of " << doc << "</desc>\n";
1872 o << " <param_F symbol=\"x\"/>";
1873 o << " </message_out>\n";
1874 return o;
1875}
1876static ostream &dump_any_port(ostream &o, string name, string doc)
1877{
1878 o << " <message_in pattern=\"" << name << "\" typetag=\"*\">\n";
1879 o << " <desc>" << doc << "</desc>\n";
1880 o << " </message_in>\n";
1881 return o;
1882}
1883
1884static ostream &dump_generic_port(ostream &o, string name, string doc, string type)
1885{
1886 const char *t = type.c_str();
1887 string arg_names = "xyzabcdefghijklmnopqrstuvw";
1888
1889 //start out with argument separator
1890 if(*t++ != ':')
1891 return o;
1892 //now real arguments (assume [] don't exist)
1893 string args;
1894 while(*t && *t != ':')
1895 args += *t++;
1896
1897 o << " <message_in pattern=\"" << name << "\" typetag=\"" << args << "\">\n";
1898 o << " <desc>" << doc << "</desc>\n";
1899
1900 assert(args.length()<arg_names.length());
1901 for(unsigned i=0; i<args.length(); ++i)
1902 o << " <param_" << args[i] << " symbol=\"" << arg_names[i] << "\"/>\n";
1903 o << " </message_in>\n";
1904
1905 if(*t == ':')
1906 return dump_generic_port(o, name, doc, t);
1907 else
1908 return o;
1909}
1910
1911void dump_ports_cb(const rtosc::Port *p, const char *name,const char*,
1912 const Ports&,void *v, void*)
1913{
1914 std::ostream &o = *(std::ostream*)v;
1915 auto meta = p->meta();
1916 const char *args = strchr(p->name, ':');
1917 auto mparameter = meta.find("parameter");
1918 auto mdoc = meta.find("documentation");
1919 string doc;
1920
1921 if(mdoc != p->meta().end())
1922 doc = mdoc.value;
1923 if(meta.find("internal") != meta.end()) {
1924 doc += "[INTERNAL]";
1925 }
1926
1927 if(mparameter != p->meta().end()) {
1928 char type = 0;
1929 if(args) {
1930 if(strchr(args, 'f'))
1931 type = 'f';
1932 else if(strchr(args, 'i'))
1933 type = 'i';
1934 else if(strchr(args, 'c'))
1935 type = 'c';
1936 else if(strchr(args, 'T'))
1937 type = 't';
1938 else if(strchr(args, 's'))
1939 type = 's';
1940 }
1941
1942 if(!type) {
1943 fprintf(stderr, "rtosc port dumper: Cannot handle '%s'\n", name);
1944 fprintf(stderr, " args = <%s>\n", args);
1945 return;
1946 }
1947
1948 if(type == 't') {
1949 dump_t_f_port(o, name, doc);
1950 return;
1951 }
1952
1953 o << " <message_in pattern=\"" << name << "\" typetag=\"" << type << "\">\n";
1954 o << " <desc>Set Value of " << doc << "</desc>\n";
1955 if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c') {
1956 o << " <param_" << type << " symbol=\"x\"";
1957 units(o, meta["unit"]);
1958 o << ">\n";
1959 o << " <range_min_max " << (type == 'f' ? "lmin=\"[\" lmax=\"]\"" : "");
1960 o << " min=\"" << meta["min"] << "\" max=\"" << meta["max"] << "\"/>\n";
1961 o << " </param_" << type << ">";
1962 } else if(meta.find("enumerated") != meta.end()) {
1963 o << " <param_" << type << " symbol=\"x\">\n";
1964 o << " <range_min_max min=\"" << enum_min(meta) << "\" max=\"";
1965 o << enum_max(meta) << "\">\n";
1966 add_options(o, meta);
1967 o << " </range_min_max>\n";
1968 o << " </param_" << type << ">\n";
1969 } else {
1970 o << " <param_" << type << " symbol=\"x\"";
1971 units(o, meta["unit"]);
1972 o << "/>\n";
1973 }
1974 o << " </message_in>\n";
1975 o << " <message_in pattern=\"" << name << "\" typetag=\"\">\n";
1976 o << " <desc>Get Value of " << doc << "</desc>\n";
1977 o << " </message_in>\n";
1978 o << " <message_out pattern=\"" << name << "\" typetag=\"" << type << "\">\n";
1979 o << " <desc>Value of " << doc << "</desc>\n";
1980 if(meta.find("min") != meta.end() && meta.find("max") != meta.end() && type != 'c') {
1981 o << " <param_" << type << " symbol=\"x\"";
1982 units(o, meta["unit"]);
1983 o << ">\n";
1984 o << " <range_min_max " << (type == 'f' ? "lmin=\"[\" lmax=\"]\"" : "");
1985 o << " min=\"" << meta["min"] << "\" max=\"" << meta["max"] << "\"/>\n";
1986 o << " </param_" << type << ">\n";
1987 } else if(meta.find("enumerated") != meta.end()) {
1988 o << " <param_" << type << " symbol=\"x\">\n";
1989 o << " <range_min_max min=\"" << enum_min(meta) << "\" max=\"";
1990 o << enum_max(meta) << "\">\n";
1991 add_options(o, meta);
1992 o << " </range_min_max>\n";
1993 o << " </param_" << type << ">\n";
1994 } else {
1995 o << " <param_" << type << " symbol=\"x\"";
1996 units(o, meta["unit"]);
1997 o << "/>\n";
1998 }
1999 o << " </message_out>\n";
2000 } else if(mdoc != meta.end() && (!args || args == std::string(""))) {
2001 dump_any_port(o, name, doc);
2002 } else if(mdoc != meta.end() && args) {
2003 dump_generic_port(o, name, doc, args);
2004 } else if(mdoc != meta.end()) {
2005 fprintf(stderr, "Skipping \"%s\"\n", name);
2006 if(args) {
2007 fprintf(stderr, " type = %s\n", args);
2008 }
2009 } else
2010 fprintf(stderr, "Skipping [UNDOCUMENTED] \"%s\"\n", name);
2011}
2012
2013std::ostream &rtosc::operator<<(std::ostream &o, rtosc::OscDocFormatter &formatter)
2014{
2015 o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
2016 o << "<osc_unit format_version=\"1.0\">\n";
2017 o << " <meta>\n";
2018 o << " <name>" << formatter.prog_name << "</name>\n";
2019 o << " <uri>" << formatter.uri << "</uri>\n";
2020 o << " <doc_origin>" << formatter.doc_origin << "</doc_origin>\n";
2021 o << " <author><firstname>" << formatter.author_first;
2022 o << "</firstname><lastname>" << formatter.author_last << "</lastname></author>\n";
2023 o << " </meta>\n";
2024 char buffer[1024];
2025 memset(buffer, 0, sizeof(buffer));
2026 walk_ports2(formatter.p, buffer, 1024, &o, dump_ports_cb);
2027 o << "</osc_unit>\n";
2028 return o;
2029}
2030
#define NULL
Definition CarlaBridgeFormat.cpp:30
void walk_ports2(const rtosc::Ports *base, char *name_buffer, size_t buffer_size, void *data, rtosc::port_walker_t walker)
Definition ports.cpp:1698
assert(0)
uint8_t a
Definition Spc_Cpu.h:141
float arg(const fft_t *freqs, off_t x)
Definition OscilGen.cpp:58
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
static void message(int level, const char *fmt,...)
Definition adplugdb.cpp:120
static intptr_t dispatcher(NativeHostHandle h, NativeHostDispatcherOpcode c, int32_t i, intptr_t v, void *p, float o)
Definition carla-host-plugin.c:48
RtData subclass to capture argument values from a runtime object.
Definition ports.cpp:745
rtosc_arg_val_t * arg_vals
Definition ports.cpp:747
int nargs
Definition ports.cpp:748
void chain(const char *msg) override
Bypass message to some kind of backend if the message can not be handled.
Definition ports.cpp:755
void reply(const char *, const char *args,...) override
Definition ports.cpp:775
void replyArray(const char *, const char *args, rtosc_arg_t *vals) override
Definition ports.cpp:762
void chain(const char *path, const char *args,...) override
Definition ports.cpp:750
void reply(const char *) override
Reply if information has been requested.
Definition ports.cpp:760
int size() const
Return the number of argument values stored.
Definition ports.cpp:789
Capture(std::size_t max_args, rtosc_arg_val_t *arg_vals)
Definition ports.cpp:790
size_t max_args
Definition ports.cpp:746
Definition ports.cpp:653
int cols_used
Definition ports.cpp:656
CapturePretty(char *buffer, std::size_t size, int cols_used)
Definition ports.cpp:699
std::size_t buffersize
Definition ports.cpp:655
const char * value() const
Return the argument values, pretty-printed.
Definition ports.cpp:698
void reply(const char *, const char *args,...) override
Definition ports.cpp:678
char * buffer
Definition ports.cpp:654
void reply(const char *) override
Reply if information has been requested.
Definition ports.cpp:658
Definition ports.h:124
const char * str_ptr
Definition ports.h:137
MetaContainer(const char *str_)
Definition ports.cpp:172
size_t length(void) const
Definition ports.cpp:197
MetaIterator end(void) const
Definition ports.cpp:184
const char * operator[](const char *str) const
Definition ports.cpp:208
MetaIterator begin(void) const
Definition ports.cpp:176
MetaIterator find(const char *str) const
Definition ports.cpp:189
Definition ports.h:106
MetaIterator & operator++(void)
Definition ports.cpp:146
const char * value
Definition ports.h:120
const char * title
Definition ports.h:119
MetaIterator(const char *str)
Definition ports.cpp:140
Definition ports.cpp:253
bool * enump
Definition ports.cpp:255
bool rtosc_match_args(const char *pattern, const char *msg)
Definition ports.cpp:262
ivec_t assoc
Definition ports.cpp:259
ivec_t pos
Definition ports.cpp:258
bool hard_match(int i, const char *msg)
Definition ports.cpp:285
cvec_t arg_spec
Definition ports.cpp:257
ivec_t remap
Definition ports.cpp:260
svec_t fixed
Definition ports.cpp:256
Definition ports.h:317
static int default_response(size_t nargs, bool first_round, dependency_t dependency)
Definition ports.cpp:1137
@ abort
the message shall lead to abort the savefile loading
Definition ports.h:324
@ discard
the message shall not be dispatched
Definition ports.h:325
void operator()(const char *msg)
call this to dispatch a message
Definition ports.cpp:1127
virtual int on_dispatch(size_t portname_max, char *portname, size_t maxargs, size_t nargs, rtosc_arg_val_t *args, bool round2, dependency_t dependency)
Definition ports.cpp:1152
dependency_t
Definition ports.h:328
@ not_specified
default values do depend on others
Definition ports.h:331
const Ports * ports
Definition ports.h:318
void * runtime
Definition ports.h:319
char loc[1024]
Definition ports.h:320
* e
Definition inflate.c:1404
UINT_D64 w
Definition inflate.c:942
int * l
Definition inflate.c:1579
unsigned z
Definition inflate.c:1589
unsigned * m
Definition inflate.c:1559
struct huft * t
Definition inflate.c:943
register unsigned k
Definition inflate.c:946
register unsigned j
Definition inflate.c:1576
unsigned v[N_MAX]
Definition inflate.c:1584
unsigned d
Definition inflate.c:940
struct huft * u[BMAX]
Definition inflate.c:1583
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
unsigned x[BMAX+1]
Definition inflate.c:1586
bool rtosc_match(const char *pattern, const char *msg, const char **path_end)
Definition dispatch.c:132
const char * rtosc_match_path(const char *pattern, const char *msg, const char **path_end)
Definition dispatch.c:70
static PuglViewHint int value
Definition pugl.h:1708
static const char * title
Definition pugl.h:1747
static const char * name
Definition pugl.h:1582
virtual ASIOError start()=0
int val
Definition jpeglib.h:956
JSAMPIMAGE data
Definition jpeglib.h:945
int int32_t
Definition mid.cpp:97
const char * msg
Definition missing_descriptor.c:20
Definition globals.h:37
const char * msg_t
Definition ports.h:48
static char tmp[256]
Definition undo-history.cpp:80
int enum_key(Port::MetaContainer meta, const char *value)
Definition ports.cpp:1809
void map_arg_vals(rtosc_arg_val_t *av, size_t n, Port::MetaContainer meta)
Definition ports.cpp:974
std::string get_changed_values(const Ports &ports, void *runtime)
Definition ports.cpp:1029
void(* port_walker_t)(const Port *, const char *, const char *, const Ports &, void *, void *)
Definition ports.h:452
std::ostream & operator<<(std::ostream &o, OscDocFormatter &formatter)
Definition ports.cpp:2013
int canonicalize_arg_vals(rtosc_arg_val_t *av, size_t n, const char *port_args, Port::MetaContainer meta)
Definition ports.cpp:939
osc_element< 0, rtMsg< Types... > >::type first(rtMsg< Types... > &Tuple)
Definition typed-message.h:152
int dispatch_printed_messages(const char *messages, const Ports &ports, void *runtime, savefile_dispatcher_t *dispatcher=NULL)
Definition ports.cpp:1161
std::string save_to_file(const Ports &ports, void *runtime, const char *appname, rtosc_version appver)
Definition ports.cpp:1253
int load_from_file(const char *file_content, const Ports &ports, void *runtime, const char *appname, rtosc_version appver, savefile_dispatcher_t *dispatcher=NULL)
Definition ports.cpp:1272
const char * get_default_value(const char *port_name, const Ports &ports, void *runtime, const Port *port_hint=NULL, int32_t idx=-1, int recursive=1)
Definition ports.cpp:853
void walk_ports(const Ports *base, char *name_buffer, size_t buffer_size, void *data, port_walker_t walker, void *runtime=NULL)
Definition ports.cpp:1570
#define N
Definition nseel-cfunc.c:36
#define min(x, y)
Definition os.h:74
#define max(x, y)
Definition os.h:78
png_uint_32 length
Definition png.c:2247
static const char * get_value_from_runtime(void *runtime, const Ports &ports, size_t loc_size, char *loc, char *buffer_with_port, std::size_t buffersize, int cols_used)
Returns a port's value pretty-printed from a runtime object. The port object must not be known.
Definition ports.cpp:710
static msg_t snip(msg_t m)
Definition ports.cpp:1342
static ostream & dump_any_port(ostream &o, string name, string doc)
Definition ports.cpp:1876
static ostream & dump_t_f_port(ostream &o, string name, string doc)
Definition ports.cpp:1853
static ivec_t find_remap(words_t &strs, ivec_t &pos, ivec_t &assoc)
Definition ports.cpp:441
std::vector< tuple_t > tvec_t
Definition ports.cpp:249
void metaiterator_advance(const char *&title, const char *&value)
Definition ports.cpp:123
bool port_is_enabled(const Port *port, char *loc, size_t loc_size, const Ports &base, void *runtime)
Check if the port port is enabled.
Definition ports.cpp:1500
std::vector< std::string > words_t
Definition ports.cpp:244
#define __builtin_expect(a, b)
Definition ports.cpp:514
static ostream & add_options(ostream &o, Port::MetaContainer meta)
Definition ports.cpp:1824
static ostream & dump_generic_port(ostream &o, string name, string doc, string type)
Definition ports.cpp:1884
static void generate_minimal_hash(std::vector< std::string > str, Port_Matcher &pm)
Definition ports.cpp:458
bool scmp(const char *a, const char *b)
Definition ports.cpp:238
static void scat(char *dest, const char *src)
Definition ports.cpp:35
std::vector< int > ivec_t
Definition ports.cpp:247
bool has(T &t, Z &z)
Definition ports.cpp:334
void dump_ports_cb(const rtosc::Port *p, const char *name, const char *, const Ports &, void *v, void *)
Definition ports.cpp:1911
static void move_path(char *&r, char *&w, char *start)
Definition ports.cpp:1387
static void read_path(char *&r, char *start)
Definition ports.cpp:1374
std::vector< std::string > svec_t
Definition ports.cpp:245
static ivec_t find_pos(words_t &strs)
Definition ports.cpp:344
static ivec_t find_assoc(const words_t &strs, const ivec_t &pos)
Definition ports.cpp:395
std::vector< int > tuple_t
Definition ports.cpp:248
std::vector< const char * > cvec_t
Definition ports.cpp:246
int count_dups(std::vector< T > &t)
Definition ports.cpp:314
static int int_max(int a, int b)
Definition ports.cpp:342
static int enum_min(Port::MetaContainer meta)
Definition ports.cpp:1781
bool arg_matcher(const char *pattern, const char *args)
Definition ports.cpp:216
static bool parent_path_p(char *read, char *start)
Definition ports.cpp:1367
tvec_t do_hash(const words_t &strs, const ivec_t &pos)
Definition ports.cpp:299
static void units(std::ostream &o, const char *u)
Definition ports.cpp:1772
static int enum_max(Port::MetaContainer meta)
Definition ports.cpp:1795
int rtosc_count_printed_arg_vals_of_msg(const char *msg)
Definition pretty-format.c:739
size_t rtosc_print_arg_vals(const rtosc_arg_val_t *args, size_t n, char *buffer, size_t bs, const rtosc_print_options *opt, int cols_used)
Definition pretty-format.c:297
size_t rtosc_scan_message(const char *src, char *address, size_t adrsize, rtosc_arg_val_t *args, size_t n, char *buffer_for_strings, size_t bufsize)
Definition pretty-format.c:1086
int rtosc_count_printed_arg_vals(const char *src)
Definition pretty-format.c:715
size_t rtosc_scan_arg_vals(const char *src, rtosc_arg_val_t *args, size_t n, char *buffer_for_strings, size_t bufsize)
Definition pretty-format.c:1059
rtosc_version rtosc_current_version()
Return the version RT OSC has been compiled with.
void rtosc_version_print_to_12byte_str(const rtosc_version *v, char *_12bytes)
Print the version pointed to by v to the buffer _12bytes.
size_t rtosc_vmessage(char *buffer, size_t len, const char *address, const char *arguments, va_list ap)
Definition rtosc.c:497
size_t rtosc_amessage(char *buffer, size_t len, const char *address, const char *arguments, const rtosc_arg_t *args)
Definition rtosc.c:515
const char * rtosc_argument_string(const char *msg)
Definition rtosc.c:11
int rtosc_arg_vals_eq(rtosc_arg_val_t *lhs, rtosc_arg_val_t *rhs, size_t lsize, size_t rsize, const rtosc_cmp_options *opt)
Definition rtosc.c:237
void rtosc_v2argvals(rtosc_arg_val_t *args, size_t nargs, const char *arg_str, va_list ap)
Definition rtosc.c:478
Definition lv2apply.c:40
ClonePorts(const Ports &p, std::initializer_list< ClonePort > c)
Definition ports.cpp:1446
MergePorts(std::initializer_list< const Ports * > c)
Definition ports.cpp:1470
Definition ports.h:485
std::string author_first
Definition ports.h:490
const Ports * p
Definition ports.h:486
std::string author_last
Definition ports.h:491
std::string prog_name
Definition ports.h:487
std::string doc_origin
Definition ports.h:489
std::string uri
Definition ports.h:488
Definition ports.h:99
MetaContainer meta(void) const
Definition ports.h:140
const char * metadata
Statically accessable data about port.
Definition ports.h:101
const char * name
Pattern for messages to match.
Definition ports.h:100
const Ports * ports
Pointer to further ports.
Definition ports.h:102
Definition ports.h:161
~Ports(void)
Definition ports.cpp:507
std::function< void(msg_t, RtData &)> default_handler
Definition ports.h:163
Ports(std::initializer_list< Port > l)
Definition ports.cpp:501
const Port & operator[](unsigned i) const
Definition ports.h:177
unsigned elms
Definition ports.h:236
static char * collapsePath(char *p)
Definition ports.cpp:1401
void dispatch(const char *m, RtData &d, bool base_dispatch=false) const
Definition ports.cpp:517
std::vector< Port > ports
Definition ports.h:162
class Port_Matcher * impl
Definition ports.h:235
void refreshMagic(void)
Definition ports.cpp:1432
const Port * apropos(const char *path) const
Definition ports.cpp:1348
data object for the dispatch routine
Definition ports.h:55
int matches
number of matches returned from dispatch routine
Definition ports.h:66
char * loc
Definition ports.h:63
virtual void replyArray(const char *path, const char *args, rtosc_arg_t *vals)
Definition ports.cpp:64
virtual void reply(const char *path, const char *args,...)
Definition ports.cpp:71
virtual void broadcast(const char *path, const char *args,...)
Transmit initialization/change of a value to all listeners.
Definition ports.cpp:99
virtual void broadcastArray(const char *path, const char *args, rtosc_arg_t *vals)
Definition ports.cpp:110
virtual void chainArray(const char *path, const char *args, rtosc_arg_t *vals)
Definition ports.cpp:92
virtual void forward(const char *rational=NULL)
Definition ports.cpp:118
RtData(void)
Definition ports.cpp:42
void push_index(int ind)
Definition ports.cpp:49
size_t loc_size
Definition ports.h:64
void * obj
runtime object to dispatch this object to
Definition ports.h:65
void pop_index(void)
Definition ports.cpp:56
int idx[16]
Definition ports.h:72
virtual void chain(const char *path, const char *args,...)
Definition ports.cpp:82
const char * message
Will be set to point to the full OSC message in case of a base dispatch.
Definition ports.h:70
Definition rtosc.h:127
rtosc_arg_t val
Definition rtosc.h:129
char type
Definition rtosc.h:128
struct containing an rtosc version
Definition rtosc-version.h:40
Definition rtosc.h:46
int32_t i
Definition rtosc.h:47
char T
Definition rtosc.h:48
const char * s
Definition rtosc.h:54
int n
Definition crypt.c:458
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
memcpy(hh, h, RAND_HEAD_LEN)
int r
Definition crypt.c:458
uch h[RAND_HEAD_LEN]
Definition crypt.c:459
b
Definition crypt.c:628
ulg size
Definition extract.c:2350
strcat(fmt, FZOFFT_FMT)
int * pattern
Definition match.c:126
int result
Definition process.c:1455
read(f, &c, 1)
char * pp
Definition unix.c:513
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396
else sprintf(d_t_str, LoadFarString(shtYMDHMTime), yr%100, monthstr, dy, hh, mm)