]> git.saurik.com Git - apple/libc.git/blob - gen/asl_core.c
Libc-825.24.tar.gz
[apple/libc.git] / gen / asl_core.c
1 /*
2 * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <ctype.h>
25 #include <stdio.h>
26 #include <asl_core.h>
27 #include <asl_private.h>
28 #include <string.h>
29 #include <membership.h>
30 #include <pthread.h>
31 #include <libkern/OSAtomic.h>
32
33 #define ASL_STRING_QUANTUM 256
34 static const char *cvis_7_13 = "abtnvfr";
35
36 /*
37 * Message ID generation
38 */
39 static uint64_t _asl_core_msg_next_id = 1;
40 static pthread_mutex_t core_lock = PTHREAD_MUTEX_INITIALIZER;
41
42 #define mix(a, b, c) \
43 { \
44 a -= b; a -= c; a ^= (c>>13); \
45 b -= c; b -= a; b ^= (a<< 8); \
46 c -= a; c -= b; c ^= (b>>13); \
47 a -= b; a -= c; a ^= (c>>12); \
48 b -= c; b -= a; b ^= (a<<16); \
49 c -= a; c -= b; c ^= (b>> 5); \
50 a -= b; a -= c; a ^= (c>> 3); \
51 b -= c; b -= a; b ^= (a<<10); \
52 c -= a; c -= b; c ^= (b>>15); \
53 }
54
55 /*
56 * Hash is used to improve string search.
57 */
58 uint32_t
59 asl_core_string_hash(const char *s, uint32_t inlen)
60 {
61 uint32_t a, b, c, l, len;
62
63 if (s == NULL) return 0;
64
65 l = inlen;
66 if (l == 0)
67 {
68 if (s[0] == '\0') return 0;
69 l = strlen(s);
70 }
71
72 len = l;
73 a = b = 0x9e3779b9;
74 c = 0;
75
76 while (len >= 12)
77 {
78 a += (s[0] + ((uint32_t)s[1]<<8) + ((uint32_t)s[ 2]<<16) + ((uint32_t)s[ 3]<<24));
79 b += (s[4] + ((uint32_t)s[5]<<8) + ((uint32_t)s[ 6]<<16) + ((uint32_t)s[ 7]<<24));
80 c += (s[8] + ((uint32_t)s[9]<<8) + ((uint32_t)s[10]<<16) + ((uint32_t)s[11]<<24));
81
82 mix(a, b, c);
83
84 s += 12;
85 len -= 12;
86 }
87
88 c += l;
89 switch(len)
90 {
91 case 11: c += ((uint32_t)s[10]<<24);
92 case 10: c += ((uint32_t)s[9]<<16);
93 case 9 : c += ((uint32_t)s[8]<<8);
94
95 case 8 : b += ((uint32_t)s[7]<<24);
96 case 7 : b += ((uint32_t)s[6]<<16);
97 case 6 : b += ((uint32_t)s[5]<<8);
98 case 5 : b += s[4];
99
100 case 4 : a += ((uint32_t)s[3]<<24);
101 case 3 : a += ((uint32_t)s[2]<<16);
102 case 2 : a += ((uint32_t)s[1]<<8);
103 case 1 : a += s[0];
104 }
105
106 mix(a, b, c);
107
108 if (c == 0) c = 1;
109 return c;
110 }
111
112 const char *
113 asl_core_error(uint32_t code)
114 {
115 switch (code)
116 {
117 case ASL_STATUS_OK: return "Operation Succeeded";
118 case ASL_STATUS_INVALID_ARG: return "Invalid Argument";
119 case ASL_STATUS_INVALID_STORE: return "Invalid Data Store";
120 case ASL_STATUS_INVALID_STRING: return "Invalid String";
121 case ASL_STATUS_INVALID_ID: return "Invalid ID Number";
122 case ASL_STATUS_INVALID_MESSAGE: return "Invalid Message";
123 case ASL_STATUS_NOT_FOUND: return "Not Found";
124 case ASL_STATUS_READ_FAILED: return "Read Operation Failed";
125 case ASL_STATUS_WRITE_FAILED: return "Write Operation Failed";
126 case ASL_STATUS_NO_MEMORY: return "System Memory Allocation Failed";
127 case ASL_STATUS_ACCESS_DENIED: return "Access Denied";
128 case ASL_STATUS_READ_ONLY: return "Read Only Access";
129 case ASL_STATUS_WRITE_ONLY: return "Write Only Access";
130 case ASL_STATUS_MATCH_FAILED: return "Match Failed";
131 case ASL_STATUS_NO_RECORDS: return "No More Records";
132 }
133
134 return "Operation Failed";
135 }
136
137 static uint32_t
138 asl_core_check_user_access(int32_t msgu, int32_t readu)
139 {
140 /* -1 means anyone may read */
141 if (msgu == -1) return ASL_STATUS_OK;
142
143 /* Check for exact match */
144 if (msgu == readu) return ASL_STATUS_OK;
145
146 return ASL_STATUS_ACCESS_DENIED;
147 }
148
149 static uint32_t
150 asl_core_check_group_access(int32_t msgg, int32_t readu, int32_t readg)
151 {
152 int check;
153 uuid_t uu, gu;
154
155 /* -1 means anyone may read */
156 if (msgg == -1) return ASL_STATUS_OK;
157
158 /* Check for exact match */
159 if (msgg == readg) return ASL_STATUS_OK;
160
161 /* Check if user (u) is in read group (msgg) */
162 mbr_uid_to_uuid(readu, uu);
163 mbr_gid_to_uuid(msgg, gu);
164
165 check = 0;
166 mbr_check_membership(uu, gu, &check);
167 if (check != 0) return ASL_STATUS_OK;
168
169 return ASL_STATUS_ACCESS_DENIED;
170 }
171
172 uint32_t
173 asl_core_check_access(int32_t msgu, int32_t msgg, int32_t readu, int32_t readg, uint16_t flags)
174 {
175 uint16_t uset, gset;
176
177 /* root (uid 0) may always read */
178 if (readu == 0) return ASL_STATUS_OK;
179
180 uset = flags & ASL_MSG_FLAG_READ_UID_SET;
181 gset = flags & ASL_MSG_FLAG_READ_GID_SET;
182
183 /* if no access controls are set, anyone may read */
184 if ((uset | gset) == 0) return ASL_STATUS_OK;
185
186 /* if only uid is set, then access is only by uid match */
187 if ((uset != 0) && (gset == 0)) return asl_core_check_user_access(msgu, readu);
188
189 /* if only gid is set, then access is only by gid match */
190 if ((uset == 0) && (gset != 0)) return asl_core_check_group_access(msgg, readu, readg);
191
192 /* both uid and gid are set - check user, then group */
193 if ((asl_core_check_user_access(msgu, readu)) == ASL_STATUS_OK) return ASL_STATUS_OK;
194 return asl_core_check_group_access(msgg, readu, readg);
195 }
196
197 uint64_t
198 asl_core_htonq(uint64_t n)
199 {
200 #ifdef __BIG_ENDIAN__
201 return n;
202 #else
203 u_int32_t t;
204 union
205 {
206 u_int64_t q;
207 u_int32_t l[2];
208 } x;
209
210 x.q = n;
211 t = x.l[0];
212 x.l[0] = htonl(x.l[1]);
213 x.l[1] = htonl(t);
214
215 return x.q;
216 #endif
217 }
218
219 uint64_t
220 asl_core_ntohq(uint64_t n)
221 {
222 #ifdef __BIG_ENDIAN__
223 return n;
224 #else
225 u_int32_t t;
226 union
227 {
228 u_int64_t q;
229 u_int32_t l[2];
230 } x;
231
232 x.q = n;
233 t = x.l[0];
234 x.l[0] = ntohl(x.l[1]);
235 x.l[1] = ntohl(t);
236
237 return x.q;
238 #endif
239 }
240
241 uint64_t
242 asl_core_new_msg_id(uint64_t start)
243 {
244 uint64_t out;
245
246 pthread_mutex_lock(&core_lock);
247
248 if (start != 0) _asl_core_msg_next_id = start;
249
250 out = _asl_core_msg_next_id;
251 _asl_core_msg_next_id++;
252
253 pthread_mutex_unlock(&core_lock);
254
255 return out;
256 }
257
258 /*
259 * asl_core_encode_buffer
260 * encode arbitrary data as a C string without embedded zero (nul) characters
261 *
262 * The routine computes a histogram of the input buffer and finds
263 * the two least frequently used non-nul chars (L[0] and L[1]).
264 *
265 * L[0] is used to stand in for nul.
266 * L[1] is used as the escape character.
267 * Occurrences of nul in the data are encoded as L[0]
268 * Occurrences of L[0] in the data are encoded as the sequence L[1] 1.
269 * Occurrences of L[1] in the data are encoded as the sequence L[1] 2.
270 *
271 * The output string is preceded by L[0] L[1], and is nul terminated.
272 * The output length is 2 + n + N(L[0]) + N(L[1]) + 1
273 * where N(x) is the number of occurrences of x in the input string.
274 * The worst case occurs when all characters are equally frequent,
275 * In that case the output size will less that 1% larger than the input.
276 */
277 char *
278 asl_core_encode_buffer(const char *in, uint32_t len)
279 {
280 char *str;
281 uint32_t i, j, k, outlen, breakit, min, hist[256];
282 uint32_t lfu[2], save[2];
283 uint8_t v;
284
285 if (in == NULL) return NULL;
286 if (len == 0) return NULL;
287
288 memset(hist, 0, sizeof(hist));
289 save[0] = 0;
290 save[1] = 0;
291
292 for (i = 0; i < len; i++)
293 {
294 v = in[i];
295 hist[v]++;
296 }
297
298 for (j = 0; j < 2; j++)
299 {
300 lfu[j] = 1;
301 min = hist[1];
302
303 for (i = 2; i < 256; i++)
304 {
305 if (hist[i] < min)
306 {
307 lfu[j] = i;
308 min = hist[i];
309
310 /*
311 * Stop if there are no occurances or character i in the input.
312 * The minimum will never be less than zero.
313 */
314 if (min == 0) break;
315
316 /*
317 * When looking for the second least frequently used character,
318 * stop scanning if we hit the same minimum as we saw in the first
319 * pass. There will be no smaller values.
320 */
321 if ((j == 1) && (min == save[0])) break;
322 }
323 }
324
325 save[j] = hist[lfu[j]];
326 hist[lfu[j]] = (uint32_t)-1;
327 }
328
329 outlen = 2 + len + save[0] + save[1] + 1;
330
331 str = malloc(outlen);
332 if (str == NULL) return NULL;
333
334 str[outlen - 1] = '\0';
335
336 str[0] = lfu[0];
337 str[1] = lfu[1];
338
339 j = 2;
340
341 for (i = 0; i < len; i++)
342 {
343 v = in[i];
344 if (v == 0)
345 {
346 str[j++] = lfu[0];
347 continue;
348 }
349
350 breakit = 0;
351 for (k = 0; (k < 2) && (breakit == 0); k++)
352 {
353 if (v == lfu[k])
354 {
355 str[j++] = lfu[1];
356 str[j++] = k + 1;
357 breakit = 1;
358 }
359 }
360
361 if (breakit == 1) continue;
362
363 str[j++] = v;
364 }
365
366 return str;
367 }
368
369 /*
370 * asl_core_decode_buffer
371 * decode a string produced by asl_encode_buffer to recreate the original data
372 */
373 int32_t
374 asl_core_decode_buffer(const char *in, char **buf, uint32_t *len)
375 {
376 uint8_t v;
377 uint32_t i, j, n, outlen;
378 uint8_t lfu[2];
379 char *out;
380
381 if (buf == NULL) return -1;
382 if (len == NULL) return -1;
383
384 lfu[0] = in[0];
385 lfu[1] = in[1];
386
387 outlen = 0;
388
389 /* strip trailing nul */
390 n = strlen(in);
391
392 /* determine output length and check for invalid input */
393 for (i = 2; i < n; i++)
394 {
395 v = in[i];
396 if (v == lfu[1])
397 {
398 i++;
399 if (i == n) return -1;
400
401 v = in[i];
402 if ((v < 1) || (v > 2)) return -1;
403
404 outlen++;
405 }
406 else outlen++;
407 }
408
409 if (outlen == 0) return -1;
410
411 out = malloc(outlen);
412 if (out == NULL) return -1;
413
414 j = 0;
415 for (i = 2; i < n; i++)
416 {
417 v = in[i];
418 if (v == lfu[0])
419 {
420 out[j++] = 0;
421 }
422 else if (v == lfu[1])
423 {
424 i++;
425 v = in[i];
426 out[j++] = lfu[v - 1];
427 }
428 else out[j++] = v;
429 }
430
431 *len = outlen;
432 *buf = out;
433 return 0;
434 }
435
436 /* asl_string_t support */
437
438 asl_string_t *
439 asl_string_new(uint32_t encoding)
440 {
441 asl_string_t *str = (asl_string_t *)calloc(1, sizeof(asl_string_t));
442 if (str == NULL) return NULL;
443
444 str->encoding = encoding;
445 str->delta = ASL_STRING_QUANTUM;
446 if (encoding & ASL_STRING_VM) str->delta = PAGE_SIZE;
447 str->bufsize = 0;
448 str->cursor = 0;
449
450 if (encoding & ASL_STRING_LEN) asl_string_append_no_encoding(str, " 0 ");
451 return str;
452 }
453
454 void
455 asl_string_free(asl_string_t *str)
456 {
457 if (str == NULL) return;
458
459 if (str->encoding & ASL_STRING_VM)
460 {
461 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
462 }
463 else
464 {
465 free(str->buf);
466 }
467
468 free(str);
469 }
470
471 char *
472 asl_string_free_return_bytes(asl_string_t *str)
473 {
474 char *out;
475 if (str == NULL) return NULL;
476
477 out = str->buf;
478 free(str);
479 return out;
480 }
481
482 char *
483 asl_string_bytes(asl_string_t *str)
484 {
485 if (str == NULL) return NULL;
486 return str->buf;
487 }
488
489 /* length includes trailing nul */
490 size_t
491 asl_string_length(asl_string_t *str)
492 {
493 if (str == NULL) return 0;
494 if (str->cursor == 0) return 0;
495
496 return str->cursor + 1;
497 }
498
499 size_t
500 asl_string_allocated_size(asl_string_t *str)
501 {
502 if (str == NULL) return 0;
503 return str->bufsize;
504 }
505
506 static int
507 _asl_string_grow(asl_string_t *str, size_t len)
508 {
509 size_t newlen = 0;
510
511 if (str == NULL) return -1;
512 if (len == 0) return 0;
513
514 if (str->bufsize == 0)
515 {
516 newlen = ((len + str->delta - 1) / str->delta) * str->delta;
517 }
518 else
519 {
520 /* used size is (str->cursor + 1) including tailiing nul */
521 if (len <= (str->bufsize - (str->cursor + 1))) return 0;
522
523 /* really this is ((str->cursor + 1) + len + (str->delta - 1)) */
524 newlen = ((str->cursor + len + str->delta) / str->delta) * str->delta;
525 }
526
527 if (str->encoding & ASL_STRING_VM)
528 {
529 kern_return_t kstatus;
530 vm_address_t new = 0;
531
532 kstatus = vm_allocate(mach_task_self(), &new, newlen, TRUE);
533 if (kstatus != KERN_SUCCESS)
534 {
535 new = 0;
536 newlen = 0;
537 return -1;
538 }
539
540 if (str->buf != NULL)
541 {
542 memcpy((void *)new, str->buf, str->bufsize);
543 vm_deallocate(mach_task_self(), (vm_address_t)str->buf, str->bufsize);
544 }
545
546 str->buf = (char *)new;
547 str->bufsize = newlen;
548 }
549 else
550 {
551 str->buf = reallocf(str->buf, newlen);
552 if (str->buf == NULL)
553 {
554 str->cursor = 0;
555 str->bufsize = 0;
556 return -1;
557 }
558
559 str->bufsize = newlen;
560 }
561
562 return 0;
563 }
564
565 asl_string_t *
566 asl_string_append_char_no_encoding(asl_string_t *str, const char c)
567 {
568 size_t len;
569
570 if (str == NULL) return NULL;
571
572 len = 1;
573 if (str->bufsize == 0) len++;
574
575 if (_asl_string_grow(str, len) < 0) return str;
576
577 str->buf[str->cursor] = c;
578 str->cursor++;
579 str->buf[str->cursor] = '\0';
580
581 if (str->encoding & ASL_STRING_LEN)
582 {
583 char tmp[11];
584 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
585 memcpy(str->buf, tmp, 10);
586 }
587
588 return str;
589 }
590
591 asl_string_t *
592 asl_string_append_no_encoding(asl_string_t *str, const char *app)
593 {
594 size_t len, applen;
595
596 if (str == NULL) return NULL;
597 if (app == NULL) return str;
598
599 applen = strlen(app);
600 len = applen;
601 if (str->bufsize == 0) len++;
602
603 if (_asl_string_grow(str, len) < 0) return str;
604
605 memcpy(str->buf + str->cursor, app, applen);
606
607 str->cursor += applen;
608 str->buf[str->cursor] = '\0';
609
610 if (str->encoding & ASL_STRING_LEN)
611 {
612 char tmp[11];
613 snprintf(tmp, sizeof(tmp), "%10lu", str->cursor - 10);
614 memcpy(str->buf, tmp, 10);
615 }
616
617 return str;
618 }
619
620 static asl_string_t *
621 asl_string_append_internal(asl_string_t *str, const char *app, int encode_space)
622 {
623 uint8_t x;
624 const char *p;
625
626 if (str == NULL) return NULL;
627 if (app == NULL) return str;
628
629 switch (str->encoding & ASL_ENCODE_MASK)
630 {
631 case ASL_ENCODE_NONE:
632 {
633 return asl_string_append_no_encoding(str, app);
634 }
635 case ASL_ENCODE_SAFE:
636 {
637 /* minor encoding to reduce the likelyhood of spoof attacks */
638 const char *p;
639
640 for (p = app; *p != '\0'; p++)
641 {
642 if ((*p == 10) || (*p == 13))
643 {
644 asl_string_append_no_encoding(str, "\n\t");
645 }
646 else if (*p == 8)
647 {
648 asl_string_append_no_encoding(str, "^H");
649 }
650 else
651 {
652 asl_string_append_char_no_encoding(str, *p);
653 }
654 }
655
656 return str;
657 }
658 case ASL_ENCODE_ASL:
659 {
660 for (p = app; *p != '\0'; p++)
661 {
662 int meta = 0;
663
664 x = *p;
665
666 /* Meta chars get \M prefix */
667 if (x >= 128)
668 {
669 /* except meta-space, which is \240 */
670 if (x == 160)
671 {
672 asl_string_append_no_encoding(str, "\\240");
673 continue;
674 }
675
676 asl_string_append_no_encoding(str, "\\M");
677 x &= 0x7f;
678 meta = 1;
679 }
680
681 /* space is either ' ' or \s */
682 if (x == 32)
683 {
684 if (encode_space == 0)
685 {
686 asl_string_append_char_no_encoding(str, ' ');
687 continue;
688 }
689
690 asl_string_append_no_encoding(str, "\\s");
691 continue;
692 }
693
694 /* \ is escaped */
695 if ((meta == 0) && (x == 92))
696 {
697 asl_string_append_no_encoding(str, "\\\\");
698 continue;
699 }
700
701 /* [ and ] are escaped in ASL encoding */
702 if ((str->encoding & ASL_ENCODE_ASL) && (meta == 0) && ((*p == 91) || (*p == 93)))
703 {
704 if (*p == '[') asl_string_append_no_encoding(str, "\\[");
705 else asl_string_append_no_encoding(str, "\\]");
706 continue;
707 }
708
709 /* DEL is \^? */
710 if (x == 127)
711 {
712 if (meta == 0)
713 {
714 asl_string_append_char_no_encoding(str, '\\');
715 }
716
717 asl_string_append_no_encoding(str, "^?");
718 continue;
719 }
720
721 /* 33-126 are printable (add a '-' prefix for meta) */
722 if ((x >= 33) && (x <= 126))
723 {
724 if (meta == 1)
725 {
726 asl_string_append_char_no_encoding(str, '-');
727 }
728
729 asl_string_append_char_no_encoding(str, x);
730 continue;
731 }
732
733 /* non-meta BEL, BS, HT, NL, VT, NP, CR (7-13) are \a, \b, \t, \n, \v, \f, and \r */
734 if ((meta == 0) && (x >= 7) && (x <= 13))
735 {
736 asl_string_append_char_no_encoding(str, '\\');
737 asl_string_append_char_no_encoding(str, cvis_7_13[x - 7]);
738 continue;
739 }
740
741 /* 0 - 31 are ^@ - ^_ (non-meta get a leading \) */
742 if (x <= 31)
743 {
744 if (meta == 0)
745 {
746 asl_string_append_char_no_encoding(str, '\\');
747 }
748
749 asl_string_append_char_no_encoding(str, '^');
750 asl_string_append_char_no_encoding(str, 64 + x);
751 continue;
752 }
753
754 asl_string_append_char_no_encoding(str, x);
755 }
756
757 return str;
758 }
759 case ASL_ENCODE_XML:
760 {
761 for (p = app; *p != '\0'; p++)
762 {
763 x = *p;
764
765 if (x == '&')
766 {
767 asl_string_append_no_encoding(str, "&amp;");
768 }
769 else if (x == '<')
770 {
771 asl_string_append_no_encoding(str, "&lt;");
772 }
773 else if (x == '>')
774 {
775 asl_string_append_no_encoding(str, "&gt;");
776 }
777 else if (x == '"')
778 {
779 asl_string_append_no_encoding(str, "&quot;");
780 }
781 else if (x == '\'')
782 {
783 asl_string_append_no_encoding(str, "&apos;");
784 }
785 else if (iscntrl(x))
786 {
787 char tmp[8];
788 snprintf(tmp, sizeof(tmp), "&#x%02hhx;", x);
789 asl_string_append_no_encoding(str, tmp);
790 }
791 else
792 {
793 asl_string_append_char_no_encoding(str, x);
794 }
795 }
796 }
797 default:
798 {
799 return str;
800 }
801 }
802
803 return str;
804 }
805
806 asl_string_t *
807 asl_string_append(asl_string_t *str, const char *app)
808 {
809 return asl_string_append_internal(str, app, 0);
810 }
811
812 asl_string_t *
813 asl_string_append_asl_key(asl_string_t *str, const char *app)
814 {
815 return asl_string_append_internal(str, app, 1);
816 }
817
818 asl_string_t *
819 asl_string_append_op(asl_string_t *str, uint32_t op)
820 {
821 char opstr[8];
822 uint32_t i;
823
824 if (str == NULL) return NULL;
825
826 if (op == ASL_QUERY_OP_NULL)
827 {
828 return asl_string_append_char_no_encoding(str, '.');
829 }
830
831 i = 0;
832 if (op & ASL_QUERY_OP_CASEFOLD) opstr[i++] = 'C';
833
834 if (op & ASL_QUERY_OP_REGEX) opstr[i++] = 'R';
835
836 if (op & ASL_QUERY_OP_NUMERIC) opstr[i++] = 'N';
837
838 if (op & ASL_QUERY_OP_PREFIX)
839 {
840 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'S';
841 else opstr[i++] = 'A';
842 }
843 if (op & ASL_QUERY_OP_SUFFIX) opstr[i++] = 'Z';
844
845 switch (op & ASL_QUERY_OP_TRUE)
846 {
847 case ASL_QUERY_OP_EQUAL:
848 opstr[i++] = '=';
849 break;
850 case ASL_QUERY_OP_GREATER:
851 opstr[i++] = '>';
852 break;
853 case ASL_QUERY_OP_GREATER_EQUAL:
854 opstr[i++] = '>';
855 opstr[i++] = '=';
856 break;
857 case ASL_QUERY_OP_LESS:
858 opstr[i++] = '<';
859 break;
860 case ASL_QUERY_OP_LESS_EQUAL:
861 opstr[i++] = '<';
862 opstr[i++] = '=';
863 break;
864 case ASL_QUERY_OP_NOT_EQUAL:
865 opstr[i++] = '!';
866 break;
867 case ASL_QUERY_OP_TRUE:
868 opstr[i++] = 'T';
869 break;
870 default:
871 break;
872 }
873
874 if (i == 0)
875 {
876 return asl_string_append_char_no_encoding(str, '.');
877 }
878
879 opstr[i] = '\0';
880 return asl_string_append_no_encoding(str, opstr);
881 }
882
883 asl_string_t *
884 asl_string_append_xml_tag(asl_string_t *str, const char *tag, const char *s)
885 {
886 asl_string_append_no_encoding(str, "\t\t<");
887 asl_string_append_no_encoding(str, tag);
888 asl_string_append_no_encoding(str, ">");
889 asl_string_append_no_encoding(str, s);
890 asl_string_append_no_encoding(str, "</");
891 asl_string_append_no_encoding(str, tag);
892 asl_string_append_no_encoding(str, ">\n");
893 return str;
894 }