int git_message_trailers()

in src/trailer.c [297:424]


int git_message_trailers(git_message_trailer_array *trailer_arr, const char *message)
{
	enum trailer_state state = S_START;
	int rc = 0;
	char *ptr;
	char *key = NULL;
	char *value = NULL;
	git_array_trailer_t arr = GIT_ARRAY_INIT;

	size_t trailer_len;
	char *trailer = extract_trailer_block(message, &trailer_len);
	if (trailer == NULL)
		return -1;

	for (ptr = trailer;;) {
		switch (state) {
			case S_START: {
				if (*ptr == 0) {
					goto ret;
				}

				key = ptr;
				GOTO(S_KEY);
			}
			case S_KEY: {
				if (*ptr == 0) {
					goto ret;
				}

				if (isalnum(*ptr) || *ptr == '-') {
					/* legal key character */
					NEXT(S_KEY);
				}

				if (*ptr == ' ' || *ptr == '\t') {
					/* optional whitespace before separator */
					*ptr = 0;
					NEXT(S_KEY_WS);
				}

				if (strchr(TRAILER_SEPARATORS, *ptr)) {
					*ptr = 0;
					NEXT(S_SEP_WS);
				}

				/* illegal character */
				GOTO(S_IGNORE);
			}
			case S_KEY_WS: {
				if (*ptr == 0) {
					goto ret;
				}

				if (*ptr == ' ' || *ptr == '\t') {
					NEXT(S_KEY_WS);
				}

				if (strchr(TRAILER_SEPARATORS, *ptr)) {
					NEXT(S_SEP_WS);
				}

				/* illegal character */
				GOTO(S_IGNORE);
			}
			case S_SEP_WS: {
				if (*ptr == 0) {
					goto ret;
				}

				if (*ptr == ' ' || *ptr == '\t') {
					NEXT(S_SEP_WS);
				}

				value = ptr;
				NEXT(S_VALUE);
			}
			case S_VALUE: {
				if (*ptr == 0) {
					GOTO(S_VALUE_END);
				}

				if (*ptr == '\n') {
					NEXT(S_VALUE_NL);
				}

				NEXT(S_VALUE);
			}
			case S_VALUE_NL: {
				if (*ptr == ' ') {
					/* continuation; */
					NEXT(S_VALUE);
				}

				ptr[-1] = 0;
				GOTO(S_VALUE_END);
			}
			case S_VALUE_END: {
				git_message_trailer *t = git_array_alloc(arr);

				t->key = key;
				t->value = value;

				key = NULL;
				value = NULL;

				GOTO(S_START);
			}
			case S_IGNORE: {
				if (*ptr == 0) {
					goto ret;
				}

				if (*ptr == '\n') {
					NEXT(S_START);
				}

				NEXT(S_IGNORE);
			}
		}
	}

ret:
	trailer_arr->_trailer_block = trailer;
	trailer_arr->trailers = arr.ptr;
	trailer_arr->count = arr.size;

	return rc;
}