blob: e6ddcfe5c5c25ef4d3e5d13b62e57d36bf75b6cc [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "hf/memiter.h"
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010010
David Brazdilb856be62020-03-25 10:14:55 +000011#include "hf/check.h"
David Brazdil7a462ec2019-08-15 12:27:47 +010012#include "hf/dlog.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010013#include "hf/std.h"
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010014
15/**
16 * Initialises the given memory iterator.
17 */
18void memiter_init(struct memiter *it, const void *data, size_t size)
19{
20 it->next = data;
21 it->limit = it->next + size;
22}
23
24/**
25 * Determines if the next character is a whitespace.
26 */
27static bool memiter_isspace(struct memiter *it)
28{
29 switch (*it->next) {
30 case ' ':
31 case '\t':
32 case '\n':
33 case '\r':
34 return true;
35 default:
36 return false;
37 }
38}
39
40/**
41 * Moves iterator to the next non-whitespace character.
42 */
43static void memiter_skip_space(struct memiter *it)
44{
45 while (it->next < it->limit && memiter_isspace(it)) {
46 it->next++;
47 }
48}
49
50/**
51 * Compares the iterator to a null-terminated string.
52 */
53bool memiter_iseq(const struct memiter *it, const char *str)
54{
Andrew Scull55baca62019-04-05 14:56:20 +010055 size_t it_len = it->limit - it->next;
56 size_t len = strnlen_s(str, it_len + 1);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +000057
Andrew Scull55baca62019-04-05 14:56:20 +010058 if (len != it_len) {
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010059 return false;
60 }
Wedson Almeida Filho81568c42019-01-04 13:33:02 +000061
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +010062 return memcmp(it->next, str, len) == 0;
63}
64
65/**
66 * Retrieves the next string that is delimited by whitespaces. The result is
67 * stored in "str".
68 */
69bool memiter_parse_str(struct memiter *it, struct memiter *str)
70{
71 /* Skip all white space and fail if we reach the end of the buffer. */
72 memiter_skip_space(it);
73 if (it->next >= it->limit) {
74 return false;
75 }
76
77 str->next = it->next;
78
79 /* Find the end of the string. */
80 while (it->next < it->limit && !memiter_isspace(it)) {
81 it->next++;
82 }
83
84 str->limit = it->next;
85
86 return true;
87}
88
89/**
90 * Parses the next string that represents a 64-bit number.
91 */
92bool memiter_parse_uint(struct memiter *it, uint64_t *value)
93{
94 uint64_t v = 0;
95
96 /* Skip all white space and fail if we reach the end of the buffer. */
97 memiter_skip_space(it);
98 if (it->next >= it->limit) {
99 return false;
100 }
101
102 /* Fail if it's not a number. */
103 if (*it->next < '0' || *it->next > '9') {
104 return false;
105 }
106
107 /* Parse the number. */
108 do {
109 v = v * 10 + *it->next - '0';
110 it->next++;
111 } while (it->next < it->limit && *it->next >= '0' && *it->next <= '9');
112
113 *value = v;
114
115 return true;
116}
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100117
118/**
119 * Advances the iterator by the given number of bytes. Returns true if the
120 * iterator was advanced without going over its limit; returns false and leaves
121 * the iterator unmodified otherwise.
122 */
123bool memiter_advance(struct memiter *it, size_t v)
124{
125 const char *p = it->next + v;
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000126
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100127 if (p < it->next || p > it->limit) {
128 return false;
129 }
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000130
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100131 it->next = p;
David Brazdilb856be62020-03-25 10:14:55 +0000132 return true;
133}
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000134
David Brazdilb856be62020-03-25 10:14:55 +0000135/**
136 * Decrements the limit of iterator by the given number of bytes. Returns true
137 * if the limit was reduced without going over the base; returns false and
138 * leaves the iterator unmodified otherwise.
139 */
140bool memiter_restrict(struct memiter *it, size_t v)
141{
142 size_t s = memiter_size(it);
143
144 if (v > s) {
145 return false;
146 }
147
148 it->limit = it->next + (s - v);
149 return true;
150}
151
152/**
153 * Initializes `newit` with the first `v` bytes of `it` and advances `it` by
154 * the same number of bytes. This splits the original range into two iterators
155 * after `v` bytes.
156 * Returns true on success; returns false and leaves `it` unmodified and `newit`
157 * uninitialized otherwise.
158 */
159bool memiter_consume(struct memiter *it, size_t v, struct memiter *newit)
160{
161 if (v > memiter_size(it)) {
162 return false;
163 }
164
165 memiter_init(newit, memiter_base(it), v);
166 CHECK(memiter_advance(it, v));
Wedson Almeida Filho9ee60e92018-07-23 18:56:56 +0100167 return true;
168}
David Brazdil7a462ec2019-08-15 12:27:47 +0100169
David Brazdil74e9c3b2019-08-28 11:09:08 +0100170const void *memiter_base(const struct memiter *it)
David Brazdil7a462ec2019-08-15 12:27:47 +0100171{
172 return (const void *)it->next;
173}
174
175/**
176 * Returns the number of bytes in interval [it.next, it.limit).
177 */
David Brazdil74e9c3b2019-08-28 11:09:08 +0100178size_t memiter_size(const struct memiter *it)
David Brazdil7a462ec2019-08-15 12:27:47 +0100179{
180 return it->limit - it->next;
181}