/* Copies a <sep>-delimited unit from <from> into a new entry in <to>. * * \<sep> is not counted as the separator, but copied to the new entry * as <sep>. No other escape sequences are supported. * * Returns the number of bytes read out of <from>; this may be more * than the length of the new entry in <to>. The new entry is * prepended; the caller can reverse <to> once built. */ static size_t SubStrnCopyChr(Rlist **to, const char *from, char sep, char lstrip) { assert(from && from[0]); size_t offset = 0; while (lstrip != '\0' && from[0] == lstrip && from[0] != '\0') { /* Skip over all instances of the 'lstrip' character (e.g. ' ') if * specified */ from++; offset++; } if (from[0] == '\0') { /* Reached the end already so there's nothing to add to the result list, just tell the caller how far they can move. */ return offset; } const char *end = from; size_t escapes = 0; while (end && end[0] && end[0] != sep) { end = strchr(end, sep); assert(end == NULL || end[0] == sep); if (end && end > from && end[-1] == '\\') { escapes++; end++; } } size_t consume = (end == NULL) ? strlen(from) : (end - from); assert(consume >= escapes); char copy[1 + consume - escapes], *dst = copy; for (const char *src = from; src[0] != '\0' && src[0] != sep; src++) { if (src[0] == '\\' && src[1] == sep) { src++; /* Skip over the backslash so we copy the sep */ } dst++[0] = src[0]; } assert(dst + 1 == copy + sizeof(copy)); *dst = '\0'; /* Prepend to the list and reverse when done, costing O(len), * instead of appending, which costs O(len**2). */ RlistPrependRval(to, RvalCopyScalar((Rval) { copy, RVAL_TYPE_SCALAR })); return offset + consume; }
Rlist *RlistPrepend(Rlist **start, const void *item, RvalType type) { switch (type) { case RVAL_TYPE_LIST: { Rlist *lp = NULL; for (const Rlist *rp = item; rp; rp = rp->next) { lp = RlistPrependRval(start, RvalCopy(rp->val)); } return lp; } case RVAL_TYPE_SCALAR: case RVAL_TYPE_FNCALL: case RVAL_TYPE_CONTAINER: case RVAL_TYPE_NOPROMISEE: return RlistPrependRval(start, RvalNew(item, type)); } assert(false); return NULL; }
/* Copies a <sep>-delimited unit from <from> into a new entry in <to>. * * \<sep> is not counted as the separator, but copied to the new entry * as <sep>. No other escape sequences are supported. * * Returns the number of bytes read out of <from>; this may be more * than the length of the new entry in <to>. The new entry is * prepended; the caller can reverse <to> once built. */ static size_t SubStrnCopyChr(Rlist **to, const char *from, char sep) { assert(from && from[0]); const char *end = from; size_t escapes = 0; while (end && end[0] && end[0] != sep) { end = strchr(end, sep); assert(end == NULL || end[0] == sep); if (end && end > from && end[-1] == '\\') { escapes++; end++; } } size_t consume = (end == NULL) ? strlen(from) : (end - from); assert(consume >= escapes); char copy[1 + consume - escapes], *dst = copy; for (const char *src = from; src[0] != '\0' && src[0] != sep; src++) { if (src[0] == '\\' && src[1] == sep) { src++; /* Skip over the backslash so we copy the sep */ } dst++[0] = src[0]; } assert(dst + 1 == copy + sizeof(copy)); *dst = '\0'; /* Prepend to the list and reverse when done, costing O(len), * instead of appending, which costs O(len**2). */ RlistPrependRval(to, RvalCopyScalar((Rval) { copy, RVAL_TYPE_SCALAR })); return consume; }
static Rlist *RlistPrependFnCall(Rlist **start, const FnCall *fn) { return RlistPrependRval(start, RvalCopyFnCall((Rval) { (FnCall *)fn, RVAL_TYPE_FNCALL })); }
Rlist *RlistPrependScalar(Rlist **start, const char *scalar) { return RlistPrependRval(start, RvalCopyScalar((Rval) { (char *)scalar, RVAL_TYPE_SCALAR })); }