#
source:
trunk/third/bonobo-activation/server/activation-context-query.c
@
18563

Revision 18563, 25.7 KB checked in by ghudson, 22 years ago (diff) |
---|

Rev | Line | |
---|---|---|

[18310] | 1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ |

2 | /* | |

3 | * oafd: OAF CORBA dameon. | |

4 | * | |

5 | * Copyright (C) 1999, 2000 Red Hat, Inc. | |

6 | * Copyright (C) 1999, 2000 Eazel, Inc. | |

7 | * | |

8 | * This library is free software; you can redistribute it and/or | |

9 | * modify it under the terms of the GNU General Public License as | |

10 | * published by the Free Software Foundation; either version 2 of the | |

11 | * License, or (at your option) any later version. | |

12 | * | |

13 | * This library is distributed in the hope that it will be useful, | |

14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |

15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |

16 | * General Public License for more details. | |

17 | * | |

18 | * You should have received a copy of the GNU General Public License | |

19 | * along with this library; if not, write to the Free Software | |

20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |

21 | * | |

22 | * Authors: Elliot Lee <sopwith@redhat.com>, | |

23 | * | |

24 | */ | |

25 | ||

26 | /* | |

27 | Likely bugs: Forgetting to initialize QueryExprConst.needs_free = crash | |

28 | */ | |

29 | #include <stdio.h> | |

30 | #include <string.h> | |

31 | ||

32 | #include "activation-context-query.h" | |

33 | #include "activation-context-query-parser.h" | |

34 | ||

35 | static QueryExpr * | |

36 | qexp_new (void) | |

37 | { | |

38 | QueryExpr *retval = g_new (QueryExpr, 1); | |

39 | ||

40 | retval->have_cached_value = FALSE; | |

41 | retval->has_fields = TRUE; | |

42 | ||

43 | return retval; | |

44 | } | |

45 | ||

46 | void | |

47 | qexp_free (QueryExpr * qexp) | |

48 | { | |

49 | if (!qexp) | |

50 | return; | |

51 | ||

52 | switch (qexp->type) { | |

53 | case EXPR_FUNCTION: | |

54 | g_free (qexp->u.function_value.func_name); | |

55 | g_slist_foreach (qexp->u.function_value.arguments, | |

56 | (GFunc) qexp_free, NULL); | |

57 | g_slist_free (qexp->u.function_value.arguments); | |

58 | break; | |

59 | case EXPR_VARIABLE: | |

60 | g_free (qexp->u.var_value); | |

61 | break; | |

62 | case EXPR_ID: | |

63 | g_free (qexp->u.id_value); | |

64 | break; | |

65 | case EXPR_BINOP: | |

66 | qexp_free (qexp->u.binop_value.op1); | |

67 | qexp_free (qexp->u.binop_value.op2); | |

68 | break; | |

69 | case EXPR_UNOP: | |

70 | qexp_free (qexp->u.unop_value.op); | |

71 | break; | |

72 | case EXPR_CONSTANT: | |

73 | if (qexp->u.constant_value.value_known) { | |

74 | switch (qexp->u.constant_value.type) { | |

75 | case CONST_STRING: | |

76 | g_free (qexp->u.constant_value.u.v_string); | |

77 | break; | |

78 | case CONST_STRINGV: | |

79 | g_strfreev (qexp->u.constant_value. | |

80 | u.v_stringv); | |

81 | break; | |

82 | default: | |

83 | break; | |

84 | } | |

85 | } | |

86 | break; | |

87 | } | |

88 | ||

89 | g_free (qexp); | |

90 | } | |

91 | ||

92 | QueryExpr * | |

93 | qexp_binop_new (QueryExpr * op1, int operand, QueryExpr * op2) | |

94 | { | |

95 | QueryExpr *retval = qexp_new (); | |

96 | int optype; | |

97 | ||

98 | switch (operand) { | |

99 | case P_MULTIPLY: | |

100 | optype = OP_MULTIPLY; | |

101 | break; | |

102 | case P_DIVIDE: | |

103 | optype = OP_DIVIDE; | |

104 | break; | |

105 | case P_SUBTRACT: | |

106 | optype = OP_SUBTRACT; | |

107 | break; | |

108 | case P_ADD: | |

109 | optype = OP_ADD; | |

110 | break; | |

111 | case P_EQ: | |

112 | optype = OP_EQ; | |

113 | break; | |

114 | case P_NEQ: | |

115 | optype = OP_NEQ; | |

116 | break; | |

117 | case P_LEQ: | |

118 | optype = OP_LEQ; | |

119 | break; | |

120 | case P_GEQ: | |

121 | optype = OP_GEQ; | |

122 | break; | |

123 | case P_GT: | |

124 | optype = OP_GT; | |

125 | break; | |

126 | case P_LT: | |

127 | optype = OP_LT; | |

128 | break; | |

129 | case P_OR: | |

130 | optype = OP_OR; | |

131 | break; | |

132 | case P_AND: | |

133 | optype = OP_AND; | |

134 | break; | |

135 | case P_XOR: | |

136 | optype = OP_XOR; | |

137 | break; | |

138 | default: | |

139 | g_assert_not_reached (); | |

140 | optype = 0; | |

141 | break; | |

142 | } | |

143 | ||

144 | retval->u.binop_value.type = optype; | |

145 | retval->u.binop_value.op1 = op1; | |

146 | retval->u.binop_value.op2 = op2; | |

147 | ||

148 | retval->type = EXPR_BINOP; | |

149 | retval->has_fields = op1->has_fields || op2->has_fields; | |

150 | ||

151 | return retval; | |

152 | } | |

153 | ||

154 | QueryExpr * | |

