[MOD] Drop old Parser API, add new ID parser

This commit is contained in:
lda 2023-11-25 13:21:16 +01:00
parent 4a575cee1d
commit 4298ee469a
3 changed files with 68 additions and 254 deletions

View file

@ -24,149 +24,47 @@
#include <Parser.h> #include <Parser.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h> #include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
struct Parser {
char *string;
size_t idx;
ssize_t mark;
int eof;
};
Parser *
ParserCreate(char * str)
{
Parser * ret;
if (!str)
{
return NULL;
}
ret = Malloc(sizeof(Parser));
ret->string = StrDuplicate(str);
ret->idx = 0;
ret->eof = 0;
ret->mark = -1;
return ret;
}
void
ParserStartCopy(Parser * p)
{
if (!p)
{
return;
}
p->mark = p->idx;
}
char *
ParserEndCopy(Parser * p)
{
char *ret;
size_t len;
if (!p || p->mark < 0)
{
return NULL;
}
len = p->idx - p->mark;
ret = Malloc(len + 1);
memcpy(ret, p->string + p->mark, len);
ret[len] = '\0';
return ret;
}
int int
ParserExcept(Parser * p, char c) ParseCommonID(char *str, CommonID *id)
{ {
char strc; char sigil;
if (!p || p->eof) char *servstart;
if (!str || !id)
{ {
return 0; return 0;
} }
strc = p->string[p->idx++]; /* There must at least be 2 chararacters: the sigil and a string.*/
if (!strc) if (strlen(str) < 2)
{
p->eof = 1;
p->idx--; /* Avoid overflows */
}
return strc == c;
}
int
ParserExceptOneOf(Parser * p, const char * str)
{
char strc;
if (!p || !str || p->eof)
{ {
return 0; return 0;
} }
strc = p->string[p->idx++]; sigil = *str++;
if (!strc) /* Some sigils have the following restriction:
* > MUST NOT exceed 255 bytes (including the # sigil and the domain).
*/
if ((sigil == '#' || sigil == '@') && strlen(str) > 255)
{ {
p->eof = 1; return 0;
p->idx--; /* Avoid overflows */
} }
if (strchr(str, strc)) id->sigil = sigil;
{
return strc;
}
return 0;
}
int /* Find the position of a ':' if there is one. */
ParserGetc(Parser * p) if ((servstart = strchr(str, ':')))
{
int c;
if (!p || p->eof)
{ {
return EOF; id->local = StrSubstr(str, 1, (char) (servstart - str));
} id->server = StrDuplicate(servstart + 1);
c = p->string[p->idx++]; return 1;
if (!c)
{
p->eof = 1;
p->idx--; /* Avoid overflows */
c = EOF;
}
return c;
}
void
ParserUndo(Parser * p)
{
if (!p)
{
return;
} }
/* Otherwise, just take the rest of the string. */
id->local = StrDuplicate(str + 1) ;
id->server = NULL ;
if (!p->idx) return 1;
{
return;
}
p->eof = 0;
p->idx--;
} }
void
ParserEnd(Parser * p)
{
if (!p)
{
return;
}
Free(p->string);
Free(p);
}

View file

