platform_system_core/init/parser.c
Badhri Jagan Sridharan 0b41512a2e init: Add support "&&" operator in property triggers
"&&" 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>
2015-02-02 16:21:05 -08:00

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;
}