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 cmd
.arg_values
[i
] = va_arg(av
, struct cbox_uuid
*);
94 g_error("Invalid format character '%c' for command '%s'", args
[i
], cmd_name
);
98 gboolean result
= ct
->process_cmd(ct
, fb
, &cmd
, error
);
103 gboolean
cbox_osc_command_dump(const struct cbox_osc_command
*cmd
)
105 g_message("Command = %s, args = %s", cmd
->command
, cmd
->arg_types
);
106 for (int i
= 0; cmd
->arg_types
[i
]; i
++)
108 switch(cmd
->arg_types
[i
])
111 g_message("Args[%d] = '%s'", i
, (const char *)cmd
->arg_values
[i
]);
115 struct cbox_objhdr
*oh
= cmd
->arg_values
[i
];
117 uuid_unparse(oh
->instance_uuid
.uuid
, buf
);
118 g_message("Args[%d] = uuid:'%s'", i
, buf
);
122 g_message("Args[%d] = %d", i
, *(int *)cmd
->arg_values
[i
]);
125 g_message("Args[%d] = %f", i
, *(double *)cmd
->arg_values
[i
]);
129 struct cbox_blob
*b
= cmd
->arg_values
[i
];
130 g_message("Args[%d] = (%p, %d)", i
, b
->data
, (int)b
->size
);
134 g_error("Invalid format character '%c' for command '%s'", cmd
->arg_types
[i
], cmd
->command
);
142 gboolean
cbox_check_fb_channel(struct cbox_command_target
*fb
, const char *command
, GError
**error
)
147 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Feedback channel required for command '%s'", command
);
152 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
)
154 struct cbox_osc_command subcmd
;
155 subcmd
.command
= new_command
;
156 subcmd
.arg_types
= cmd
->arg_types
;
157 subcmd
.arg_values
= cmd
->arg_values
;
158 return ct
->process_cmd(ct
, fb
, &subcmd
, error
);
161 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
)
163 char *numcopy
= NULL
;
164 if (!cbox_parse_path_part_str(cmd
, path
, subcommand
, &numcopy
, error
))
169 *index
= strtol(numcopy
, &endptr
, 10);
170 if (!*numcopy
&& *endptr
)
172 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Invalid index %s for command %s", numcopy
, cmd
->command
);
177 if (*index
< min_index
|| *index
> max_index
)
179 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
);
188 gboolean
cbox_parse_path_part_str(const struct cbox_osc_command
*cmd
, const char *path
, const char **subcommand
, char **path_element
, GError
**error
)
190 *path_element
= NULL
;
192 int plen
= strlen(path
);
193 if (!strncmp(cmd
->command
, path
, plen
))
195 const char *num
= cmd
->command
+ plen
;
196 const char *slash
= strchr(num
, '/');
199 cbox_set_command_error_with_msg(error
, cmd
, "needs at least one extra path element");
203 *path_element
= g_strndup(num
, slash
-num
);