@ -31,10 +31,6 @@
#include <Cytoplasm/Int64.h> #include <Cytoplasm/Int64.h>
#include <Cytoplasm/UInt64.h> #include <Cytoplasm/UInt64.h>
#include <Parser.h>
#include <ctype.h>
#include <string.h> #include <string.h>
struct User struct User
@ -886,89 +882,51 @@ finish:
return arr; return arr;
} }
static int
UserIdParseLocal(Parser *p, char **ret)
{
int c;
if (!p || !ret)
{
return 0;
}
ParserStartCopy(p);
/* Always assume the general case here: every ASCII char,
* minus ':'. */
while (isascii((c = ParserGetc(p))) && c != ':')
{
/* Do nothing. */
}
if (c != EOF)
{
ParserUndo(p);
}
*ret = ParserEndCopy(p);
return 1;
}
static int
UserIdParseServer(Parser *p, char **ret)
{
int c;
if (!p || !ret)
{
return 0;
}
ParserStartCopy(p);
/* Allow *every* ASCII character. */
while (isascii((c = ParserGetc(p))))
{
/* Do nothing. */
}
if (c != EOF)
{
ParserUndo(p);
}
*ret = ParserEndCopy(p);
return 1;
}
UserId * UserId *
UserIdParse(char *id, char *defaultServer) UserIdParse(char *id, char *defaultServer)
{ {
UserId *userId; UserId *userId;
Parser *p;
if (!id) if (!id)
{ {
return NULL; return NULL;
} }
p = ParserCreate(id); id = StrDuplicate(id);
userId = Malloc(sizeof(UserId)); if (!id)
userId->localpart = NULL; {
userId->server = NULL; return NULL;
}
userId = Malloc(sizeof(UserId));
if (!userId) if (!userId)
{ {
goto finish; goto finish;
} }
/* Fully-qualified user ID. /* Fully-qualified user ID */
* TODO: Generalise this for parsing namespaced IDs, if (*id == '@')
* like room aliases and IDs. */
if (ParserExcept(p, '@'))
{ {
if (!UserIdParseLocal(p, &userId->localpart) || char *localStart = id + 1;
!ParserExcept(p, ':') || char *serverStart = localStart;
!UserIdParseServer(p, &userId->server))
while (*serverStart != ':' && *serverStart != '\0')
{
serverStart++;
}
if (*serverStart == '\0')
{ {
if (userId->localpart)
{
Free(userId->localpart);
}
Free(userId); Free(userId);
userId = NULL; userId = NULL;
goto finish;
} }
*serverStart = '\0';
serverStart++;
userId->localpart = StrDuplicate(localStart);
userId->server = StrDuplicate(serverStart);
} }
else else
{ {
@ -984,7 +942,7 @@ UserIdParse(char *id, char *defaultServer)
} }
finish: finish:
ParserEnd(p); Free(id);
return userId; return userId;
} }

View file

@ -26,73 +26,31 @@
/*** /***
* @Nm Parser * @Nm Parser
* @Nd Functions for dealing with simple grammars. * @Nd Functions for dealing with grammars found in Matrix
* @Dd November 24 2023 * @Dd November 25 2023
* @Xr User * @Xr User
* *
* The * The
* .Nm * .Nm
* API provides a simple parsing interface for basic parsers. * API provides an interface for parsing grammars within the
* Matrix specification
*/ */
/** /**
* A lot of functions here use this opaque structure. * A common identifier in the form '&local[:server]', where
* & determines the *type* of the identifier.
*/ */
typedef struct Parser Parser; typedef struct CommonID {
char sigil;
char *local;
char *server; /* Might be NULL for some sigils(e.g: room IDs >= v3) */
} CommonID;
/** /**
* Create a new parser with an input string. * Parses a common identifier, as per the Common Identifier Format as defined
* by the [matrix] specification.
*/ */
extern Parser * ParserCreate(char *); extern int ParseCommonID(char *, CommonID *);
/**
* Returns true if the character at the current position in
* the parsing process is the one given in, and advances by
* one character eitherway.
*/
extern int ParserExcept(Parser *, char);
/**
* Gets the currently pointed at character in the parser, then
* advances it by one, unless if hit by an EOF.
*/
extern int ParserGetc(Parser *);
/**
* Rolls back the currently pointed character by one(unless already
* at the start.)
*/
extern void ParserUndo(Parser *);
/**
* Returns a non-zero value if the character at the current position
* in the parsing process is one of the characters in the inputted
* string, and advances by one character eitherway.
*
* If non-zero, the return value is the actual character.
*/
extern int ParserExceptOneOf(Parser *, const char *);
/**
* Starts a clipping session. This stores an index into the
* parser, until
* .Fn ParserEndCopy
* is called.
*/
extern void ParserStartCopy(Parser *);
/**
* Ends a clipping station created by
* .Fn ParserStartCopy
* if it was called beforehand into a new buffer to be freed
* with
* .Fn Free .
*/
extern char * ParserEndCopy(Parser *);
/**
* Frees a parser created with
* .Fn ParserCreate .
*/
extern void ParserEnd(Parser *);
#endif /* TELODENDRIA_PARSER_H */ #endif /* TELODENDRIA_PARSER_H */