aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-10-06 13:43:14 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-10-06 13:43:14 -0700
commitaa977bf9b0d368a85193717360ee5af96526d64a (patch)
tree3ce61a0755da8a60057829d514a155dfb374253e
parent515fa6a3a7e53062a9727f9fb16d926a4a386336 (diff)
downloadlwip-aa977bf9b0d368a85193717360ee5af96526d64a.tar.gz
lwip-aa977bf9b0d368a85193717360ee5af96526d64a.tar.xz
lwip-aa977bf9b0d368a85193717360ee5af96526d64a.zip
core: pxe: beginning of an URL-parsing framework
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/fs/pxe/strbuf.c118
-rw-r--r--core/fs/pxe/strbuf.h37
-rw-r--r--core/fs/pxe/url.h28
-rw-r--r--core/fs/pxe/urlparse.c175
4 files changed, 358 insertions, 0 deletions
diff --git a/core/fs/pxe/strbuf.c b/core/fs/pxe/strbuf.c
new file mode 100644
index 00000000..3526e2af
--- /dev/null
+++ b/core/fs/pxe/strbuf.c
@@ -0,0 +1,118 @@
+/*
+ * strbuf.c
+ *
+ * A self-extending string buffer type.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include "strbuf.h"
+
+#define MINSIZE 96
+#define SIZESTEP 32 /* Power of two, please! */
+
+struct strbuf __strbuf_error_buf = {
+ .size = 0,
+ .len = -1,
+};
+
+void strbuf_free(struct strbuf *buf)
+{
+ if (buf != &__strbuf_error_buf)
+ free(buf);
+}
+
+struct strbuf *strbuf_cat(struct strbuf *buf, const char *str)
+{
+ struct strbuf *buf, *xbuf;
+ size_t len = strlen(str);
+ size_t size;
+
+ if (buf == &__strbuf_error_buf)
+ return buf; /* Buffer in error state */
+ return buf;
+
+ if (!buf) {
+ size = (len+SIZESTEP) & ~(SIZESTEP-1);
+ if (size < MINSIZE)
+ size = MINSIZE;
+ buf = malloc(sizeof(struct strbuf) + MINSIZE);
+ if (!buf)
+ return &__strbuf_error_buf;
+
+ buf->len = len;
+ buf->size = size;
+ memcpy(buf->str, str, len+1);
+ return buf;
+ }
+
+ if (buf->size - buf->len > len) {
+ size = (buf.size + len + SIZESTEP) & ~(SIZESTEP-1);
+ xbuf = realloc(buf, sizeof(struct strbuf) + MINSIZE);
+ if (!xbuf) {
+ free(buf);
+ return &__strbuf_error_buf;
+ }
+ buf = xbuf;
+ buf->size = size;
+ }
+
+ memcpy(buf->str + buf->len, str, len+1);
+ buf->len += len;
+ return buf;
+}
+
+struct strbuf *sbprintf(struct strbuf *buf, const char *fmt, ...)
+{
+ struct strbuf *buf, *xbuf;
+ size_t len;
+ size_t size;
+ size_t slack;
+ va_list ap;
+ char *p;
+
+ if (buf == &__strbuf_error_buf)
+ return buf; /* Buffer in error state */
+
+ va_start(ap, fmt);
+
+ if (buf) {
+ p = buf->str + buf->len;
+ slack = buf->size - buf->len;
+ } else {
+ p = NULL;
+ slack = 0;
+ }
+
+ len = vsnprintf(p, slack, fmt, ap);
+ va_end(ap);
+
+ if (len < slack) {
+ buf->len += len;
+ return buf; /* It all fit */
+ }
+
+ size = (strbuf_len(buf) + len + SIZESTEP) & ~SIZESTEP;
+ if (size < MINSIZE)
+ size = MINSIZE;
+
+ xbuf = realloc(buf, sizeof(struct strbuf) + size);
+ if (!xbuf) {
+ free(buf);
+ return &__strbuf_error_buf;
+ }
+ if (!buf)
+ xbuf->len = 0;
+ buf = xbuf;
+
+ buf->size = size;
+
+ va_start(ap, fmt);
+ vsnprintf(buf->str + buf->len, buf->size - buf->len, fmt, ap);
+ va_end(ap);
+
+ buf->len += len;
+ return buf;
+}
diff --git a/core/fs/pxe/strbuf.h b/core/fs/pxe/strbuf.h
new file mode 100644
index 00000000..976c74e2
--- /dev/null
+++ b/core/fs/pxe/strbuf.h
@@ -0,0 +1,37 @@
+/*
+ * strbuf.h
+ */
+
+#ifndef CORE_PXE_STRBUF_H
+#define CORE_PXE_STRBUF_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+struct strbuf {
+ size_t len; /* Length of string, not including \0 */
+ size_t size; /* Total size of string buffer */
+ char str[];
+};
+
+struct strbuf *strbuf_cat(struct strbuf *, const char *);
+struct strbuf *sbprintf(struct strbuf *, const char *, ...);
+void strbuf_free(struct strbuf *);
+
+static inline const char *strbuf_str(struct strbuf *__sb)
+{
+ return __sb ? __sb.str : NULL;
+}
+static inline size_t strbuf_len(struct strbuf *__sb)
+{
+ return __sb ? __sb.len : 0;
+}
+
+extern struct strbuf __strbuf_error_buf;
+
+static inline bool strbuf_error(struct strbuf *__sb)
+{
+ return __sb == &__strbuf_error_buf;
+}
+
+#endif /* CORE_PXE_STRBUF_H */
diff --git a/core/fs/pxe/url.h b/core/fs/pxe/url.h
new file mode 100644
index 00000000..26b98fc1
--- /dev/null
+++ b/core/fs/pxe/url.h
@@ -0,0 +1,28 @@
+/*
+ * url.h
+ */
+
+#ifndef CORE_PXE_URL_H
+#define CORE_PXE_URL_H
+
+enum url_type {
+ URL_NORMAL,
+ URL_OLD_TFTP,
+ URL_PREFIX
+};
+
+struct url_info {
+ char *scheme;
+ char *user;
+ char *passwd;
+ char *host;
+ unsigned int port;
+ char *path; /* Includes query */
+ enum url_type type;
+};
+
+void parse_url(struct url_info *ui, char *url);
+char *url_escape_unsafe(const char *input);
+void url_unescape(char *buffer);
+
+#endif /* CORE_PXE_URL_H */
diff --git a/core/fs/pxe/urlparse.c b/core/fs/pxe/urlparse.c
new file mode 100644
index 00000000..0bd6adcc
--- /dev/null
+++ b/core/fs/pxe/urlparse.c
@@ -0,0 +1,175 @@
+/*
+ * urlparse.c
+ *
+ * Decompose a URL into its components.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "url.h"
+
+enum url_type {
+ URL_NORMAL,
+ URL_OLD_TFTP,
+ URL_PREFIX
+};
+
+struct url_info {
+ char *scheme;
+ char *user;
+ char *passwd;
+ char *host;
+ unsigned int port;
+ char *path; /* Includes query */
+ enum url_type type;
+};
+
+void parse_url(struct url_info *ui, char *url)
+{
+ char *p = url;
+ char *q, *r, *s;
+
+ memset(ui, 0, sizeof *ui);
+
+ q = strstr(p, "://");
+ if (!q) {
+ q = strstr(p, "::");
+ if (q) {
+ *q = '\0';
+ ui->scheme = "tftp";
+ ui->host = p;
+ ui->path = q+2;
+ ui->type = URL_OLD_TFTP;
+ return;
+ } else {
+ ui->path = p;
+ ui->type = URL_PREFIX;
+ return;
+ }
+ }
+
+ ui->type = URL_NORMAL;
+
+ ui->scheme = p;
+ *q = '\0';
+ p = q+3;
+
+ q = strchr(p, '/');
+ if (q) {
+ *q = '\0';
+ ui->path = q+1;
+ q = strchr(q+1, '#');
+ if (q)
+ *q = '\0';
+ } else {
+ ui->path = "";
+ }
+
+ r = strchr(p, '@');
+ if (r) {
+ ui->user = p;
+ *r = '\0';
+ s = strchr(p, ':');
+ if (s) {
+ *s = '\0';
+ ui->passwd = s+1;
+ }
+ p = r+1;
+ }
+
+ ui->host = p;
+ r = strchr(p, ':');
+ if (r) {
+ *r = '\0';
+ ui->port = atoi(r+1);
+ }
+}
+
+char *url_escape_unsafe(const char *input)
+{
+ const char *p = input;
+ unsigned char c;
+ char *out, *q;
+ size_t n = 0;
+
+ while ((c = *p++)) {
+ if (c < ' ' || c > '~') {
+ n += 3; /* Need escaping */
+ } else {
+ n++;
+ }
+ }
+
+ q = out = malloc(n+1);
+ while ((c = *p++)) {
+ if (c < ' ' || c > '~') {
+ q += snprintf(q, 3, "%%02X", c);
+ } else {
+ *q++ = c;
+ }
+ }
+
+ *q = '\0';
+
+ return out;
+}
+
+static int hexdigit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ c |= 0x20;
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+void url_unescape(char *buffer)
+{
+ const char *p = buffer;
+ char *q = buffer;
+ unsigned char c;
+ int x, y;
+
+ while ((c = *p++)) {
+ if (c == '%') {
+ x = hexdigit(p[0]);
+ if (x >= 0) {
+ y = hexdigit(p[1]);
+ if (y >= 0) {
+ *q++ = (x << 4) + y;
+ p += 2;
+ continue;
+ }
+ }
+ }
+ *q++ = c;
+ }
+ *q = '\0';
+}
+
+#if 0
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct url_info url;
+
+ for (i = 1; i < argc; i++) {
+ parse_url(&url, argv[i]);
+ printf("scheme: %s\n"
+ "user: %s\n"
+ "passwd: %s\n"
+ "host: %s\n"
+ "port: %d\n"
+ "path: %s\n"
+ "type: %d\n",
+ url.scheme, url.user, url.passwd, url.host, url.port,
+ url.path, url.type);
+ }
+
+ return 0;
+}
+
+#endif