155 | qexp_unop_new (int operand, QueryExpr * op) | |

156 | { | |

157 | QueryExpr *retval = qexp_new (); | |

158 | int optype; | |

159 | ||

160 | switch (operand) { | |

161 | case P_SUBTRACT: | |

162 | optype = OP_SUBTRACT; | |

163 | break; | |

164 | case P_NOT: | |

165 | optype = OP_NOT; | |

166 | break; | |

167 | default: | |

168 | g_assert_not_reached (); | |

169 | optype = 0; | |

170 | break; | |

171 | } | |

172 | ||

173 | retval->type = EXPR_UNOP; | |

174 | retval->u.unop_value.type = optype; | |

175 | retval->u.unop_value.op = op; | |

176 | ||

177 | retval->has_fields = op->has_fields; | |

178 | ||

179 | return retval; | |

180 | } | |

181 | ||

182 | QueryExpr * | |

183 | qexp_function_new (char *name, GSList * exprlist) | |

184 | { | |

185 | GSList *cur; | |

186 | QueryExpr *retval = qexp_new (); | |

187 | ||

188 | retval->type = EXPR_FUNCTION; | |

189 | retval->u.function_value.func_name = name; | |

190 | retval->u.function_value.arguments = exprlist; | |

191 | ||

192 | cur = exprlist; | |

193 | ||

194 | while (cur != NULL && !((QueryExpr *) cur->data)->has_fields) { | |

195 | cur = cur->next; | |

196 | } | |

197 | ||

198 | retval->has_fields = cur ? TRUE : FALSE; | |

199 | ||

200 | return retval; | |

201 | } | |

202 | ||

203 | QueryExpr * | |

204 | qexp_variable_new (char *name) | |

205 | { | |

206 | QueryExpr *retval = qexp_new (); | |

207 | ||

208 | retval->type = EXPR_VARIABLE; | |

209 | retval->u.var_value = name; | |

210 | ||

211 | retval->has_fields = FALSE; | |

212 | ||

213 | return retval; | |

214 | } | |

215 | ||

216 | QueryExpr * | |

217 | qexp_id_new (char *name) | |

218 | { | |

219 | QueryExpr *retval = qexp_new (); | |

220 | ||

221 | retval->type = EXPR_ID; | |

222 | retval->u.var_value = name; | |

223 | ||

224 | retval->has_fields = TRUE; | |

225 | ||

226 | return retval; | |

227 | } | |

228 | ||

229 | QueryExpr * | |

230 | qexp_constant_new (QueryExprConst setme) | |

231 | { | |

232 | QueryExpr *retval = qexp_new (); | |

233 | ||

234 | retval->type = EXPR_CONSTANT; | |

235 | retval->u.constant_value = setme; | |

236 | retval->u.constant_value.value_known = TRUE; | |

237 | ||

238 | retval->has_fields = FALSE; | |

239 | ||

240 | return retval; | |

241 | } | |

242 | ||

243 | void | |

244 | qexp_dump (QueryExpr * exp) | |

245 | { | |

246 | switch (exp->type) { | |

247 | case EXPR_FUNCTION: | |

248 | { | |

249 | GSList *cur; | |

250 | ||

251 | g_print ("%s(", exp->u.function_value.func_name); | |

252 | for (cur = exp->u.function_value.arguments; cur; | |

253 | cur = cur->next) { | |

254 | qexp_dump (cur->data); | |

255 | if (cur->next) | |

256 | g_print (", "); | |

257 | } | |

258 | g_print (")"); | |

259 | } | |

260 | break; | |

261 | case EXPR_VARIABLE: | |

262 | g_print ("$%s", exp->u.var_value); | |

263 | break; | |

264 | case EXPR_ID: | |

265 | g_print ("%s", exp->u.id_value); | |

266 | break; | |

267 | case EXPR_BINOP: | |

268 | { | |

269 | char *opc; | |

270 | ||

271 | g_print ("("); | |

272 | qexp_dump (exp->u.binop_value.op1); | |

273 | g_print (")"); | |

274 | switch (exp->u.binop_value.type) { | |

275 | case OP_EQ: | |

276 | opc = "="; | |

277 | break; | |

278 | case OP_NEQ: | |

279 | opc = "!="; | |

280 | break; | |

281 | case OP_LEQ: | |

282 | opc = "<="; | |

283 | break; | |

284 | case OP_GEQ: | |

285 | opc = ">="; | |

286 | break; | |

287 | case OP_LT: | |

288 | opc = "<"; | |

289 | break; | |

290 | case OP_GT: | |

291 | opc = ">"; | |

292 | break; | |

293 | case OP_OR: | |

294 | opc = "||"; | |

295 | break; | |

296 | case OP_AND: | |

297 | opc = "&&"; | |

298 | break; | |

299 | case OP_MULTIPLY: | |

300 | opc = "*"; | |

301 | break; | |

302 | case OP_DIVIDE: | |

303 | opc = "/"; | |

304 | break; | |

305 | case OP_ADD: | |

306 | opc = "+"; | |

307 | break; | |

308 | case OP_SUBTRACT: | |

309 | opc = "-"; | |

310 | break; | |

311 | case OP_XOR: | |

312 | opc = "^"; | |

313 | break; | |

314 | default: | |

315 | opc = NULL; | |

316 | break; | |

317 | } | |

318 | g_print (" %s (", opc); | |

319 | qexp_dump (exp->u.binop_value.op2); | |

320 | g_print (")"); | |

321 | } | |

322 | break; | |

323 | case EXPR_UNOP: | |

324 | switch (exp->u.unop_value.type) { | |

325 | case OP_NOT: | |

326 | g_print ("~("); | |

327 | break; | |

328 | case OP_NEGATE: | |

329 | g_print ("-("); | |

330 | break; | |

331 | } | |

332 | qexp_dump (exp->u.unop_value.op); | |

333 | g_print (")"); | |

334 | break; | |

335 | case EXPR_CONSTANT: | |

336 | qexp_constant_dump (&exp->u.constant_value); | |

337 | break; | |

338 | default: | |

339 | g_error ("Unknown exp type %d", exp->type); | |

340 | break; | |

341 | } | |

342 | } | |

