2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include <uuid/uuid.h>
30 void cbox_command_target_init(struct cbox_command_target
*ct
, cbox_process_cmd cmd
, void *user_data
)
32 ct
->process_cmd
= cmd
;
33 ct
->user_data
= user_data
;
36 gboolean
cbox_execute_on(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, const char *cmd_name
, const char *args
, GError
**error
, ...)
41 gboolean res
= cbox_execute_on_v(ct
, fb
, cmd_name
, args
, av
, error
);
46 gboolean
cbox_execute_on_v(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, const char *cmd_name
, const char *args
, va_list av
, GError
**error
)
49 struct cbox_osc_command cmd
;
51 // XXXKF might be not good enough for weird platforms
52 int unit_size
= sizeof(double);
53 // this must be a power of 2 to guarantee proper alignment
54 assert(unit_size
>= sizeof(int) && (unit_size
== 4 || unit_size
== 8));
55 cmd
.command
= cmd_name
;
57 for (int i
= 0; args
[i
]; i
++)
59 // contains pointers to all the values, plus values themselves in case of int/double
60 // (casting them to pointers is ugly, and va_arg does not return a lvalue)
61 cmd
.arg_values
= malloc(sizeof(void *) * argcount
+ unit_size
* argcount
);
62 extra_data
= (uint8_t *)&cmd
.arg_values
[argcount
];
64 for (int i
= 0; i
< argcount
; i
++)
68 void *pv
= extra_data
+ unit_size
* i
;
72 cmd
.arg_values
[i
] = va_arg(av
, char *);
76 memcpy(pv
, &iv
, sizeof(int));
77 cmd
.arg_values
[i
] = pv
;
79 case 'f': // double really
80 fv
= (double)va_arg(av
, double);
81 memcpy(pv
, &fv
, sizeof(double));
82 cmd
.arg_values
[i
] = pv
;
85 cmd
.arg_values
[i
] = va_arg(av
, struct cbox_blob
*);
88 cmd
.arg_values
[i
] = va_arg(av
, struct cbox_objhdr
*);
91 g_error("Invalid format character '%c' for command '%s'", args
[i
], cmd_name
);
95 gboolean result
= ct
->process_cmd(ct
, fb
, &cmd
, error
);
100 gboolean
cbox_osc_command_dump(const struct cbox_osc_command
*cmd
)
102 g_message("Command = %s, args = %s", cmd
->command
, cmd
->arg_types
);
103 for (int i
= 0; cmd
->arg_types
[i
]; i
++)
105 switch(cmd
->arg_types
[i
])
108 g_message("Args[%d] = '%s'", i
, (const char *)cmd
->arg_values
[i
]);
112 struct cbox_objhdr
*oh
= cmd
->arg_values
[i
];
114 uuid_unparse(oh
->instance_uuid
.uuid
, buf
);
115 g_message("Args[%d] = uuid:'%s'", i
, buf
);
119 g_message("Args[%d] = %d", i
, *(int *)cmd
->arg_values
[i
]);
122 g_message("Args[%d] = %f", i
, *(double *)cmd
->arg_values
[i
]);
126 struct cbox_blob
*b
= cmd
->arg_values
[i
];
127 g_message("Args[%d] = (%p, %d)", i
, b
->data
, (int)b
->size
);
131 g_error("Invalid format character '%c' for command '%s'", cmd
->arg_types
[i
], cmd
->command
);
137 gboolean
cbox_check_fb_channel(struct cbox_command_target
*fb
, const char *command
, GError
**error
)
142 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Feedback channel required for command '%s'", command
);
147 gboolean
cbox_execute_sub(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, const struct cbox_osc_command
*cmd
, const char *new_command
, GError
**error
)
149 struct cbox_osc_command subcmd
;
150 subcmd
.command
= new_command
;
151 subcmd
.arg_types
= cmd
->arg_types
;
152 subcmd
.arg_values
= cmd
->arg_values
;
153 return ct
->process_cmd(ct
, fb
, &subcmd
, error
);
156 gboolean
cbox_parse_path_part_int(const struct cbox_osc_command
*cmd
, const char *path
, const char **subcommand
, int *index
, int min_index
, int max_index
, GError
**error
)
158 char *numcopy
= NULL
;
159 if (!cbox_parse_path_part_str(cmd
, path
, subcommand
, &numcopy
, error
))
164 *index
= strtol(numcopy
, &endptr
, 10);
165 if (!*numcopy
&& *endptr
)
167 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Invalid index %s for command %s", numcopy
, cmd
->command
);
172 if (*index
< min_index
|| *index
> max_index
)
174 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Index %s out of range [%d, %d] for command %s", numcopy
, min_index
, max_index
, cmd
->command
);
183 gboolean
cbox_parse_path_part_str(const struct cbox_osc_command
*cmd
, const char *path
, const char **subcommand
, char **path_element
, GError
**error
)
185 *path_element
= NULL
;
187 int plen
= strlen(path
);
188 if (!strncmp(cmd
->command
, path
, plen
))
190 const char *num
= cmd
->command
+ plen
;
191 const char *slash
= strchr(num
, '/');
194 cbox_set_command_error_with_msg(error
, cmd
, "needs at least one extra path element");
198 *path_element
= g_strndup(num
, slash
-num
);