/* bufnew • allocation of a new buffer */ struct buf * #ifndef TRACK_BUFFER_DEBUG bufnew(size_t unit) { #else bufnew_(size_t unit, const char *file, int line) { struct buf_debug_data *bdd; #endif struct buf *ret; ret = malloc(sizeof (struct buf)); if (ret) { #ifdef BUFFER_STATS buffer_stat_nb += 1; #endif #ifdef TRACK_BUFFERS parr_push(&all_buffers, ret); #endif ret->data = 0; ret->size = ret->asize = 0; ret->ref = 1; ret->unit = unit; } #ifdef TRACK_BUFFER_DEBUG if (ret) { bdd = arr_item(&all_buffers, arr_newitem(&all_buffers)); bdd->buf = ret; bdd->dupped = 0; bdd->ctime = time(0); bdd->file = file; bdd->line = line; } return ret; } #else return ret; }
/* bufdup • buffer duplication */ struct buf * #ifndef TRACK_BUFFER_DEBUG bufdup(const struct buf *src, size_t dupunit) { #else bufdup_(const struct buf *src, size_t dupunit, const char *file, int line) { struct buf_debug_data *bdd; #endif size_t blocks; struct buf *ret; if (src == 0) return 0; ret = malloc(sizeof (struct buf)); if (ret == 0) return 0; ret->unit = dupunit; ret->size = src->size; ret->ref = 1; if (!src->size) { #ifdef BUFFER_STATS buffer_stat_nb += 1; #endif ret->asize = 0; ret->data = 0; return ret; } blocks = (src->size + dupunit - 1) / dupunit; ret->asize = blocks * dupunit; ret->data = malloc(ret->asize); if (ret->data == 0) { free(ret); return 0; } memcpy(ret->data, src->data, src->size); #ifdef BUFFER_STATS buffer_stat_nb += 1; buffer_stat_alloc_bytes += ret->asize; #endif #ifdef TRACK_BUFFERS parr_push(&all_buffers, ret); #endif #ifdef TRACK_BUFFER_DEBUG bdd = arr_item(&all_buffers, arr_newitem(&all_buffers)); bdd->buf = ret; bdd->dupped = 1; bdd->ctime = time(0); bdd->file = file; bdd->line = line; return ret; } #else return ret; }
/* is_ref • returns whether a line is a reference or not */ static int is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs) { size_t i = 0; size_t id_offset, id_end; size_t link_offset, link_end; size_t title_offset, title_end; size_t line_end; struct link_ref *lr; struct buf *id; /* up to 3 optional leading spaces */ if (beg + 3 >= end) return 0; if (data[beg] == ' ') { i = 1; if (data[beg + 1] == ' ') { i = 2; if (data[beg + 2] == ' ') { i = 3; if (data[beg + 3] == ' ') return 0; } } } i += beg; /* id part: anything but a newline between brackets */ if (data[i] != '[') return 0; i += 1; id_offset = i; while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') i += 1; if (i >= end || data[i] != ']') return 0; id_end = i; /* spacer: colon (space | tab)* newline? (space | tab)* */ i += 1; if (i >= end || data[i] != ':') return 0; i += 1; while (i < end && (data[i] == ' ' || data[i] == '\t')) i += 1; if (i < end && (data[i] == '\n' || data[i] == '\r')) { i += 1; if (i < end && data[i] == '\r' && data[i - 1] == '\n') i += 1; } while (i < end && (data[i] == ' ' || data[i] == '\t')) i += 1; if (i >= end) return 0; /* link: whitespace-free sequence, optionally between angle brackets */ if (data[i] == '<') i += 1; link_offset = i; while (i < end && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r') i += 1; if (data[i - 1] == '>') link_end = i - 1; else link_end = i; /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ while (i < end && (data[i] == ' ' || data[i] == '\t')) i += 1; if (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(') return 0; line_end = 0; /* computing end-of-line */ if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') line_end = i + 1; /* optional (space|tab)* spacer after a newline */ if (line_end) { i = line_end + 1; while (i < end && (data[i] == ' ' || data[i] == '\t')) i += 1; } /* optional title: any non-newline sequence enclosed in '"() alone on its line */ title_offset = title_end = 0; if (i + 1 < end && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { i += 1; title_offset = i; /* looking for EOL */ while (i < end && data[i] != '\n' && data[i] != '\r') i += 1; if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') title_end = i + 1; else title_end = i; /* stepping back */ i -= 1; while (i > title_offset && (data[i] == ' ' || data[i] == '\t')) i -= 1; if (i > title_offset && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { line_end = title_end; title_end = i; } } if (!line_end) return 0; /* garbage after the link */ /* a valid ref has been found, filling-in return structures */ if (last) *last = line_end; if (!refs) return 1; id = bufnew(WORK_UNIT); if (build_ref_id(id, data + id_offset, id_end - id_offset) < 0) { bufrelease(id); return 0; } lr = arr_item(refs, arr_newitem(refs)); lr->id = id; lr->link = bufnew(link_end - link_offset); bufput(lr->link, data + link_offset, link_end - link_offset); if (title_end > title_offset) { lr->title = bufnew(title_end - title_offset); bufput(lr->title, data + title_offset, title_end - title_offset); } else lr->title = 0; return 1; }