343 | ||

344 | void | |

345 | qexp_constant_dump (QueryExprConst * c) | |

346 | { | |

347 | if (c->value_known) { | |

348 | switch (c->type) { | |

349 | case CONST_STRINGV: | |

350 | { | |

351 | int i; | |

352 | ||

353 | g_print ("["); | |

354 | for (i = 0; c->u.v_stringv[i]; i++) { | |

355 | g_print ("'%s'", c->u.v_stringv[i]); | |

356 | if (c->u.v_stringv[i + 1]) | |

357 | g_print (", "); | |

358 | } | |

359 | g_print ("]"); | |

360 | } | |

361 | break; | |

362 | case CONST_STRING: | |

363 | g_print ("'%s'", c->u.v_string); | |

364 | break; | |

365 | case CONST_NUMBER: | |

366 | g_print ("%f", c->u.v_number); | |

367 | break; | |

368 | case CONST_BOOLEAN: | |

369 | g_print ("%s", c->u.v_boolean ? "TRUE" : "FALSE"); | |

370 | break; | |

371 | } | |

372 | } else | |

373 | g_print ("??"); | |

374 | } | |

375 | ||

376 | /* Returns a value suitable for use in boolean expressions */ | |

377 | static gboolean | |

378 | qexp_constant_bool (const QueryExprConst * c) | |

379 | { | |

380 | if (c->value_known) | |

381 | switch (c->type) { | |

382 | case CONST_BOOLEAN: | |

383 | return c->u.v_boolean; | |

384 | case CONST_NUMBER: | |

385 | return (c->u.v_number != 0.0); | |

386 | case CONST_STRING: | |

387 | return (c->u.v_string != NULL); | |

388 | case CONST_STRINGV: | |

389 | return (c->u.v_stringv != NULL); | |

390 | } | |

391 | ||

392 | return FALSE; | |

393 | } | |

394 | ||

395 | gint | |

396 | qexp_constant_compare (const QueryExprConst * c1, const QueryExprConst * c2) | |

397 | { | |

398 | if (c1->value_known && c2->value_known) { | |

399 | g_return_val_if_fail (c1->type == c2->type, 0); | |

400 | ||

401 | switch (c1->type) { | |

402 | case CONST_STRING: | |

403 | return strcmp (c1->u.v_string, c2->u.v_string); | |

404 | break; | |

405 | case CONST_BOOLEAN: | |

406 | if (c1->u.v_boolean && !c2->u.v_boolean) | |

407 | return -1; | |

408 | else if (c2->u.v_boolean && !c1->u.v_boolean) | |

409 | return 1; | |

410 | else | |

411 | return 0; | |

412 | break; | |

413 | case CONST_NUMBER: | |

414 | { | |

415 | if (c2->u.v_number > c1->u.v_number) | |

416 | return 1; | |

417 | else if (c2->u.v_number < c1->u.v_number) | |

418 | return -1; | |

419 | else | |

420 | return 0; | |

421 | } | |

422 | break; | |

423 | default: | |

424 | g_assert_not_reached (); | |

425 | break; | |

426 | } | |

427 | } else if (c1->value_known) | |

428 | return -1; | |

429 | else if (c2->value_known) | |

430 | return 1; | |

431 | ||

432 | return 0; | |

433 | } | |

434 | ||

435 | #define qexp_constant_unuse(c) if ((c).needs_free && (c).value_known) qexp_constant_free(&(c)) | |

436 | static void | |

437 | qexp_constant_free (const QueryExprConst * c) | |

438 | { | |

439 | switch (c->type) { | |

440 | case CONST_STRING: | |

441 | g_free (c->u.v_string); | |

442 | break; | |

443 | case CONST_STRINGV: | |

444 | g_strfreev (c->u.v_stringv); | |

445 | break; | |

446 | default: | |

447 | break; | |

448 | } | |

449 | } | |

450 | ||

451 | ||

452 | /********************************************* Now the fun stuff *****************************************/ | |

453 | ||

454 | /******* handling functions *********/ | |

455 | ||

456 | ||

457 | typedef QueryExprConst (*QueryExprEvalFunc) (Bonobo_ServerInfo * si, | |

458 | QueryExpr * e, | |

459 | QueryContext * qctx); | |

460 | /* A table of the functions that can be used in queries */ | |

461 | typedef struct | |

462 | { | |

463 | const char *name; | |

464 | QueryExprEvalFunc efunc; | |

465 | int min_args, max_args; | |

466 | } | |

467 | QueryExprFuncInfo; | |

468 | ||

469 | static QueryExprConst qexp_func_has_one (Bonobo_ServerInfo * si, QueryExpr * e, | |

470 | QueryContext * qctx); | |

471 | static QueryExprConst qexp_func_has_all (Bonobo_ServerInfo * si, QueryExpr * e, | |

472 | QueryContext * qctx); | |

473 | static QueryExprConst qexp_func_has (Bonobo_ServerInfo * si, QueryExpr * e, | |

474 | QueryContext * qctx); | |

475 | ||

476 | static QueryExprConst qexp_func_prefer_by_list_order (Bonobo_ServerInfo * si, QueryExpr * e, | |

477 | QueryContext * qctx); | |

