📄 uri.l
字号:
}<FRAGMENT>.|\n |<FRAGMENT><<EOF>> { yyless(0); BEGIN ACCEPT;}<ACCEPT>.|\n |<ACCEPT><<EOF>> { yyless(0); return __length;}<INITIAL>{URI-reference} return yyleng;<INITIAL>.|\n |<INITIAL><<EOF>> { yyless(0); return 0;}%%int yywrap(void){ return 1;}#define URI_INIT(uri) \do { \ (uri)->scheme = NULL; \ (uri)->authority = NULL; \ (uri)->path = NULL; \ (uri)->query = NULL; \ (uri)->fragment = NULL; \} while (0)static int __uri_parse(struct uri *uri){ URI_INIT(uri); __uri = uri; __length = 0; BEGIN SCHEME; return yylex();}/* Scan a file and return the length of the uri. Return negative number * when and only when failed to allocate memory. */int uri_parse_file(struct uri *uri, FILE *file){ YY_BUFFER_STATE buf; int n = -1; yyin = file; if (buf = yy_create_buffer(yyin, YY_BUF_SIZE)) { yy_switch_to_buffer(buf); n = __uri_parse(uri); yy_delete_buffer(buf); } return n;}/* Scan a string ('\0' terminated). */int uri_parse_string(struct uri *uri, const char *string){ YY_BUFFER_STATE buf; int n = -1; if (buf = yy_scan_string(string)) { yy_switch_to_buffer(buf); n = __uri_parse(uri); yy_delete_buffer(buf); } return n;}/* Scan some memory bytes. */int uri_parse_bytes(struct uri *uri, const char *bytes, int len){ YY_BUFFER_STATE buf; int n = -1; if (buf = yy_scan_bytes(bytes, len)) { yy_switch_to_buffer(buf); n = __uri_parse(uri); yy_delete_buffer(buf); } return n;}/* Scan some memory bytes. The last two bytes of the memory MUST be '\0', or * the function will return -1 indicating a failure. This function has better * performance than "uri_parse_bytes", but note there is NO "const" key * word before the "base" argument, which means the content of memory may * be changed. */int uri_parse_buffer(struct uri *uri, char *base, unsigned int size){ YY_BUFFER_STATE buf; int n = -1; if (buf = yy_scan_buffer(base, size)) { yy_switch_to_buffer(buf); n = __uri_parse(uri); yy_delete_buffer(buf); } return n;}void uri_destroy(struct uri *uri){ URI_FREE(uri->scheme); if (uri->authority) { URI_AUTH_DESTROY(uri->authority); free(uri->authority); } URI_FREE(uri->path); URI_FREE(uri->query); URI_FREE(uri->fragment);}int __uri_length(void){ BEGIN INITIAL; return yylex();}int uri_length_string(const char *string){ YY_BUFFER_STATE buf; int n = -1; if (buf = yy_scan_string(string)) { yy_switch_to_buffer(buf); n = __uri_length(); yy_delete_buffer(buf); } return n;}int uri_length_bytes(const char *bytes, int len){ YY_BUFFER_STATE buf; int n = -1; if (buf = yy_scan_bytes(bytes, len)) { yy_switch_to_buffer(buf); n = __uri_length(); yy_delete_buffer(buf); } return n;}/* Validate a string ('\0' terminated). */int uri_validate_string(const char *string){ int n = uri_length_string(string); return n >= 0 ? n == strlen(string) : n;}/* Validate some memory bytes. */int uri_validate_bytes(const char *bytes, int len){ int n = uri_length_bytes(bytes, len); return n >= 0 ? n == len : n;}/* Merge two path. It sounds easy but indeed quite troublesome if you take * everything into consideration. Core of merging two URIs. The function will * allocate memory for you, which is NOT a very good programming style you * should not follow. */int __uri_path_merge(char **abs_path, const char *rel_path, const char *base_path){ int len; STACK *stack; const char *curpos; int seglen; const char *next_slash; int i; /* This merging algorithm is different from RFC 2396, which uses string, * while this algorithm uses stack. */ if (!(stack = stack_create(STACK_INITIAL_SIZE))) return -1; /* The "base_path" and the "rel_path" are divided into segments and push * all these segments and their length into the stack. If a segment * is ".", ignore it; if a segment is "..", pop one segment out. */ len = 0; for (i = 0; i < 2; i++) { /* Both "rel_path" and "base_path" can be NULL. */ if (curpos = base_path) { while (next_slash = strchr(curpos, '/')) { if (strncmp(curpos, "../", next_slash - curpos + 1) == 0) { if (stack_height(stack) > sizeof (char *) + sizeof (int) || !stack_empty(stack) && stack_top(stack, int) != 1) { len -= stack_pop(stack, int); stack_pop(stack, const char *); } } else if (strncmp(curpos, "./", next_slash - curpos + 1) != 0) { len += next_slash - curpos + 1; if (stack_push(stack, curpos, const char *) < 0 || stack_push(stack, next_slash - curpos + 1, int) < 0) { stack_destroy(stack); return -1; } } curpos = next_slash + 1; } base_path = rel_path; } } /* This part deals with the "filename", which may be empty, may be "..", * may be ".", and may be something else like "index.html". */ if (curpos) { if (strcmp(curpos, "..") == 0) { if (stack_height(stack) > sizeof (char *) + sizeof (int) || !stack_empty(stack) && stack_top(stack, int) != 1) { len -= stack_pop(stack, int); stack_pop(stack, const char *); } } else if (strcmp(curpos, ".") != 0) { len += strlen(curpos); if (stack_push(stack, curpos, const char *) < 0 || stack_push(stack, strlen(curpos), int) < 0) { stack_destroy(stack); return -1; } } } /* The result path is an "empty path". We should turn it into "no path". * "no path" is allowed while "empty path" is illegal. */ if (len == 0) { *abs_path = NULL; return 0; } /* Example: * rel_path: "../././../game/../document/rfc/rfc2616.pdf" * base_path: "/pub/incoming/./software/linux/nasm.tar.gz", * Now the stack is: * * +---------------+ <-- stack top * | 11 | * +---------------| * | rfc2616.pdf | * +---------------| * | 4 | * |---------------| * | rfc/ | * |---------------| * | 9 | * |---------------| * | document/ | * |---------------| * | 9 | * |---------------| * | incoming/ | * |---------------| * | 4 | * |---------------| * | pub/ | * |---------------| * | 1 | * |---------------| * | / | * +---------------+ <-- stack base * * len = 1 + 4 + 9 + 9 + 4 + 11 = ?? * * Note that we do NOT copy the segments into the stack, we just push the * pointers into the stack. * * All the information we need to compose the result path has been here. */ if (*abs_path = (char *)malloc((len + 1) * sizeof (char))) { *abs_path = *abs_path + len; **abs_path = '\0'; while (!stack_empty(stack)) { seglen = stack_pop(stack, int); *abs_path -= seglen; memcpy(*abs_path, stack_pop(stack, const char *), seglen); } } else len = -1; stack_destroy(stack); return len;}int uri_merge(struct uri *abs_uri, const struct uri *rel_uri, const struct uri *base_uri){ int len, n; /* I am lazy. */ #define __URI_STRDUP(str) \ ({ \ char *__res; \ if (str) \ { \ if (__res = strdup(str)) \ len += strlen(__res); \ else \ break; \ } \ else \ __res = NULL; \ __res; \ }) #define __URI_AUTH_DUP(auth) \ ({ \ struct authority *__res; \ if (auth) \ { \ if (__res = (struct authority *) \ malloc(sizeof (struct authority))) \ URI_AUTH_INIT(__res, (auth)->type); \ else \ break; \ if ((auth)->type == AT_SERVER) \ { \ if (__res->userinfo = __URI_STRDUP((auth)->userinfo)) \ len++; \ __res->host = __URI_STRDUP((auth)->host); \ if (__res->port = __URI_STRDUP((auth)->port)) \ len++; \ } \ else \ __res->reg_name = __URI_STRDUP((auth)->reg_name); \ len += 2; \ } \ else \ __res = NULL; \ __res; \ }) URI_INIT(abs_uri); len = 0; do { /* If the relative URI has a scheme, take it; else take the scheme * of the base URI. */ if (rel_uri->scheme) { abs_uri->scheme = __URI_STRDUP(rel_uri->scheme); len++; } else if (abs_uri->scheme = __URI_STRDUP(base_uri->scheme)) len++; /* If the relative URI has a scheme or an authority, take it's * authority; else take the authority of the base URI. */ if (rel_uri->scheme || rel_uri->authority) abs_uri->authority = __URI_AUTH_DUP(rel_uri->authority); else abs_uri->authority = __URI_AUTH_DUP(base_uri->authority); /* If the relative URI has a scheme or an authority or an absolute * path, take it's path; else if the relative URI does not have a * path, take the base URI's path; else if base URI has a path, * merge the relative URI's path with the base URI's path, and take * the result; else if the base URI has no path, merge the relative * URI's path with path "/" and take the result; no else. */ if (rel_uri->scheme || rel_uri->authority || rel_uri->path && *rel_uri->path == '/') abs_uri->path = __URI_STRDUP(rel_uri->path); else if (!rel_uri->path) abs_uri->path = __URI_STRDUP(base_uri->path); else if ((n = __uri_path_merge(&abs_uri->path, rel_uri->path, base_uri->path ? base_uri->path : "/")) >= 0) len += n; else break; /* Query is taken from relative URI. */ if (abs_uri->query = __URI_STRDUP(rel_uri->query)) len++; /* Fragment is taken from relative URI. */ if (abs_uri->fragment = __URI_STRDUP(rel_uri->fragment)) len++; return len; } while (0); #undef __URI_AUTH_DUP #undef __URI_STRDUP uri_destroy(abs_uri); return -1;}/* Recombine a URI structure into a URI string. Quite boring. */int uri_recombine(const struct uri *uri, char *uristr, unsigned int len){ char *curpos = uristr; char *end = curpos + len; unsigned int n; do { if (uri->scheme) { n = strlen(uri->scheme); if (curpos + n + 1 < end) { MEMCPY_PLUS(curpos, uri->scheme, n); *curpos++ = ':'; } else break; } if (uri->authority) { if (curpos + 2 < end) { *curpos++ = '/'; *curpos++ = '/'; } else break; if (uri->authority->type == AT_SERVER) { if (uri->authority->userinfo) { n = strlen(uri->authority->userinfo); if (curpos + n + 1 < end) { MEMCPY_PLUS(curpos, uri->authority->userinfo, n); *curpos++ = '@'; } else break; } if (uri->authority->host) { n = strlen(uri->authority->host); if (curpos + n < end) MEMCPY_PLUS(curpos, uri->authority->host, n); else break; } if (uri->authority->port) { n = strlen(uri->authority->port); if (curpos + n + 1 < end) { *curpos++ = ':'; MEMCPY_PLUS(curpos, uri->authority->port, n); } else break; } } else if (uri->authority->type == AT_REG_NAME) { if (uri->authority->reg_name) { n = strlen(uri->authority->reg_name); if (curpos + n < end) MEMCPY_PLUS(curpos, uri->authority->reg_name, n); else break; } } } if (uri->path) { n = strlen(uri->path); if (curpos + n < end) MEMCPY_PLUS(curpos, uri->path, n); else break; } if (uri->query) { n = strlen(uri->query); if (curpos + n + 1 < end) { *curpos++ = '?'; MEMCPY_PLUS(curpos, uri->query, n); } else break; } if (uri->fragment) { n = strlen(uri->fragment); if (curpos + n + 1 < end) { *curpos++ = '#'; MEMCPY_PLUS(curpos, uri->fragment, n); } else break; } if (curpos < end) *curpos = '\0'; else break; return curpos - uristr; } while (0); errno = ENOSPC; return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -