/* 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; }
Rval RvalCopy(Rval rval) { switch (rval.type) { case RVAL_TYPE_SCALAR: return RvalCopyScalar(rval); case RVAL_TYPE_FNCALL: return RvalCopyFnCall(rval); case RVAL_TYPE_LIST: return RvalCopyList(rval); default: Log(LOG_LEVEL_VERBOSE, "Unknown type %c in CopyRvalItem - should not happen", rval.type); return ((Rval) {NULL, rval.type}); } }
/* 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; }
Rlist *RlistAppendScalar(Rlist **start, const char *scalar) { return RlistAppendRval(start, RvalCopyScalar((Rval) { (char *)scalar, RVAL_TYPE_SCALAR })); }