478 | ||

479 | static QueryExprConst qexp_func_defined (Bonobo_ServerInfo * si, QueryExpr * e, | |

480 | QueryContext * qctx); | |

481 | static QueryExprConst qexp_func_max (Bonobo_ServerInfo * si, QueryExpr * e, | |

482 | QueryContext * qctx); | |

483 | static QueryExprConst qexp_func_min (Bonobo_ServerInfo * si, QueryExpr * e, | |

484 | QueryContext * qctx); | |

485 | ||

486 | static const QueryExprFuncInfo qexp_func_impls[] = { | |

487 | {"has_one", qexp_func_has_one, 2}, | |

488 | {"has_all", qexp_func_has_all, 2}, | |

489 | {"has", qexp_func_has, 2}, | |

490 | {"prefer_by_list_order", qexp_func_prefer_by_list_order, 2}, | |

491 | {"defined", qexp_func_defined, 1}, | |

492 | {"max", qexp_func_max, 1}, | |

493 | {"min", qexp_func_min, 1}, | |

494 | {NULL} | |

495 | }; | |

496 | ||

497 | static QueryExprConst | |

498 | qexp_evaluate_function (Bonobo_ServerInfo * si, QueryExpr * e, | |

499 | QueryContext * qctx) | |

500 | { | |

501 | QueryExprConst retval; | |

502 | const char *func_name; | |

503 | int i, n, max; | |

504 | const QueryExprFuncInfo *fi; | |

505 | ||

506 | func_name = e->u.function_value.func_name; | |

507 | ||

508 | for (i = 0; qexp_func_impls[i].name; i++) { | |

509 | if (!g_ascii_strcasecmp (func_name, qexp_func_impls[i].name)) | |

510 | break; | |

511 | } | |

512 | ||

513 | fi = &qexp_func_impls[i]; | |

514 | if (!fi->name) { | |

515 | retval.value_known = FALSE; | |

516 | retval.needs_free = FALSE; | |

517 | g_warning ("Invalid function name '%s'", func_name); | |

518 | return retval; | |

519 | } | |

520 | ||

521 | n = g_slist_length (e->u.function_value.arguments); | |

522 | ||

523 | max = fi->max_args; | |

524 | if (max < fi->min_args) | |

525 | max = fi->min_args; | |

526 | if ((n < fi->min_args) || (n > max)) { | |

527 | g_warning | |

528 | ("Incorrect argument count to function '%s': got %d, need between %d and %d", | |

529 | func_name, n, fi->min_args, max); | |

530 | } | |

531 | ||

532 | return fi->efunc (si, e, qctx); | |

533 | ||

534 | } | |

535 | ||

536 | static QueryExprConst | |

537 | qexp_func_has_one (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

538 | { | |

539 | QueryExprConst retval, v1, v2; | |

540 | int i, j; | |

541 | gboolean found; | |

542 | char **check_one, **check_two; | |

543 | ||

544 | v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx); | |

545 | v2 = | |

546 | qexp_evaluate (si, e->u.function_value.arguments->next->data, | |

547 | qctx); | |

548 | ||

549 | retval.value_known = TRUE; | |

550 | ||

551 | if (!v1.value_known || !v2.value_known) { | |

552 | retval.type = CONST_BOOLEAN; | |

553 | retval.u.v_boolean = FALSE; | |

554 | } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRINGV) { | |

555 | retval.value_known = FALSE; | |

556 | } else { | |

557 | found = FALSE; | |

558 | ||

559 | check_one = v1.u.v_stringv; | |

560 | check_two = v2.u.v_stringv; | |

561 | ||

562 | for (i = j = 0; check_one[i]; i++) { | |

563 | for (j = 0; check_two[j]; j++) { | |

564 | if (!strcmp (check_one[i], check_two[j])) { | |

565 | found = TRUE; | |

566 | break; | |

567 | } | |

568 | } | |

569 | } | |

570 | ||

571 | retval.type = CONST_BOOLEAN; | |

572 | retval.u.v_boolean = found; | |

573 | } | |

574 | ||

575 | retval.needs_free = FALSE; | |

576 | qexp_constant_unuse (v1); | |

577 | qexp_constant_unuse (v2); | |

578 | ||

579 | return retval; | |

580 | } | |

581 | ||

582 | static QueryExprConst | |

583 | qexp_func_has_all (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

584 | { | |

585 | QueryExprConst retval, v1, v2; | |

586 | int i, j; | |

587 | char **check_one, **check_two; | |

588 | ||

589 | v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx); | |

590 | v2 = | |

591 | qexp_evaluate (si, e->u.function_value.arguments->next->data, | |

592 | qctx); | |

593 | ||

594 | retval.value_known = TRUE; | |

595 | ||

596 | if (!v1.value_known || !v2.value_known) { | |

597 | retval.type = CONST_BOOLEAN; | |

598 | retval.u.v_boolean = FALSE; | |

599 | } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRINGV) { | |

600 | retval.value_known = FALSE; | |

601 | } else { | |

602 | check_one = v1.u.v_stringv; | |

603 | check_two = v2.u.v_stringv; | |

604 | ||

605 | for (i = j = 0; check_two[j] && check_one[i]; j++) { | |

606 | for (i = 0; check_one[i]; i++) { | |

607 | if (!strcmp (check_two[j], check_one[i])) | |

608 | break; | |

609 | } | |

610 | } | |

611 | ||

612 | retval.type = CONST_BOOLEAN; | |

613 | retval.u.v_boolean = check_one[i] ? TRUE : FALSE; | |

614 | } | |

615 | ||

616 | retval.needs_free = FALSE; | |

617 | ||

