libyml/
macros.rs

1// ------------------------------------
2// Buffer Management Macros
3// ------------------------------------
4
5/// Initializes a buffer with a given size.
6///
7/// # Parameters
8///
9/// * `buffer`: A mutable reference to a `YamlBufferT` struct that needs to be initialized.
10/// * `size`: The size of the buffer in bytes.
11///
12/// # Return
13///
14/// This macro does not return a value. It initializes the provided buffer with the given size.
15///
16/// # Safety
17///
18/// This macro assumes that the `yaml_malloc` function is correctly implemented and handles memory allocation.
19#[macro_export]
20macro_rules! BUFFER_INIT {
21    ($buffer:expr, $size:expr) => {{
22        let start = addr_of_mut!($buffer.start);
23        *start = yaml_malloc($size as size_t) as *mut yaml_char_t;
24        let pointer = addr_of_mut!($buffer.pointer);
25        *pointer = $buffer.start;
26        let last = addr_of_mut!($buffer.last);
27        *last = *pointer;
28        let end = addr_of_mut!($buffer.end);
29        *end = $buffer.start.wrapping_add($size);
30    }};
31}
32
33/// Deletes the buffer and frees the allocated memory.
34///
35/// # Parameters
36///
37/// * `buffer`: A mutable reference to the buffer to be deleted.
38///
39/// # Return
40///
41/// This function does not return a value.
42#[macro_export]
43macro_rules! BUFFER_DEL {
44    ($buffer:expr) => {{
45        // Free the allocated memory
46        yaml_free($buffer.start as *mut libc::c_void);
47
48        // Set all pointers to null after freeing the memory
49        $buffer.start = ptr::null_mut::<yaml_char_t>();
50        $buffer.pointer = ptr::null_mut::<yaml_char_t>();
51        $buffer.last = ptr::null_mut::<yaml_char_t>();
52        $buffer.end = ptr::null_mut::<yaml_char_t>();
53    }};
54}
55
56// ------------------------------------
57// String Management Macros
58// ------------------------------------
59
60/// Assigns a new value to a `YamlStringT` struct.
61///
62/// This macro creates a new `YamlStringT` instance with the given start and end pointers.
63/// The end pointer is calculated by offsetting the start pointer by the given length.
64/// The pointer is set to the start pointer.
65///
66/// # Parameters
67///
68/// * `string`: A pointer to the start of the string.
69/// * `length`: The length of the string.
70///
71/// # Return
72///
73/// A new `YamlStringT` instance with the given start, end, and pointer values.
74#[macro_export]
75macro_rules! STRING_ASSIGN {
76    ($string:expr, $length:expr) => {
77        YamlStringT {
78            start: $string,
79            end: $string.wrapping_offset($length as isize),
80            pointer: $string,
81        }
82    };
83}
84
85/// Initializes a string for use with the yaml library.
86///
87/// This macro allocates memory for a string, initializes the start, pointer, and end pointers,
88/// and sets the memory to all zeros.
89///
90/// # Parameters
91///
92/// * `$string`: A mutable reference to a `YamlStringT` struct, representing the string to be initialized.
93///
94/// # Return
95///
96/// This macro does not return a value.
97#[macro_export]
98macro_rules! STRING_INIT {
99    ($string:expr) => {{
100        $string.start = yaml_malloc(16) as *mut yaml_char_t;
101        $string.pointer = $string.start;
102        $string.end = $string.start.wrapping_add(16);
103        let _ = memset($string.start as *mut libc::c_void, 0, 16);
104    }};
105}
106
107/// Deletes a string and frees the allocated memory.
108///
109/// # Parameters
110///
111/// * `string`: A mutable reference to a `YamlStringT` struct representing the string to be deleted.
112///
113/// # Return
114///
115/// This function does not return a value.
116///
117/// # Safety
118///
119/// This function assumes that the `string` parameter is a valid pointer to a `YamlStringT` struct.
120/// It calls the `yaml_free` function to free the allocated memory for the string.
121#[macro_export]
122macro_rules! STRING_DEL {
123    ($string:expr) => {{
124        yaml_free($string.start as *mut libc::c_void);
125        $string.end = ptr::null_mut::<yaml_char_t>();
126        $string.pointer = $string.end;
127        $string.start = $string.pointer;
128    }};
129}
130
131/// Extends the capacity of a string by reallocating memory if the current capacity is insufficient.
132///
133/// # Parameters
134///
135/// * `string`: A mutable reference to a `YamlStringT` struct representing the string.
136///
137/// # Return
138///
139/// This macro does not return a value. It extends the capacity of the string by reallocating memory if necessary.
140#[macro_export]
141macro_rules! STRING_EXTEND {
142    ($string:expr) => {
143        if $string.pointer.wrapping_add(5) >= $string.end {
144            yaml_string_extend(
145                addr_of_mut!($string.start),
146                addr_of_mut!($string.pointer),
147                addr_of_mut!($string.end),
148            );
149        }
150    };
151}
152
153/// Clears the content of the string by setting the pointer to the start and filling the memory
154/// from the start to the end with zeros.
155///
156/// # Parameters
157///
158/// * `string`: A mutable reference to a struct containing the start, pointer, and end pointers representing the string.
159///
160/// # Return
161///
162/// This macro does not return a value. It modifies the content of the string in place.
163#[macro_export]
164macro_rules! CLEAR {
165    ($string:expr) => {{
166        $string.pointer = $string.start;
167        let _ = memset(
168            $string.start as *mut libc::c_void,
169            0,
170            $string.end.offset_from($string.start) as libc::c_ulong,
171        );
172    }};
173}
174
175/// Joins two strings together by appending the contents of `string_b` to `string_a`.
176///
177/// # Parameters
178///
179/// * `string_a`: A mutable reference to the first string. Its contents will be modified.
180/// * `string_b`: A mutable reference to the second string. Its contents will not be modified.
181///
182/// # Return
183///
184/// This macro does not return a value. It modifies the contents of `string_a` in-place.
185#[macro_export]
186macro_rules! JOIN {
187    ($string_a:expr, $string_b:expr) => {{
188        // Check the length to ensure we don't overflow
189        let a_len = $string_a.pointer.offset_from($string_a.start) as usize;
190        let b_len = $string_b.pointer.offset_from($string_b.start) as usize;
191
192        // If the combined length would exceed available space, reallocate
193        if a_len.checked_add(b_len).is_some() && $string_a.pointer.add(b_len) <= $string_a.end {
194            yaml_string_join(
195                addr_of_mut!($string_a.start),
196                addr_of_mut!($string_a.pointer),
197                addr_of_mut!($string_a.end),
198                addr_of_mut!($string_b.start),
199                addr_of_mut!($string_b.pointer),
200                addr_of_mut!($string_b.end),
201            );
202            $string_b.pointer = $string_b.start;
203        } else {
204            panic!("String join would overflow memory bounds");
205        }
206    }};
207}
208
209/// This macro checks if the octet at the specified offset in the given string matches the provided octet.
210///
211/// # Parameters
212///
213/// * `string`: A reference to the string where the octet will be checked.
214/// * `octet`: The octet to be checked.
215/// * `offset`: The offset from the start of the string where the octet will be checked.
216///
217/// # Return
218///
219/// * `bool`: Returns `true` if the octet at the specified offset matches the provided octet, otherwise returns `false`.
220#[macro_export]
221macro_rules! CHECK_AT {
222    ($string:expr, $octet:expr, $offset:expr) => {
223        *$string.pointer.offset($offset) == $octet
224    };
225}
226
227/// A macro that checks if the current byte in the given string matches a specific octet.
228///
229/// # Parameters
230///
231/// * `string`: A reference to the string to be checked.
232/// * `octet`: The octet to be matched.
233///
234/// # Return
235///
236/// * `bool`: Returns `true` if the current byte in the string matches the given octet, otherwise `false`.
237#[macro_export]
238macro_rules! CHECK {
239    ($string:expr, $octet:expr) => {
240        *$string.pointer == $octet
241    };
242}
243
244/// Checks if the current character in the string is an alphabetic character.
245///
246/// # Parameters
247///
248/// * `string`: A mutable reference to a struct containing a pointer to a byte array.
249///
250/// # Return
251///
252/// Returns `true` if the current character is an alphabetic character (A-Z, a-z, 0-9, '_', '-'),
253/// and `false` otherwise.
254#[macro_export]
255macro_rules! IS_ALPHA {
256    ($string:expr) => {
257        *$string.pointer >= b'0' && *$string.pointer <= b'9'
258            || *$string.pointer >= b'A' && *$string.pointer <= b'Z'
259            || *$string.pointer >= b'a' && *$string.pointer <= b'z'
260            || *$string.pointer == b'_'
261            || *$string.pointer == b'-'
262    };
263}
264
265/// Checks if the byte pointed to by the `pointer` in the given string is a digit (0-9).
266///
267/// # Parameters
268///
269/// * `string`: A reference to a struct containing a `pointer` field pointing to a byte in a string.
270///
271/// # Return value
272///
273/// Returns `true` if the byte pointed to by the `pointer` is a digit (0-9), and `false` otherwise.
274#[macro_export]
275macro_rules! IS_DIGIT {
276    ($string:expr) => {
277        *$string.pointer >= b'0' && *$string.pointer <= b'9'
278    };
279}
280
281/// Converts the byte at the current pointer in the string to its corresponding integer value.
282///
283/// # Parameters
284///
285/// * `string`: A mutable reference to a struct containing a pointer to a byte array.
286///
287/// # Return
288///
289/// * Returns the integer value of the byte at the current pointer in the string.
290///   The byte is assumed to be in the ASCII range (0-9), so the function subtracts the ASCII value of '0' (48)
291///   to convert it to its integer representation.
292#[macro_export]
293macro_rules! AS_DIGIT {
294    ($string:expr) => {
295        (*$string.pointer - b'0') as libc::c_int
296    };
297}
298
299/// Checks if the character at the given offset in the string is a hexadecimal digit.
300///
301/// # Parameters
302///
303/// * `string`: A reference to the string to check.
304/// * `offset`: The offset in the string to check.
305///
306/// # Return
307///
308/// Returns `true` if the character at the given offset is a hexadecimal digit (0-9, A-F, a-f),
309/// and `false` otherwise.
310#[macro_export]
311macro_rules! IS_HEX_AT {
312    ($string:expr, $offset:expr) => {
313        *$string.pointer.wrapping_offset($offset) >= b'0'
314            && *$string.pointer.wrapping_offset($offset) <= b'9'
315            || *$string.pointer.wrapping_offset($offset) >= b'A'
316                && *$string.pointer.wrapping_offset($offset) <= b'F'
317            || *$string.pointer.wrapping_offset($offset) >= b'a'
318                && *$string.pointer.wrapping_offset($offset) <= b'f'
319    };
320}
321
322/// Converts a hexadecimal character at a given offset in a string to its corresponding integer value.
323///
324/// # Parameters
325///
326/// * `string`: A reference to a string containing hexadecimal characters.
327/// * `offset`: The offset in the string where the hexadecimal character is located.
328///
329/// # Return
330///
331/// An integer representing the hexadecimal value of the character at the given offset.
332///
333/// # Note
334///
335/// This macro assumes that the input string contains valid hexadecimal characters.
336#[macro_export]
337macro_rules! AS_HEX_AT {
338    ($string:expr, $offset:expr) => {
339        if *$string.pointer.wrapping_offset($offset) >= b'A'
340            && *$string.pointer.wrapping_offset($offset) <= b'F'
341        {
342            *$string.pointer.wrapping_offset($offset) - b'A' + 10
343        } else if *$string.pointer.wrapping_offset($offset) >= b'a'
344            && *$string.pointer.wrapping_offset($offset) <= b'f'
345        {
346            *$string.pointer.wrapping_offset($offset) - b'a' + 10
347        } else {
348            *$string.pointer.wrapping_offset($offset) - b'0'
349        } as libc::c_int
350    };
351}
352
353/// Checks if the current character in the string is an ASCII character.
354///
355/// # Parameters
356///
357/// * `string`: A reference to a struct containing a pointer to the current character in the string.
358///
359/// # Return
360///
361/// Returns `true` if the current character is an ASCII character (i.e., its value is less than or equal to 0x7F),
362/// and `false` otherwise.
363#[macro_export]
364macro_rules! IS_ASCII {
365    ($string:expr) => {
366        *$string.pointer <= b'\x7F'
367    };
368}
369
370/// Checks if the character at the current pointer in the given string is printable.
371///
372/// # Parameters
373///
374/// * `string`: A reference to a struct containing a pointer to the current character in the string.
375///
376/// # Return
377///
378/// * `bool`: Returns `true` if the character is printable, and `false` otherwise.
379///
380/// # Details
381///
382/// This macro checks if the character at the current pointer in the given string is printable.
383/// It considers various Unicode ranges and special characters to determine printability.
384///
385/// The macro uses pattern matching to check the byte value of the character and its position in the string.
386/// It checks for ASCII printable characters, Unicode printable characters in specific ranges,
387/// and special characters that are considered printable.
388///
389/// The macro returns `true` if the character is printable, and `false` otherwise.
390#[macro_export]
391macro_rules! IS_PRINTABLE {
392    ($string:expr) => {
393        match *$string.pointer {
394            // ASCII
395            0x0A | 0x20..=0x7E => true,
396            // U+A0 ... U+BF
397            0xC2 => match *$string.pointer.wrapping_offset(1) {
398                0xA0..=0xBF => true,
399                _ => false,
400            },
401            // U+C0 ... U+CFFF
402            0xC3..=0xEC => true,
403            // U+D000 ... U+D7FF
404            0xED => match *$string.pointer.wrapping_offset(1) {
405                0x00..=0x9F => true,
406                _ => false,
407            },
408            // U+E000 ... U+EFFF
409            0xEE => true,
410            // U+F000 ... U+FFFD
411            0xEF => match *$string.pointer.wrapping_offset(1) {
412                0xBB => match *$string.pointer.wrapping_offset(2) {
413                    // except U+FEFF
414                    0xBF => false,
415                    _ => true,
416                },
417                0xBF => match *$string.pointer.wrapping_offset(2) {
418                    0xBE | 0xBF => false,
419                    _ => true,
420                },
421                _ => true,
422            },
423            // U+10000 ... U+10FFFF
424            0xF0..=0xF4 => true,
425            _ => false,
426        }
427    };
428}
429
430/// Checks if the character at the specified offset in the given string is a null character (ASCII 0).
431///
432/// # Parameters
433///
434/// * `$string`: A reference to the string to check.
435/// * `$offset`: The offset within the string to check.
436///
437/// # Return
438///
439/// Returns `true` if the character at the specified offset is a null character, and `false` otherwise.
440#[macro_export]
441macro_rules! IS_Z_AT {
442    ($string:expr, $offset:expr) => {
443        CHECK_AT!($string, b'\0', $offset)
444    };
445}
446
447/// Checks if the character at the current pointer in the given string is a null character (ASCII 0).
448///
449/// # Parameters
450///
451/// * `$string`: A reference to the string to check.
452///
453/// # Return
454///
455/// * `bool`: Returns `true` if the character is a null character, and `false` otherwise.
456#[macro_export]
457macro_rules! IS_Z {
458    ($string:expr) => {
459        IS_Z_AT!($string, 0)
460    };
461}
462
463/// Checks if the first three bytes of the given string form the UTF-8 byte order mark (BOM) for UTF-8 encoding.
464///
465/// # Parameters
466///
467/// * `string`: A reference to the string to check.
468///
469/// # Return
470///
471/// * `bool`: Returns `true` if the first three bytes of the string form the UTF-8 BOM, and `false` otherwise.
472#[macro_export]
473macro_rules! IS_BOM {
474    ($string:expr) => {
475        CHECK_AT!($string, b'\xEF', 0)
476            && CHECK_AT!($string, b'\xBB', 1)
477            && CHECK_AT!($string, b'\xBF', 2)
478    };
479}
480
481/// Checks if the character at the specified offset in the given string is a space character (ASCII 0x20).
482///
483/// # Parameters
484///
485/// * `$string`: A reference to the string to check.
486/// * `$offset`: The offset within the string to check.
487///
488/// # Return
489///
490/// * `bool`: Returns `true` if the character at the specified offset is a space character, and `false` otherwise.
491#[macro_export]
492macro_rules! IS_SPACE_AT {
493    ($string:expr, $offset:expr) => {
494        CHECK_AT!($string, b' ', $offset)
495    };
496}
497
498/// Checks if the character at the current pointer in the given string is a space character (ASCII 0x20).
499///
500/// # Parameters
501///
502/// * `string`: A reference to the string to check.
503///
504/// # Return
505///
506/// * `bool`: Returns `true` if the character is a space character, and `false` otherwise.
507#[macro_export]
508macro_rules! IS_SPACE {
509    ($string:expr) => {
510        IS_SPACE_AT!($string, 0)
511    };
512}
513
514/// Checks if the character at the specified offset in the given string is a tab character (ASCII 0x09).
515///
516/// # Parameters
517///
518/// * `$string`: A reference to the string to check.
519/// * `$offset`: The offset within the string to check.
520///
521/// # Return
522///
523/// * `bool`: Returns `true` if the character at the specified offset is a tab character, and `false` otherwise.
524#[macro_export]
525macro_rules! IS_TAB_AT {
526    ($string:expr, $offset:expr) => {
527        CHECK_AT!($string, b'\t', $offset)
528    };
529}
530
531/// Checks if the character at the current pointer in the given string is a tab character (ASCII 0x09).
532///
533/// # Parameters
534///
535/// * `string`: A reference to the string to check.
536///
537/// # Return
538///
539/// * `bool`: Returns `true` if the character is a tab character, and `false` otherwise.
540#[macro_export]
541macro_rules! IS_TAB {
542    ($string:expr) => {
543        IS_TAB_AT!($string, 0)
544    };
545}
546
547/// Checks if the character at the specified offset in the given string is a space or tab character.
548///
549/// # Parameters
550///
551/// * `$string`: A reference to the string to check.
552/// * `$offset`: The offset within the string to check.
553///
554/// # Return
555///
556/// * `bool`: Returns `true` if the character at the specified offset is a space or tab character, and `false` otherwise.
557#[macro_export]
558macro_rules! IS_BLANK_AT {
559    ($string:expr, $offset:expr) => {
560        IS_SPACE_AT!($string, $offset) || IS_TAB_AT!($string, $offset)
561    };
562}
563
564/// Checks if the character at the current pointer in the given string is a space or tab character.
565///
566/// # Parameters
567///
568/// * `$string`: A reference to the string to check.
569///
570/// # Return
571///
572/// * `bool`: Returns `true` if the character is a space or tab character, and `false` otherwise.
573#[macro_export]
574macro_rules! IS_BLANK {
575    ($string:expr) => {
576        IS_BLANK_AT!($string, 0)
577    };
578}
579
580/// Checks if the character at the specified offset in the given string is a line break character.
581///
582/// # Parameters
583///
584/// * `$string`: A reference to the string to check.
585/// * `$offset`: The offset within the string to check.
586///
587/// # Return
588///
589/// Returns `true` if the character at the specified offset is a line break character (CR, LF, NEL, LS, PS),
590/// and `false` otherwise.
591#[macro_export]
592macro_rules! IS_BREAK_AT {
593    ($string:expr, $offset:expr) => {
594        CHECK_AT!($string, b'\r', $offset)
595            || CHECK_AT!($string, b'\n', $offset)
596            || CHECK_AT!($string, b'\xC2', $offset)
597                && CHECK_AT!(
598                    $string,
599                    b'\x85',
600                    ($offset + 1).try_into().unwrap()
601                )
602            || CHECK_AT!($string, b'\xE2', $offset)
603                && CHECK_AT!(
604                    $string,
605                    b'\x80',
606                    ($offset + 1).try_into().unwrap()
607                )
608                && CHECK_AT!(
609                    $string,
610                    b'\xA8',
611                    ($offset + 2).try_into().unwrap()
612                )
613            || CHECK_AT!($string, b'\xE2', $offset)
614                && CHECK_AT!(
615                    $string,
616                    b'\x80',
617                    ($offset + 1).try_into().unwrap()
618                )
619                && CHECK_AT!(
620                    $string,
621                    b'\xA9',
622                    ($offset + 2).try_into().unwrap()
623                )
624    };
625}
626
627/// Checks if the character at the current pointer in the given string is a line break character.
628///
629/// # Parameters
630///
631/// * `string`: A reference to the string to check.
632///
633/// # Return
634///
635/// Returns `true` if the character is a line break character (CR, LF, NEL, LS, PS), and `false` otherwise.
636#[macro_export]
637macro_rules! IS_BREAK {
638    ($string:expr) => {
639        IS_BREAK_AT!($string, 0)
640    };
641}
642
643/// Checks if the character at the current pointer in the given string is a carriage return followed by a line feed.
644///
645/// # Parameters
646///
647/// * `string`: A reference to the string to check.
648///
649/// # Return
650///
651/// Returns `true` if the character at the current pointer is a carriage return followed by a line feed, and `false` otherwise.
652#[macro_export]
653macro_rules! IS_CRLF {
654    ($string:expr) => {
655        CHECK_AT!($string, b'\r', 0) && CHECK_AT!($string, b'\n', 1)
656    };
657}
658
659/// Checks if the character at the specified offset in the given string is a line break character or a null character.
660///
661/// # Parameters
662///
663/// * `string`: A reference to the string to check.
664/// * `offset`: The offset within the string to check.
665///
666/// # Return
667///
668/// Returns `true` if the character at the specified offset is a line break character or a null character, and `false` otherwise.
669#[macro_export]
670macro_rules! IS_BREAKZ_AT {
671    ($string:expr, $offset:expr) => {
672        IS_BREAK_AT!($string, $offset) || IS_Z_AT!($string, $offset)
673    };
674}
675
676/// Checks if the character at the current pointer in the given string is a line break character or a null character.
677///
678/// # Parameters
679///
680/// * `string`: A reference to the string to check.
681///
682/// # Return
683///
684/// Returns `true` if the character is a line break character (CR, LF, NEL, LS, PS) or a null character, and `false` otherwise.
685#[macro_export]
686macro_rules! IS_BREAKZ {
687    ($string:expr) => {
688        IS_BREAKZ_AT!($string, 0)
689    };
690}
691
692/// Checks if the character at the specified offset in the given string is a space, tab, or line break character,
693/// or if it is a null character.
694///
695/// # Parameters
696///
697/// * `$string`: A reference to the string to check.
698/// * `$offset`: The offset within the string to check.
699///
700/// # Return
701///
702/// Returns `true` if the character at the specified offset is a space, tab, line break character, or null character,
703/// and `false` otherwise.
704#[macro_export]
705macro_rules! IS_BLANKZ_AT {
706    ($string:expr, $offset:expr) => {
707        IS_BLANK_AT!($string, $offset)
708            || IS_BREAKZ_AT!($string, $offset)
709    };
710}
711
712/// Checks if the character at the current pointer in the given string is a space, tab, line break character,
713/// or if it is a null character.
714///
715/// # Parameters
716///
717/// * `string`: A reference to the string to check.
718///
719/// # Return
720///
721/// Returns `true` if the character is a space, tab, line break character, or null character,
722/// and `false` otherwise.
723#[macro_export]
724macro_rules! IS_BLANKZ {
725    ($string:expr) => {
726        IS_BLANKZ_AT!($string, 0)
727    };
728}
729
730/// Returns the width of a Unicode character at the given offset in a string.
731///
732/// # Parameters
733///
734/// * `string`: A reference to the string containing the Unicode characters.
735/// * `offset`: The offset in the string where the Unicode character is located.
736///
737/// # Return
738///
739/// The width of the Unicode character at the given offset. The width is determined by the first byte of the character:
740/// - If the first byte is 0x00-0x7F, the width is 1.
741/// - If the first byte is 0xC0-0xDF, the width is 2.
742/// - If the first byte is 0xE0-0xEF, the width is 3.
743/// - If the first byte is 0xF0-0xF7, the width is 4.
744/// - If the first byte does not match any of the above patterns, the width is 0.
745#[macro_export]
746macro_rules! WIDTH_AT {
747    ($string:expr, $offset:expr) => {
748        if *$string.pointer.wrapping_offset($offset) & 0x80 == 0x00 {
749            1
750        } else if *$string.pointer.wrapping_offset($offset) & 0xE0
751            == 0xC0
752        {
753            2
754        } else if *$string.pointer.wrapping_offset($offset) & 0xF0
755            == 0xE0
756        {
757            3
758        } else if *$string.pointer.wrapping_offset($offset) & 0xF8
759            == 0xF0
760        {
761            4
762        } else {
763            0
764        }
765    };
766}
767
768/// Returns the width of the Unicode character at the current position in a string.
769///
770/// This macro calculates the width of the Unicode character that the `pointer` in the given string is currently pointing to.
771/// The width is determined by checking the first byte of the character at the current position in the string, using the
772/// `WIDTH_AT!` macro with an offset of `0`.
773///
774/// # Parameters
775///
776/// * `string`: A reference to a struct containing a `pointer` field that points to a byte in a string.
777///   This byte is expected to be the start of a Unicode character.
778///
779/// # Return
780///
781/// The width of the Unicode character at the current position of the `pointer` in the string:
782///
783/// - If the first byte is in the range `0x00` to `0x7F`, the width is 1 byte.
784/// - If the first byte is in the range `0xC0` to `0xDF`, the width is 2 bytes.
785/// - If the first byte is in the range `0xE0` to `0xEF`, the width is 3 bytes.
786/// - If the first byte is in the range `0xF0` to `0xF7`, the width is 4 bytes.
787/// - If the first byte does not match any of the above patterns, the width is 0, indicating an invalid or unsupported character.
788///
789/// # Safety
790///
791/// The caller must ensure that the `pointer` in the `string` is pointing to valid memory and that the memory contains a valid Unicode sequence.
792/// Using this macro on an invalid or corrupted string may result in undefined behavior or incorrect results.
793#[macro_export]
794macro_rules! WIDTH {
795    ($string:expr) => {
796        WIDTH_AT!($string, 0)
797    };
798}
799
800/// Moves the pointer of the given string to the next Unicode character.
801///
802/// This macro moves the pointer of the given string to the next Unicode character,
803/// taking into account the width of the Unicode character. The width is determined
804/// by the first byte of the character.
805///
806/// # Parameters
807///
808/// * `string`: A mutable reference to the string whose pointer will be moved.
809///
810/// # Return
811///
812/// This macro does not return a value. It moves the pointer of the given string
813/// to the next Unicode character.
814#[macro_export]
815macro_rules! MOVE {
816    ($string:expr) => {
817        $string.pointer =
818            $string.pointer.wrapping_offset(WIDTH!($string))
819    };
820}
821
822/// Copies the content of a string to another string.
823///
824/// This macro copies the content of a string to another string. It handles different Unicode character
825/// encodings by checking the first byte of the character. If the character is a single-byte character, it
826/// is copied directly. If the character is a multi-byte character, it is copied byte by byte.
827///
828/// # Parameters
829///
830/// * `string_a`: A mutable reference to the destination string where the content will be copied.
831/// * `string_b`: A mutable reference to the source string from which the content will be copied.
832///
833/// # Return
834///
835/// This macro does not return a value. It copies the content of a string to another string.
836#[macro_export]
837macro_rules! copy {
838    ($string_a:expr, $string_b:expr) => {
839        if *$string_b.pointer & 0x80 == 0x00 {
840            *$string_a.pointer = *$string_b.pointer;
841            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
842            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
843        } else if *$string_b.pointer & 0xE0 == 0xC0 {
844            *$string_a.pointer = *$string_b.pointer;
845            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
846            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
847            *$string_a.pointer = *$string_b.pointer;
848            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
849            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
850        } else if *$string_b.pointer & 0xF0 == 0xE0 {
851            *$string_a.pointer = *$string_b.pointer;
852            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
853            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
854            *$string_a.pointer = *$string_b.pointer;
855            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
856            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
857            *$string_a.pointer = *$string_b.pointer;
858            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
859            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
860        } else if *$string_b.pointer & 0xF8 == 0xF0 {
861            *$string_a.pointer = *$string_b.pointer;
862            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
863            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
864            *$string_a.pointer = *$string_b.pointer;
865            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
866            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
867            *$string_a.pointer = *$string_b.pointer;
868            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
869            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
870            *$string_a.pointer = *$string_b.pointer;
871            $string_a.pointer = $string_a.pointer.wrapping_offset(1);
872            $string_b.pointer = $string_b.pointer.wrapping_offset(1);
873        }
874    };
875}
876
877// ------------------------------------
878// Stack Management Macros
879// ------------------------------------
880
881/// Initializes a stack with a specified type and allocates memory for it.
882///
883/// # Parameters
884///
885/// * `stack`: A mutable reference to the stack to be initialized.
886/// * `type`: The type of elements that will be stored in the stack.
887///
888/// # Return
889///
890/// This function does not return a value. It initializes the stack with the given type and allocates memory for it.
891/// The memory is allocated using the `yaml_malloc` function, and the start, top, and end pointers of the stack are set accordingly.
892#[macro_export]
893macro_rules! STACK_INIT {
894    ($stack:expr, $type:ty) => {{
895        $stack.start =
896            yaml_malloc(16 * size_of::<$type>() as libc::c_ulong)
897                as *mut $type;
898        $stack.top = $stack.start;
899        $stack.end = $stack.start.offset(16_isize);
900    }};
901}
902
903/// Deallocates the memory used by the stack and sets all pointers to null.
904///
905/// # Parameters
906///
907/// * `stack`: A mutable reference to the stack to be deallocated.
908///
909/// # Return
910///
911/// This function does not return a value. It deallocates the memory used by the stack and sets all pointers to null.
912#[macro_export]
913macro_rules! STACK_DEL {
914    ($stack:expr) => {
915        yaml_free($stack.start as *mut libc::c_void);
916        $stack.end = ptr::null_mut();
917        $stack.top = ptr::null_mut();
918        $stack.start = ptr::null_mut();
919    };
920}
921
922/// Checks if the stack has no elements.
923///
924/// This macro checks if the stack has no elements by comparing the start and top pointers.
925/// If the start and top pointers are equal, it means the stack is empty and the function returns `true`.
926/// Otherwise, it means the stack has elements and the function returns `false`.
927///
928/// # Parameters
929///
930/// * `stack`: A mutable reference to the stack to be checked.
931///
932/// # Return
933///
934/// * `true` if the stack is empty, i.e., the start and top pointers are equal.
935/// * `false` if the stack is not empty, i.e., the start and top pointers are not equal.
936#[macro_export]
937macro_rules! STACK_EMPTY {
938    ($stack:expr) => {
939        $stack.start == $stack.top
940    };
941}
942
943/// Checks if the stack has enough memory to push a new element.
944///
945/// This macro checks if the stack has enough memory to push a new element by comparing the distance
946/// between the top and start pointers with the maximum allowed distance. If the distance is less than
947/// the maximum allowed distance minus one, it means the stack has enough memory and the function
948/// returns `OK`. Otherwise, it sets the error field of the context to `YamlMemoryError` and returns
949/// `FAIL`.
950///
951/// # Parameters
952///
953/// * `$context`: A mutable reference to the context in which the stack is being used.
954/// * `$stack`: A mutable reference to the stack being checked.
955///
956/// # Return
957///
958/// * `OK` if the stack has enough memory to push a new element.
959/// * `FAIL` if the stack does not have enough memory to push a new element.
960#[macro_export]
961macro_rules! STACK_LIMIT {
962    ($context:expr, $stack:expr) => {
963        if $stack.top.c_offset_from($stack.start)
964            < libc::c_int::MAX as isize - 1
965        {
966            OK
967        } else {
968            (*$context).error = YamlMemoryError;
969            FAIL
970        }
971    };
972}
973
974/// Pushes a value onto the stack.
975///
976/// This macro pushes a value onto the stack. If the stack is full, it extends the stack by allocating
977/// additional memory.
978///
979/// # Parameters
980///
981/// * `stack`: A mutable reference to the stack onto which the value will be pushed.
982/// * `value`: The value to be pushed onto the stack.
983///
984/// # Return
985///
986/// This macro does not return a value. It pushes the value onto the stack.
987#[macro_export]
988macro_rules! PUSH {
989    (do $stack:expr, $push:expr) => {{
990        if $stack.top == $stack.end {
991            yaml_stack_extend(
992                addr_of_mut!($stack.start) as *mut *mut libc::c_void,
993                addr_of_mut!($stack.top) as *mut *mut libc::c_void,
994                addr_of_mut!($stack.end) as *mut *mut libc::c_void,
995            );
996        }
997        $push;
998        $stack.top = $stack.top.wrapping_offset(1);
999    }};
1000    ($stack:expr, *$value:expr) => {
1001        PUSH!(do $stack, ptr::copy_nonoverlapping($value, $stack.top, 1))
1002    };
1003    ($stack:expr, $value:expr) => {
1004        PUSH!(do $stack, ptr::write($stack.top, $value))
1005    };
1006}
1007
1008/// Removes and returns the last element from the stack.
1009///
1010/// # Parameters
1011///
1012/// * `stack`: A mutable reference to the stack from which the last element will be removed.
1013///
1014/// # Return
1015///
1016/// * The last element from the stack.
1017#[macro_export]
1018macro_rules! POP {
1019    ($stack:expr) => {
1020        *{
1021            $stack.top = $stack.top.offset(-1);
1022            $stack.top
1023        }
1024    };
1025}
1026
1027// ------------------------------------
1028// Queue Management Macros
1029// ------------------------------------
1030
1031/// Initializes a queue with a specified type and allocates memory for it.
1032///
1033/// # Parameters
1034///
1035/// * `queue`: A mutable reference to the queue to be initialized.
1036/// * `type`: The type of elements that will be stored in the queue.
1037///
1038/// # Return
1039///
1040/// This function does not return a value. It initializes the queue with the given type and allocates memory for it.
1041#[macro_export]
1042macro_rules! QUEUE_INIT {
1043    ($queue:expr, $type:ty) => {{
1044        $queue.start =
1045            yaml_malloc(16 * size_of::<$type>() as libc::c_ulong)
1046                as *mut $type;
1047        $queue.tail = $queue.start;
1048        $queue.head = $queue.tail;
1049        $queue.end = $queue.start.offset(16_isize);
1050    }};
1051}
1052
1053/// Deallocates the memory used by the queue and sets all pointers to null.
1054///
1055/// # Parameters
1056///
1057/// * `queue`: A mutable reference to the queue to be deallocated.
1058///
1059/// # Return
1060///
1061/// This function does not return a value.
1062#[macro_export]
1063macro_rules! QUEUE_DEL {
1064    ($queue:expr) => {
1065        yaml_free($queue.start as *mut libc::c_void);
1066        $queue.end = ptr::null_mut();
1067        $queue.tail = ptr::null_mut();
1068        $queue.head = ptr::null_mut();
1069        $queue.start = ptr::null_mut();
1070    };
1071}
1072
1073/// Checks if the queue is empty.
1074///
1075/// # Parameters
1076///
1077/// * `queue`: A mutable reference to the queue to be checked.
1078///
1079/// # Return
1080///
1081/// * `true` if the queue is empty, i.e., the head and tail pointers are equal.
1082/// * `false` if the queue is not empty, i.e., the head and tail pointers are not equal.
1083#[macro_export]
1084macro_rules! QUEUE_EMPTY {
1085    ($queue:expr) => {
1086        $queue.head == $queue.tail
1087    };
1088}
1089
1090/// Enqueues a value onto the queue.
1091///
1092/// This macro enqueues a value onto the queue. If the queue is full, it extends the queue by allocating additional memory.
1093///
1094/// # Parameters
1095///
1096/// * `queue`: A mutable reference to the queue onto which the value will be enqueued.
1097/// * `value`: The value to be enqueued onto the queue. This can be a reference or a direct value.
1098///
1099/// # Return
1100///
1101/// This macro does not return a value. It enqueues the value onto the queue.
1102#[macro_export]
1103macro_rules! ENQUEUE {
1104    (do $queue:expr, $enqueue:expr) => {{
1105        if $queue.tail == $queue.end {
1106            yaml_queue_extend(
1107                addr_of_mut!($queue.start) as *mut *mut libc::c_void,
1108                addr_of_mut!($queue.head) as *mut *mut libc::c_void,
1109                addr_of_mut!($queue.tail) as *mut *mut libc::c_void,
1110                addr_of_mut!($queue.end) as *mut *mut libc::c_void,
1111            );
1112        }
1113        $enqueue;
1114        $queue.tail = $queue.tail.wrapping_offset(1);
1115    }};
1116    ($queue:expr, *$value:expr) => {
1117        ENQUEUE!(do $queue, ptr::copy_nonoverlapping($value, $queue.tail, 1))
1118    };
1119    ($queue:expr, $value:expr) => {
1120        ENQUEUE!(do $queue, ptr::write($queue.tail, $value))
1121    };
1122}
1123
1124/// Removes and returns the first element from the queue.
1125///
1126/// # Parameters
1127///
1128/// * `queue`: A mutable reference to the queue from which the first element will be removed.
1129///
1130/// # Return
1131///
1132/// * The first element from the queue.
1133#[macro_export]
1134macro_rules! DEQUEUE {
1135    ($queue:expr) => {
1136        *{
1137            let head = $queue.head;
1138            $queue.head = $queue.head.wrapping_offset(1);
1139            head
1140        }
1141    };
1142}
1143
1144/// Inserts a value into the queue at the specified index.
1145///
1146/// # Parameters
1147///
1148/// * `queue`: A mutable reference to the queue where the value will be inserted.
1149/// * `index`: The index at which the value will be inserted.
1150/// * `value`: The value to be inserted into the queue.
1151///
1152/// # Return
1153///
1154/// This macro does not return a value.
1155#[macro_export]
1156macro_rules! QUEUE_INSERT {
1157    ($queue:expr, $index:expr, $value:expr) => {{
1158        if $queue.tail == $queue.end {
1159            yaml_queue_extend(
1160                addr_of_mut!($queue.start) as *mut *mut libc::c_void,
1161                addr_of_mut!($queue.head) as *mut *mut libc::c_void,
1162                addr_of_mut!($queue.tail) as *mut *mut libc::c_void,
1163                addr_of_mut!($queue.end) as *mut *mut libc::c_void,
1164            );
1165        }
1166        let _ = memmove(
1167            $queue
1168                .head
1169                .wrapping_offset($index as isize)
1170                .wrapping_offset(1_isize)
1171                as *mut libc::c_void,
1172            $queue.head.wrapping_offset($index as isize)
1173                as *const libc::c_void,
1174            ($queue.tail.c_offset_from($queue.head) as libc::c_ulong)
1175                .wrapping_sub($index)
1176                .wrapping_mul(size_of::<YamlTokenT>() as libc::c_ulong),
1177        );
1178        *$queue.head.wrapping_offset($index as isize) = $value;
1179        let fresh14 = addr_of_mut!($queue.tail);
1180        *fresh14 = (*fresh14).wrapping_offset(1);
1181    }};
1182}