0b41512a2e
"&&" operator can now be used to test the validity of two of more properties. For example: on property:test.a=1 && property:test.b=1 setprop test.c 1 The above stub sets the test.c to 1 only when both test.a=1 and test.b=1 (cherry-pick of 162f7d797c67019a7a3f08c3b0f0ffc91d548ddc.) Change-Id: I72c19f7aa92231372a416193618ee6c7fd368141 Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
188 lines
4.3 KiB
C
188 lines
4.3 KiB
C
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "parser.h"
|
|
#include "log.h"
|
|
|
|
#define RAW(x...) log_write(6, x)
|
|
|
|
void DUMP(void)
|
|
{
|
|
#if 0
|
|
struct service *svc;
|
|
struct action *act;
|
|
struct command *cmd;
|
|
struct listnode *node;
|
|
struct listnode *node2;
|
|
char name_str[256] = "";
|
|
struct socketinfo *si;
|
|
int n;
|
|
|
|
list_for_each(node, &service_list) {
|
|
svc = node_to_item(node, struct service, slist);
|
|
RAW("service %s\n", svc->name);
|
|
RAW(" class '%s'\n", svc->classname);
|
|
RAW(" exec");
|
|
for (n = 0; n < svc->nargs; n++) {
|
|
RAW(" '%s'", svc->args[n]);
|
|
}
|
|
RAW("\n");
|
|
for (si = svc->sockets; si; si = si->next) {
|
|
RAW(" socket %s %s 0%o\n", si->name, si->type, si->perm);
|
|
}
|
|
}
|
|
|
|
list_for_each(node, &action_list) {
|
|
act = node_to_item(node, struct action, alist);
|
|
RAW("on ");
|
|
build_triggers_string(name_str, sizeof(name_str), act);
|
|
RAW("%s", name_str);
|
|
RAW("\n");
|
|
|
|
list_for_each(node2, &act->commands) {
|
|
cmd = node_to_item(node2, struct command, clist);
|
|
RAW(" %p", cmd->func);
|
|
for (n = 0; n < cmd->nargs; n++) {
|
|
RAW(" %s", cmd->args[n]);
|
|
}
|
|
RAW("\n");
|
|
}
|
|
RAW("\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void parse_error(struct parse_state *state, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
char buf[128];
|
|
int off;
|
|
|
|
snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
|
|
buf[127] = 0;
|
|
off = strlen(buf);
|
|
|
|
va_start(ap, fmt);
|
|
vsnprintf(buf + off, 128 - off, fmt, ap);
|
|
va_end(ap);
|
|
buf[127] = 0;
|
|
ERROR("%s", buf);
|
|
}
|
|
|
|
int next_token(struct parse_state *state)
|
|
{
|
|
char *x = state->ptr;
|
|
char *s;
|
|
|
|
if (state->nexttoken) {
|
|
int t = state->nexttoken;
|
|
state->nexttoken = 0;
|
|
return t;
|
|
}
|
|
|
|
for (;;) {
|
|
switch (*x) {
|
|
case 0:
|
|
state->ptr = x;
|
|
return T_EOF;
|
|
case '\n':
|
|
x++;
|
|
state->ptr = x;
|
|
return T_NEWLINE;
|
|
case ' ':
|
|
case '\t':
|
|
case '\r':
|
|
x++;
|
|
continue;
|
|
case '#':
|
|
while (*x && (*x != '\n')) x++;
|
|
if (*x == '\n') {
|
|
state->ptr = x+1;
|
|
return T_NEWLINE;
|
|
} else {
|
|
state->ptr = x;
|
|
return T_EOF;
|
|
}
|
|
default:
|
|
goto text;
|
|
}
|
|
}
|
|
|
|
textdone:
|
|
state->ptr = x;
|
|
*s = 0;
|
|
return T_TEXT;
|
|
text:
|
|
state->text = s = x;
|
|
textresume:
|
|
for (;;) {
|
|
switch (*x) {
|
|
case 0:
|
|
goto textdone;
|
|
case ' ':
|
|
case '\t':
|
|
case '\r':
|
|
x++;
|
|
goto textdone;
|
|
case '\n':
|
|
state->nexttoken = T_NEWLINE;
|
|
x++;
|
|
goto textdone;
|
|
case '"':
|
|
x++;
|
|
for (;;) {
|
|
switch (*x) {
|
|
case 0:
|
|
/* unterminated quoted thing */
|
|
state->ptr = x;
|
|
return T_EOF;
|
|
case '"':
|
|
x++;
|
|
goto textresume;
|
|
default:
|
|
*s++ = *x++;
|
|
}
|
|
}
|
|
break;
|
|
case '\\':
|
|
x++;
|
|
switch (*x) {
|
|
case 0:
|
|
goto textdone;
|
|
case 'n':
|
|
*s++ = '\n';
|
|
break;
|
|
case 'r':
|
|
*s++ = '\r';
|
|
break;
|
|
case 't':
|
|
*s++ = '\t';
|
|
break;
|
|
case '\\':
|
|
*s++ = '\\';
|
|
break;
|
|
case '\r':
|
|
/* \ <cr> <lf> -> line continuation */
|
|
if (x[1] != '\n') {
|
|
x++;
|
|
continue;
|
|
}
|
|
case '\n':
|
|
/* \ <lf> -> line continuation */
|
|
state->line++;
|
|
x++;
|
|
/* eat any extra whitespace */
|
|
while((*x == ' ') || (*x == '\t')) x++;
|
|
continue;
|
|
default:
|
|
/* unknown escape -- just copy */
|
|
*s++ = *x++;
|
|
}
|
|
continue;
|
|
default:
|
|
*s++ = *x++;
|
|
}
|
|
}
|
|
return T_EOF;
|
|
}
|