618 | qexp_constant_unuse (v1); | |

619 | qexp_constant_unuse (v2); | |

620 | ||

621 | return retval; | |

622 | } | |

623 | ||

624 | static QueryExprConst | |

625 | qexp_func_has (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

626 | { | |

627 | QueryExprConst retval, v1, v2; | |

628 | char **check_one, *check_two; | |

629 | int i; | |

630 | ||

631 | v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx); | |

632 | v2 = | |

633 | qexp_evaluate (si, e->u.function_value.arguments->next->data, | |

634 | qctx); | |

635 | ||

636 | retval.value_known = TRUE; | |

637 | ||

638 | if (!v1.value_known || !v2.value_known) { | |

639 | retval.type = CONST_BOOLEAN; | |

640 | retval.u.v_boolean = FALSE; | |

641 | } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRING) { | |

642 | retval.value_known = FALSE; | |

643 | } else { | |

644 | check_one = v1.u.v_stringv; | |

645 | check_two = v2.u.v_string; | |

646 | ||

647 | for (i = 0; check_one[i]; i++) { | |

648 | if (!strcmp (check_one[i], check_two)) | |

649 | break; | |

650 | } | |

651 | ||

652 | retval.type = CONST_BOOLEAN; | |

653 | retval.u.v_boolean = check_one[i] ? TRUE : FALSE; | |

654 | } | |

655 | ||

656 | retval.needs_free = FALSE; | |

657 | ||

658 | qexp_constant_unuse (v1); | |

659 | qexp_constant_unuse (v2); | |

660 | ||

661 | return retval; | |

662 | } | |

663 | ||

664 | ||

665 | ||

666 | static QueryExprConst | |

667 | qexp_func_prefer_by_list_order (Bonobo_ServerInfo *si, | |

668 | QueryExpr *e, | |

669 | QueryContext *qctx) | |

670 | { | |

671 | QueryExprConst retval, item, list; | |

672 | char **check_one, *check_two; | |

673 | int i; | |

674 | int position; | |

675 | ||

676 | item = qexp_evaluate (si, e->u.function_value.arguments->data, qctx); | |

677 | list = qexp_evaluate (si, e->u.function_value.arguments->next->data, qctx); | |

678 | ||

679 | retval.value_known = TRUE; | |

680 | ||

681 | if (!item.value_known || !list.value_known) { | |

682 | retval.type = CONST_BOOLEAN; | |

683 | retval.u.v_boolean = FALSE; | |

684 | } else if (item.type != CONST_STRING || list.type != CONST_STRINGV) { | |

685 | retval.value_known = FALSE; | |

686 | } else { | |

687 | position = -1; | |

688 | ||

689 | check_one = list.u.v_stringv; | |

690 | check_two = item.u.v_string; | |

691 | ||

692 | for (i = 0; check_one[i] != NULL; i++) { | |

693 | if (position == -1 && | |

694 | strcmp (check_one[i], check_two) == 0) { | |

695 | position = i; | |

696 | } | |

697 | } | |

698 | ||

699 | if (position != -1) { | |

700 | position = i - position; | |

701 | } | |

702 | ||

703 | retval.type = CONST_NUMBER; | |

704 | retval.u.v_number = position; | |

705 | } | |

706 | ||

707 | retval.needs_free = FALSE; | |

708 | ||

709 | qexp_constant_unuse (item); | |

710 | qexp_constant_unuse (list); | |

711 | ||

712 | return retval; | |

713 | } | |

714 | ||

715 | ||

716 | static QueryExprConst | |

717 | qexp_func_defined (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

718 | { | |

719 | QueryExprConst retval, v1; | |

720 | ||

721 | v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx); | |

722 | ||

723 | retval.value_known = TRUE; | |

724 | ||

725 | retval.type = CONST_BOOLEAN; | |

726 | ||

727 | retval.u.v_boolean = v1.value_known ? TRUE : FALSE; | |

728 | ||

729 | retval.needs_free = FALSE; | |

730 | ||

731 | qexp_constant_unuse (v1); | |

732 | ||

733 | return retval; | |

734 | } | |

735 | ||

736 | ||

737 | static QueryExprConst | |

