static const char *ReferenceEnd(const char *str, size_t len) { assert(len > 1); assert(str[0] == '$'); assert(str[1] == '{' || str[1] == '('); #define MAX_VARIABLE_REFERENCE_LEVELS 10 char stack[MAX_VARIABLE_REFERENCE_LEVELS] = { 0, str[1], 0 }; int level = 1; for (size_t i = 2; i < len; i++) { switch (str[i]) { case '{': case '(': if (level < MAX_VARIABLE_REFERENCE_LEVELS - 1) { level++; stack[level] = str[i]; } else { Log(LOG_LEVEL_ERR, "Stack overflow in variable reference parsing. More than %d levels", MAX_VARIABLE_REFERENCE_LEVELS); return NULL; } break; case '}': if (stack[level] != '{') { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference bracket mismatch '%s'", StringWriterData(w)); WriterClose(w); return NULL; } level--; break; case ')': if (stack[level] != '(') { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference bracket mismatch '%s'", StringWriterData(w)); WriterClose(w); return NULL; } level--; break; } if (level == 0) { return str + i; } } return NULL; }
bool ExtractScalarReference(Buffer *out, const char *str, size_t len, bool extract_inner) { if (len <= 1) { return false; } const char *dollar_point = memchr(str, '$', len); if (!dollar_point || (dollar_point - str) == len) { return false; } else { const char *close_point = NULL; { size_t remaining = len - (dollar_point - str); if (*(dollar_point + 1) == '{' || *(dollar_point + 1) == '(') { close_point = ReferenceEnd(dollar_point, remaining); } else { return ExtractScalarReference(out, dollar_point + 1, remaining - 1, extract_inner); } } if (!close_point) { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference close mismatch '%s'", StringWriterData(w)); WriterClose(w); return false; } size_t outer_len = close_point - dollar_point + 1; if (outer_len <= 3) { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Empty variable reference close mismatch '%s'", StringWriterData(w)); WriterClose(w); return false; } if (extract_inner) { BufferAppend(out, dollar_point + 2, outer_len - 3); } else { BufferAppend(out, dollar_point, outer_len); } return true; } }
char *SearchAndReplace(const char *source, const char *search, const char *replace) { const char *source_ptr = source; if ((source == NULL) || (search == NULL) || (replace == NULL)) { ProgrammingError("Programming error: NULL argument is passed to SearchAndReplace"); } if (strcmp(search, "") == 0) { return xstrdup(source); } Writer *w = StringWriter(); for (;;) { const char *found_ptr = strstr(source_ptr, search); if (found_ptr == NULL) { WriterWrite(w, source_ptr); return StringWriterClose(w); } WriterWriteLen(w, source_ptr, found_ptr - source_ptr); WriterWrite(w, replace); source_ptr += found_ptr - source_ptr + strlen(search); } }
Writer *FileReadFromFd(int fd, size_t max_size, bool *truncated) { if (truncated) { *truncated = false; } Writer *w = StringWriter(); for (;;) { char buf[READ_BUFSIZE]; /* Reading more data than needed is deliberate. It is a truncation detection. */ ssize_t read_ = read(fd, buf, READ_BUFSIZE); if (read_ == 0) { /* Done. */ return w; } else if (read_ < 0) { if (errno != EINTR) { /* Something went wrong. */ WriterClose(w); return NULL; } /* Else: interrupted - try again. */ } else if (read_ + StringWriterLength(w) > max_size) { WriterWriteLen(w, buf, max_size - StringWriterLength(w)); /* Reached limit - stop. */ if (truncated) { *truncated = true; } return w; } else /* Filled buffer; copy and ask for more. */ { WriterWriteLen(w, buf, read_); } } }
Writer *FileRead(const char *filename, size_t max_size, bool *truncated) { int fd = open(filename, O_RDONLY); if (fd == -1) return NULL; Writer *w = StringWriter(); for (;;) { char buf[READ_BUFSIZE]; /* Reading more data than needed is deliberate. It is a truncation detection. */ ssize_t read_ = read(fd, buf, READ_BUFSIZE); if (read_ == 0) { if (truncated) *truncated = false; close(fd); return w; } if (read_ < 0) { if (errno == EINTR) continue; WriterClose(w); close(fd); return NULL; } if (read_ + StringWriterLength(w) > max_size) { WriterWriteLen(w, buf, max_size - StringWriterLength(w)); if (truncated) *truncated = true; close(fd); return w; } WriterWriteLen(w, buf, read_); } }
static void RenderContent(Writer *out, const char *content, size_t len, bool html, bool skip_content) { if (skip_content) { return; } if (html) { RenderHTMLContent(out, content, len); } else { WriterWriteLen(out, content, len); } }
size_t WriterWrite(Writer *writer, const char *str) { return WriterWriteLen(writer, str, INT_MAX); }