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