738 | qexp_func_max (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

739 | { | |

740 | int i; | |

741 | QueryExprConst max_val_so_far; | |

742 | ||

743 | max_val_so_far.value_known = FALSE; | |

744 | ||

745 | for (i = 0; i < qctx->nservers; i++) { | |

746 | QueryExprConst new_val; | |

747 | ||

748 | new_val = | |

749 | qexp_evaluate (qctx->sil[i], | |

750 | e->u.function_value.arguments->data, | |

751 | qctx); | |

752 | if (qexp_constant_compare (&max_val_so_far, &new_val) > 0) | |

753 | max_val_so_far = new_val; | |

754 | } | |

755 | ||

756 | /* The value of this function never changes on a per-record basis, so we never have to revaluate it */ | |

757 | e->has_fields = FALSE; | |

758 | ||

759 | return max_val_so_far; | |

760 | } | |

761 | ||

762 | static QueryExprConst | |

763 | qexp_func_min (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

764 | { | |

765 | int i; | |

766 | QueryExprConst min_val_so_far; | |

767 | ||

768 | min_val_so_far.value_known = FALSE; | |

769 | ||

770 | for (i = 0; i < qctx->nservers; i++) { | |

771 | QueryExprConst new_val; | |

772 | ||

773 | new_val = | |

774 | qexp_evaluate (qctx->sil[i], | |

775 | e->u.function_value.arguments->data, | |

776 | qctx); | |

777 | if (qexp_constant_compare (&min_val_so_far, &new_val) > 0) | |

778 | min_val_so_far = new_val; | |

779 | } | |

780 | ||

781 | /* see comment in qexp_func_max */ | |

782 | e->has_fields = FALSE; | |

783 | ||

784 | return min_val_so_far; | |

785 | } | |

786 | ||

787 | /********** Variables *******/ | |

788 | ||

789 | static QueryExprConst | |

790 | qexp_evaluate_variable (Bonobo_ServerInfo * si, QueryExpr * e, | |

791 | QueryContext * qctx) | |

792 | { | |

793 | QueryExprConst retval; | |

794 | ||

795 | retval.value_known = FALSE; | |

796 | ||

797 | if (qctx->cctx) { | |

798 | CORBA_Environment ev; | |

799 | CORBA_NVList nvout; | |

800 | ||

801 | CORBA_exception_init (&ev); | |

802 | CORBA_Context_get_values (qctx->cctx, NULL, 0, e->u.var_value, | |

803 | &nvout, &ev); | |

804 | ||

805 | /* FIXME bugzilla.eazel.com 2732: non-standard - I | |

806 | * screwed up the NVList implementation in ORBit */ | |

807 | ||

808 | if (ev._major == CORBA_NO_EXCEPTION) { | |

809 | if (nvout->list->len > 0) { | |

810 | CORBA_NamedValue *nv; | |

811 | retval.value_known = TRUE; | |

812 | retval.type = CONST_STRING; | |

813 | nv = | |

814 | &g_array_index (nvout->list, | |

815 | CORBA_NamedValue, 0); | |

816 | retval.u.v_string = | |

817 | g_strdup (*(char **) nv-> | |

818 | argument._value); | |

819 | retval.needs_free = TRUE; | |

820 | } else | |

821 | g_warning ("Unknown variable %s", | |

822 | e->u.var_value); | |

823 | ||

824 | CORBA_NVList_free (nvout, &ev); | |

825 | } else | |

826 | g_warning ("Unknown variable %s", e->u.var_value); | |

827 | ||

828 | CORBA_exception_free (&ev); | |

829 | } else | |

830 | g_warning ("Unknown variable %s", e->u.var_value); | |

831 | ||

832 | return retval; | |

833 | } | |

834 | ||

835 | /********* fields ***********/ | |

836 | static QueryExprConst | |

837 | qexp_evaluate_id (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

838 | { | |

839 | QueryExprConst retval; | |

840 | ||

841 | retval.value_known = retval.needs_free = FALSE; | |

842 | ||

843 | if (si) { | |

844 | retval.value_known = TRUE; | |

845 | retval.type = CONST_STRING; | |

846 | if (!g_ascii_strcasecmp (e->u.id_value, "location_info")) | |

847 | retval.u.v_string = si->location_info; | |

848 | else if (!g_ascii_strcasecmp (e->u.id_value, "server_type")) | |

849 | retval.u.v_string = si->server_type; | |

850 | else if (!g_ascii_strcasecmp (e->u.id_value, "iid")) | |

851 | retval.u.v_string = si->iid; | |

852 | else if (!g_ascii_strcasecmp (e->u.id_value, "username")) | |

853 | retval.u.v_string = si->username; | |

854 | else if (!g_ascii_strcasecmp (e->u.id_value, "hostname")) | |

855 | retval.u.v_string = si->hostname; | |

856 | else { | |

857 | int i; | |

858 | for (i = 0; i < si->props._length; i++) { | |

859 | if (!strcmp | |

860 | (e->u.id_value, | |

861 | si->props._buffer[i].name)) break; | |

862 | } | |

863 | ||

864 | retval.value_known = FALSE; | |

865 | ||

866 | if (i < si->props._length) { | |

867 | Bonobo_ActivationPropertyValue *av; | |

868 | ||

869 | av = &si->props._buffer[i].v; | |

870 | ||

871 | switch (av->_d) { | |

872 | case Bonobo_ACTIVATION_P_STRING: | |

873 | retval.type = CONST_STRING; | |

874 | retval.u.v_string = | |

875 | av->_u.value_string; | |

876 | break; | |

877 | case Bonobo_ACTIVATION_P_NUMBER: | |

878 | retval.type = CONST_NUMBER; | |

879 | retval.u.v_number = | |

880 | av->_u.value_number; | |

881 | break; | |

882 | case Bonobo_ACTIVATION_P_BOOLEAN: | |

883 | retval.type = CONST_BOOLEAN; | |

884 | retval.u.v_boolean = | |

885 | av->_u.value_boolean; | |

886 | break; | |

887 | case Bonobo_ACTIVATION_P_STRINGV: | |

888 | { | |

889 | /* FIXME bugzilla.eazel.com 2729: it would be nice to replace the | |

890 | * NULL-terminated string arrays with | |

891 | * CORBA_sequence_string all over | |

892 | */ | |

893 | ||

894 | int i; | |

895 | retval.type = CONST_STRINGV; | |

896 | ||

897 | retval.needs_free = TRUE; | |

898 | ||

899 | retval.u.v_stringv = | |

900 | g_malloc (sizeof | |

901 | (char *) * | |

902 | (av-> | |

903 | _u.value_stringv._length | |

904 | + 1)); | |

905 | for (i = 0; | |

906 | i < | |

907 | av->_u. | |

908 | value_stringv._length; | |

909 | i++) retval. | |

910 | u.v_stringv[i] | |

911 | = | |

912 | g_strdup | |

913 | (av->_u.value_stringv._buffer | |

914 | [i]); | |

915 | retval.u.v_stringv[i] = NULL; | |

916 | } | |

917 | break; | |

918 | } | |

919 | ||

920 | retval.value_known = TRUE; | |

921 | } else if (qctx->id_evaluator) | |

922 | retval = | |

923 | qctx->id_evaluator (si, e->u.id_value, | |

924 | qctx); | |

925 | } | |

926 | } | |

927 | ||

928 | return retval; | |

929 | } | |

930 | ||

931 | /********* binary operators *********/ | |

932 | ||

933 | static QueryExprConst | |

934 | qexp_evaluate_binop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

935 | { | |

936 | QueryExprConst retval, v1, v2; | |

937 | gboolean negate_result = FALSE; | |

938 | ||

939 | v2.value_known = FALSE; /* To make sure that qexp_constant_unuse works properly if we short-circuit */ | |

940 | ||

941 | retval.value_known = TRUE; | |

942 | retval.needs_free = FALSE; | |

943 | ||

944 | v1 = qexp_evaluate (si, e->u.binop_value.op1, qctx); | |

945 | ||

946 | /* Perform short-circuiting */ | |

947 | switch (e->u.binop_value.type) { | |

948 | case OP_OR: | |

949 | if (v1.value_known && qexp_constant_bool (&v1)) { | |

950 | retval.type = CONST_BOOLEAN; | |

951 | retval.u.v_boolean = TRUE; | |

952 | qexp_constant_unuse (v1); | |

953 | return retval; | |

954 | } | |

955 | break; | |

956 | case OP_AND: | |

957 | if (v1.value_known && !qexp_constant_bool (&v1)) { | |

958 | retval.type = CONST_BOOLEAN; | |

959 | retval.u.v_boolean = FALSE; | |

960 | qexp_constant_unuse (v1); | |

961 | return retval; | |

962 | } | |

963 | break; | |

964 | default: | |

965 | break; | |

966 | } | |

967 | ||

968 | v2 = qexp_evaluate (si, e->u.binop_value.op2, qctx); | |

969 | ||

970 | retval.value_known = TRUE; | |

971 | ||

972 | switch (e->u.binop_value.type) { | |

973 | case OP_NEQ: | |

974 | negate_result = TRUE; | |

975 | case OP_EQ: | |

976 | retval.type = CONST_BOOLEAN; | |

977 | retval.u.v_boolean = qexp_constant_compare (&v1, &v2) == 0; | |

978 | break; | |

979 | case OP_GEQ: | |

980 | negate_result = TRUE; | |

981 | case OP_LT: | |

982 | retval.type = CONST_BOOLEAN; | |

983 | retval.u.v_boolean = qexp_constant_compare (&v1, &v2) < 0; | |

984 | break; | |

985 | case OP_LEQ: | |

986 | negate_result = TRUE; | |

987 | case OP_GT: | |

988 | retval.type = CONST_BOOLEAN; | |

989 | retval.u.v_boolean = qexp_constant_compare (&v1, &v2) > 0; | |

990 | break; | |

991 | case OP_OR: | |

992 | retval.type = CONST_BOOLEAN; | |

993 | retval.u.v_boolean = qexp_constant_bool (&v1) | |

994 | || qexp_constant_bool (&v2); | |

995 | break; | |

996 | case OP_AND: | |

997 | retval.type = CONST_BOOLEAN; | |

998 | retval.u.v_boolean = qexp_constant_bool (&v1) | |

999 | && qexp_constant_bool (&v2); | |

1000 | break; | |

1001 | case OP_MULTIPLY: | |

1002 | if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER) | |

1003 | retval.value_known = FALSE; | |

1004 | else { | |

1005 | retval.type = CONST_NUMBER; | |

1006 | retval.u.v_number = v1.u.v_number * v2.u.v_number; | |

1007 | } | |

1008 | break; | |

1009 | case OP_DIVIDE: | |

1010 | if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER) | |

1011 | retval.value_known = FALSE; | |

1012 | else { | |

1013 | retval.type = CONST_NUMBER; | |

1014 | if (v2.u.v_number == 0.0) | |

1015 | retval.value_known = FALSE; | |

1016 | else | |

1017 | retval.u.v_number = | |

1018 | v1.u.v_number / v2.u.v_number; | |

1019 | } | |

1020 | break; | |

1021 | case OP_ADD: | |

1022 | if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER) | |

1023 | retval.value_known = FALSE; | |

1024 | else { | |

1025 | retval.type = CONST_NUMBER; | |

1026 | retval.u.v_number = v1.u.v_number + v2.u.v_number; | |

1027 | } | |

1028 | break; | |

1029 | case OP_SUBTRACT: | |

1030 | if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER) | |

1031 | retval.value_known = FALSE; | |

1032 | else { | |

1033 | retval.type = CONST_NUMBER; | |

1034 | retval.u.v_number = v1.u.v_number - v2.u.v_number; | |

1035 | } | |

1036 | break; | |

1037 | case OP_XOR: | |

1038 | retval.type = CONST_BOOLEAN; | |

1039 | retval.u.v_boolean = | |

1040 | qexp_constant_bool (&v1) ^ qexp_constant_bool (&v2); | |

1041 | break; | |

1042 | } | |

1043 | ||

1044 | if (negate_result) | |

1045 | retval.u.v_boolean = !retval.u.v_boolean; | |

1046 | ||

1047 | qexp_constant_unuse (v1); | |

1048 | qexp_constant_unuse (v2); | |

1049 | ||

1050 | return retval; | |

1051 | } | |

1052 | ||

1053 | /********** unary operators **********/ | |

1054 | static QueryExprConst | |

1055 | qexp_evaluate_unop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

1056 | { | |

1057 | QueryExprConst retval, v1; | |

1058 | ||

1059 | retval.value_known = TRUE; | |

1060 | ||

1061 | v1 = qexp_evaluate (si, e->u.unop_value.op, qctx); | |

1062 | switch (e->u.unop_value.type) { | |

1063 | case OP_NOT: | |

1064 | retval.type = CONST_BOOLEAN; | |

1065 | retval.u.v_boolean = !qexp_constant_bool (&v1); | |

1066 | break; | |

1067 | case OP_NEGATE: | |

1068 | if (v1.type != CONST_NUMBER) | |

1069 | retval.value_known = FALSE; | |

1070 | else { | |

1071 | retval.type = CONST_NUMBER; | |

1072 | retval.u.v_number = -(v1.u.v_number); | |

1073 | } | |

1074 | break; | |

1075 | } | |

1076 | ||

1077 | qexp_constant_unuse (v1); | |

1078 | ||

1079 | return retval; | |

1080 | } | |

