refspec: factor out parsing a single refspec
Factor out the logic which parses a single refspec into its own function. This makes it easier to reuse this logic in a future patch. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									0ad4a5ff50
								
							
						
					
					
						commit
						3eec3700fd
					
				
							
								
								
									
										205
									
								
								refspec.c
								
								
								
								
							
							
						
						
									
										205
									
								
								refspec.c
								
								
								
								
							|  | @ -14,110 +14,123 @@ static struct refspec_item s_tag_refspec = { | |||
| /* See TAG_REFSPEC for the string version */ | ||||
| const struct refspec_item *tag_refspec = &s_tag_refspec; | ||||
|  | ||||
| /* | ||||
|  * Parses the provided refspec 'refspec' and populates the refspec_item 'item'. | ||||
|  * Returns 1 if successful and 0 if the refspec is invalid. | ||||
|  */ | ||||
| static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch) | ||||
| { | ||||
| 	size_t llen; | ||||
| 	int is_glob; | ||||
| 	const char *lhs, *rhs; | ||||
| 	int flags; | ||||
|  | ||||
| 	is_glob = 0; | ||||
|  | ||||
| 	lhs = refspec; | ||||
| 	if (*lhs == '+') { | ||||
| 		item->force = 1; | ||||
| 		lhs++; | ||||
| 	} | ||||
|  | ||||
| 	rhs = strrchr(lhs, ':'); | ||||
|  | ||||
| 	/* | ||||
| 	 * Before going on, special case ":" (or "+:") as a refspec | ||||
| 	 * for pushing matching refs. | ||||
| 	 */ | ||||
| 	if (!fetch && rhs == lhs && rhs[1] == '\0') { | ||||
| 		item->matching = 1; | ||||
| 		return 1; | ||||
| 	} | ||||
|  | ||||
| 	if (rhs) { | ||||
| 		size_t rlen = strlen(++rhs); | ||||
| 		is_glob = (1 <= rlen && strchr(rhs, '*')); | ||||
| 		item->dst = xstrndup(rhs, rlen); | ||||
| 	} | ||||
|  | ||||
| 	llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); | ||||
| 	if (1 <= llen && memchr(lhs, '*', llen)) { | ||||
| 		if ((rhs && !is_glob) || (!rhs && fetch)) | ||||
| 			return 0; | ||||
| 		is_glob = 1; | ||||
| 	} else if (rhs && is_glob) { | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	item->pattern = is_glob; | ||||
| 	item->src = xstrndup(lhs, llen); | ||||
| 	flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); | ||||
|  | ||||
| 	if (fetch) { | ||||
| 		struct object_id unused; | ||||
|  | ||||
| 		/* LHS */ | ||||
| 		if (!*item->src) | ||||
| 			; /* empty is ok; it means "HEAD" */ | ||||
| 		else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused)) | ||||
| 			item->exact_sha1 = 1; /* ok */ | ||||
| 		else if (!check_refname_format(item->src, flags)) | ||||
| 			; /* valid looking ref is ok */ | ||||
| 		else | ||||
| 			return 0; | ||||
| 		/* RHS */ | ||||
| 		if (!item->dst) | ||||
| 			; /* missing is ok; it is the same as empty */ | ||||
| 		else if (!*item->dst) | ||||
| 			; /* empty is ok; it means "do not store" */ | ||||
| 		else if (!check_refname_format(item->dst, flags)) | ||||
| 			; /* valid looking ref is ok */ | ||||
| 		else | ||||
| 			return 0; | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * LHS | ||||
| 		 * - empty is allowed; it means delete. | ||||
| 		 * - when wildcarded, it must be a valid looking ref. | ||||
| 		 * - otherwise, it must be an extended SHA-1, but | ||||
| 		 *   there is no existing way to validate this. | ||||
| 		 */ | ||||
| 		if (!*item->src) | ||||
| 			; /* empty is ok */ | ||||
| 		else if (is_glob) { | ||||
| 			if (check_refname_format(item->src, flags)) | ||||
| 				return 0; | ||||
| 		} | ||||
| 		else | ||||
| 			; /* anything goes, for now */ | ||||
| 		/* | ||||
| 		 * RHS | ||||
| 		 * - missing is allowed, but LHS then must be a | ||||
| 		 *   valid looking ref. | ||||
| 		 * - empty is not allowed. | ||||
| 		 * - otherwise it must be a valid looking ref. | ||||
| 		 */ | ||||
| 		if (!item->dst) { | ||||
| 			if (check_refname_format(item->src, flags)) | ||||
| 				return 0; | ||||
| 		} else if (!*item->dst) { | ||||
| 			return 0; | ||||
| 		} else { | ||||
| 			if (check_refname_format(item->dst, flags)) | ||||
| 				return 0; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) | ||||
| { | ||||
| 	int i; | ||||
| 	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs)); | ||||
|  | ||||
| 	for (i = 0; i < nr_refspec; i++) { | ||||
| 		size_t llen; | ||||
| 		int is_glob; | ||||
| 		const char *lhs, *rhs; | ||||
| 		int flags; | ||||
|  | ||||
| 		is_glob = 0; | ||||
|  | ||||
| 		lhs = refspec[i]; | ||||
| 		if (*lhs == '+') { | ||||
| 			rs[i].force = 1; | ||||
| 			lhs++; | ||||
| 		} | ||||
|  | ||||
| 		rhs = strrchr(lhs, ':'); | ||||
|  | ||||
| 		/* | ||||
| 		 * Before going on, special case ":" (or "+:") as a refspec | ||||
| 		 * for pushing matching refs. | ||||
| 		 */ | ||||
| 		if (!fetch && rhs == lhs && rhs[1] == '\0') { | ||||
| 			rs[i].matching = 1; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		if (rhs) { | ||||
| 			size_t rlen = strlen(++rhs); | ||||
| 			is_glob = (1 <= rlen && strchr(rhs, '*')); | ||||
| 			rs[i].dst = xstrndup(rhs, rlen); | ||||
| 		} | ||||
|  | ||||
| 		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); | ||||
| 		if (1 <= llen && memchr(lhs, '*', llen)) { | ||||
| 			if ((rhs && !is_glob) || (!rhs && fetch)) | ||||
| 				goto invalid; | ||||
| 			is_glob = 1; | ||||
| 		} else if (rhs && is_glob) { | ||||
| 		if (!parse_refspec(&rs[i], refspec[i], fetch)) | ||||
| 			goto invalid; | ||||
| 		} | ||||
|  | ||||
| 		rs[i].pattern = is_glob; | ||||
| 		rs[i].src = xstrndup(lhs, llen); | ||||
| 		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); | ||||
|  | ||||
| 		if (fetch) { | ||||
| 			struct object_id unused; | ||||
|  | ||||
| 			/* LHS */ | ||||
| 			if (!*rs[i].src) | ||||
| 				; /* empty is ok; it means "HEAD" */ | ||||
| 			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused)) | ||||
| 				rs[i].exact_sha1 = 1; /* ok */ | ||||
| 			else if (!check_refname_format(rs[i].src, flags)) | ||||
| 				; /* valid looking ref is ok */ | ||||
| 			else | ||||
| 				goto invalid; | ||||
| 			/* RHS */ | ||||
| 			if (!rs[i].dst) | ||||
| 				; /* missing is ok; it is the same as empty */ | ||||
| 			else if (!*rs[i].dst) | ||||
| 				; /* empty is ok; it means "do not store" */ | ||||
| 			else if (!check_refname_format(rs[i].dst, flags)) | ||||
| 				; /* valid looking ref is ok */ | ||||
| 			else | ||||
| 				goto invalid; | ||||
| 		} else { | ||||
| 			/* | ||||
| 			 * LHS | ||||
| 			 * - empty is allowed; it means delete. | ||||
| 			 * - when wildcarded, it must be a valid looking ref. | ||||
| 			 * - otherwise, it must be an extended SHA-1, but | ||||
| 			 *   there is no existing way to validate this. | ||||
| 			 */ | ||||
| 			if (!*rs[i].src) | ||||
| 				; /* empty is ok */ | ||||
| 			else if (is_glob) { | ||||
| 				if (check_refname_format(rs[i].src, flags)) | ||||
| 					goto invalid; | ||||
| 			} | ||||
| 			else | ||||
| 				; /* anything goes, for now */ | ||||
| 			/* | ||||
| 			 * RHS | ||||
| 			 * - missing is allowed, but LHS then must be a | ||||
| 			 *   valid looking ref. | ||||
| 			 * - empty is not allowed. | ||||
| 			 * - otherwise it must be a valid looking ref. | ||||
| 			 */ | ||||
| 			if (!rs[i].dst) { | ||||
| 				if (check_refname_format(rs[i].src, flags)) | ||||
| 					goto invalid; | ||||
| 			} else if (!*rs[i].dst) { | ||||
| 				goto invalid; | ||||
| 			} else { | ||||
| 				if (check_refname_format(rs[i].dst, flags)) | ||||
| 					goto invalid; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return rs; | ||||
|  | ||||
|  invalid: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Brandon Williams
						Brandon Williams