1081 | ||

1082 | /********** constants ************/ | |

1083 | static QueryExprConst | |

1084 | qexp_evaluate_constant (Bonobo_ServerInfo * si, QueryExpr * e, | |

1085 | QueryContext * qctx) | |

1086 | { | |

1087 | return e->u.constant_value; | |

1088 | } | |

1089 | ||

1090 | /***** The grand poobah of functions *****/ | |

1091 | QueryExprConst | |

1092 | qexp_evaluate (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

1093 | { | |

1094 | QueryExprConst retval; | |

1095 | ||

1096 | if (e->have_cached_value) { | |

1097 | retval = e->cached_value; | |

1098 | } else { | |

1099 | switch (e->type) { | |

1100 | case EXPR_FUNCTION: | |

1101 | retval = qexp_evaluate_function (si, e, qctx); | |

1102 | break; | |

1103 | case EXPR_VARIABLE: | |

1104 | retval = qexp_evaluate_variable (si, e, qctx); | |

1105 | break; | |

1106 | case EXPR_ID: | |

1107 | retval = qexp_evaluate_id (si, e, qctx); | |

1108 | break; | |

1109 | case EXPR_BINOP: | |

1110 | retval = qexp_evaluate_binop (si, e, qctx); | |

1111 | break; | |

1112 | case EXPR_UNOP: | |

1113 | retval = qexp_evaluate_unop (si, e, qctx); | |

1114 | break; | |

1115 | case EXPR_CONSTANT: | |

1116 | retval = qexp_evaluate_constant (si, e, qctx); | |

1117 | break; | |

1118 | } | |

1119 | } | |

1120 | ||

1121 | if (!e->has_fields) { | |

1122 | e->cached_value = retval; | |

1123 | e->have_cached_value = TRUE; | |

1124 | retval.needs_free = FALSE; /* We don't want people freeing our cached value... */ | |

1125 | } | |

1126 | ||

1127 | return retval; | |

1128 | } | |

1129 | ||

1130 | gboolean | |

1131 | qexp_matches (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx) | |

1132 | { | |

1133 | QueryExprConst res; | |

1134 | gboolean retval; | |

1135 | ||

1136 | res = qexp_evaluate (si, e, qctx); | |

1137 | ||

1138 | retval = qexp_constant_bool (&res); | |

1139 | ||

1140 | qexp_constant_unuse (res); | |

1141 | ||

1142 | return retval; | |

1143 | } | |

1144 | ||

1145 | typedef struct | |

1146 | { | |

1147 | QueryExpr **sexps; | |

1148 | int nexps; | |

1149 | QueryContext *qctx; | |

1150 | } | |

1151 | QexpSortData; | |

1152 | ||

1153 | ||

1154 | static int | |

1155 | qexp_sort_compare (gconstpointer a, gconstpointer b, gpointer user_data) | |

1156 | { | |

1157 | Bonobo_ServerInfo *x = * (Bonobo_ServerInfo **) a; | |

1158 | Bonobo_ServerInfo *y = * (Bonobo_ServerInfo **) b; | |

1159 | QexpSortData * sort_data = user_data; | |

1160 | int i; | |

1161 | ||

1162 | if (x == NULL) { | |

1163 | return 1; | |

1164 | } | |

1165 | ||

1166 | if (y == NULL) { | |

1167 | return -1; | |

1168 | } | |

1169 | ||

1170 | for (i = 0; i < sort_data->nexps; i++) { | |

1171 | QueryExprConst cx, cy; | |

1172 | int res; | |

1173 | ||

1174 | cx = qexp_evaluate (x, sort_data->sexps[i], sort_data->qctx); | |

1175 | cy = qexp_evaluate (y, sort_data->sexps[i], sort_data->qctx); | |

1176 | ||

1177 | res = qexp_constant_compare (&cx, &cy); | |

1178 | ||

1179 | qexp_constant_unuse (cx); | |

1180 | qexp_constant_unuse (cy); | |

1181 | ||

1182 | if (res > 0) | |

1183 | return 1; | |

1184 | else if (res < 0) | |

1185 | return -1; | |

1186 | } | |

1187 | ||

1188 | return 0; | |

1189 | } | |

1190 | ||

1191 | void | |

1192 | qexp_sort (Bonobo_ServerInfo ** servers, int nservers, QueryExpr ** sexps, | |

1193 | int nexps, QueryContext * qctx) | |

1194 | { | |

1195 | QexpSortData sort_data; | |

1196 | ||

1197 | sort_data.sexps = sexps; | |

1198 | sort_data.nexps = nexps; | |

1199 | sort_data.qctx = qctx; | |

1200 | ||

1201 | g_qsort_with_data (servers, nservers, sizeof (Bonobo_ServerInfo *), | |

1202 | qexp_sort_compare, &sort_data); | |

1203 | } |

**Note:**See TracBrowser for help on using the repository browser.