Add a :ts[c] modifier to allow controlling the separator used between
words in a variable expansion. If 'c' is omitted no separator is used.
This commit is contained in:
parent
fadd31bf33
commit
f1cf540a8d
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: make.1,v 1.80 2003/06/26 18:21:45 wiz Exp $
|
||||
.\" $NetBSD: make.1,v 1.81 2003/07/14 20:39:20 sjg Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
|
@ -625,6 +625,13 @@ Replaces each word in the variable with everything but its suffix.
|
|||
Converts variable to lower-case letters.
|
||||
.It Cm tu
|
||||
Converts variable to upper-case letters.
|
||||
.It Cm ts Ar c
|
||||
Words in the variable are normally separated by a space on expansion.
|
||||
This modifier sets the separator to the character
|
||||
.Ar c .
|
||||
If
|
||||
.Ar c
|
||||
is omitted, then no separator is used.
|
||||
.Sm off
|
||||
.It Cm S No \&/ Ar old_string Xo
|
||||
.No \&/ Ar new_string
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: var.c,v 1.73 2003/07/14 18:19:13 christos Exp $ */
|
||||
/* $NetBSD: var.c,v 1.74 2003/07/14 20:39:20 sjg Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1988, 1989, 1990, 1993
|
||||
|
@ -39,14 +39,14 @@
|
|||
*/
|
||||
|
||||
#ifdef MAKE_BOOTSTRAP
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.73 2003/07/14 18:19:13 christos Exp $";
|
||||
static char rcsid[] = "$NetBSD: var.c,v 1.74 2003/07/14 20:39:20 sjg Exp $";
|
||||
#else
|
||||
#include <sys/cdefs.h>
|
||||
#ifndef lint
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.73 2003/07/14 18:19:13 christos Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.74 2003/07/14 20:39:20 sjg Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#endif
|
||||
|
@ -165,6 +165,8 @@ typedef struct Var {
|
|||
#define VAR_MATCH_END 0x10 /* Match at end of word */
|
||||
#define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */
|
||||
|
||||
static Byte varSpace = ' '; /* word separator in expansions */
|
||||
|
||||
/* Var_Set flags */
|
||||
#define VAR_NO_EXPORT 0x01 /* do not export */
|
||||
|
||||
|
@ -656,8 +658,8 @@ VarHead(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
|
||||
slash = strrchr (word, '/');
|
||||
if (slash != (char *)NULL) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte (buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte (buf, varSpace);
|
||||
}
|
||||
*slash = '\0';
|
||||
Buf_AddBytes (buf, strlen (word), (Byte *)word);
|
||||
|
@ -667,11 +669,9 @@ VarHead(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
/*
|
||||
* If no directory part, give . (q.v. the POSIX standard)
|
||||
*/
|
||||
if (addSpace) {
|
||||
Buf_AddBytes(buf, 2, (const Byte *)" .");
|
||||
} else {
|
||||
Buf_AddByte(buf, (Byte)'.');
|
||||
}
|
||||
if (addSpace && varSpace)
|
||||
Buf_AddByte(buf, varSpace);
|
||||
Buf_AddByte(buf, (Byte)'.');
|
||||
}
|
||||
return(dummy ? TRUE : TRUE);
|
||||
}
|
||||
|
@ -703,8 +703,8 @@ VarTail(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
{
|
||||
char *slash;
|
||||
|
||||
if (addSpace) {
|
||||
Buf_AddByte (buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte (buf, varSpace);
|
||||
}
|
||||
|
||||
slash = strrchr (word, '/');
|
||||
|
@ -746,8 +746,8 @@ VarSuffix(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
|
||||
dot = strrchr (word, '.');
|
||||
if (dot != (char *)NULL) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte (buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte (buf, varSpace);
|
||||
}
|
||||
*dot++ = '\0';
|
||||
Buf_AddBytes (buf, strlen (dot), (Byte *)dot);
|
||||
|
@ -784,8 +784,8 @@ VarRoot(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
{
|
||||
char *dot;
|
||||
|
||||
if (addSpace) {
|
||||
Buf_AddByte (buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte (buf, varSpace);
|
||||
}
|
||||
|
||||
dot = strrchr (word, '.');
|
||||
|
@ -826,8 +826,8 @@ VarMatch(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
ClientData pattern)
|
||||
{
|
||||
if (Str_Match(word, (char *) pattern)) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
addSpace = TRUE;
|
||||
Buf_AddBytes(buf, strlen(word), (Byte *)word);
|
||||
|
@ -868,8 +868,8 @@ VarSYSVMatch(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
VarPattern *pat = (VarPattern *) patp;
|
||||
char *varexp;
|
||||
|
||||
if (addSpace)
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace)
|
||||
Buf_AddByte(buf, varSpace);
|
||||
|
||||
addSpace = TRUE;
|
||||
|
||||
|
@ -913,8 +913,8 @@ VarNoMatch(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
ClientData pattern)
|
||||
{
|
||||
if (!Str_Match(word, (char *) pattern)) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
addSpace = TRUE;
|
||||
Buf_AddBytes(buf, strlen(word), (Byte *)word);
|
||||
|
@ -972,8 +972,8 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
* if rhs is non-null.
|
||||
*/
|
||||
if (pattern->rightLen != 0) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
addSpace = TRUE;
|
||||
Buf_AddBytes(buf, pattern->rightLen,
|
||||
|
@ -990,8 +990,8 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
* Matches at start but need to copy in trailing characters
|
||||
*/
|
||||
if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
addSpace = TRUE;
|
||||
}
|
||||
|
@ -1023,8 +1023,8 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
* by the right-hand-side.
|
||||
*/
|
||||
if (((cp - word) + pattern->rightLen) != 0) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
addSpace = TRUE;
|
||||
}
|
||||
|
@ -1059,7 +1059,7 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
cp = Str_FindSubstring(word, pattern->lhs);
|
||||
if (cp != (char *)NULL) {
|
||||
if (addSpace && (((cp - word) + pattern->rightLen) != 0)){
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
Buf_AddByte(buf, varSpace);
|
||||
addSpace = FALSE;
|
||||
}
|
||||
Buf_AddBytes(buf, cp-word, (const Byte *)word);
|
||||
|
@ -1079,8 +1079,8 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
}
|
||||
}
|
||||
if (wordLen != 0) {
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
Buf_AddBytes(buf, wordLen, (Byte *)word);
|
||||
}
|
||||
|
@ -1094,8 +1094,8 @@ VarSubstitute(GNode *ctx, char *word, Boolean addSpace, Buffer buf,
|
|||
return (addSpace);
|
||||
}
|
||||
nosub:
|
||||
if (addSpace) {
|
||||
Buf_AddByte(buf, (Byte)' ');
|
||||
if (addSpace && varSpace) {
|
||||
Buf_AddByte(buf, varSpace);
|
||||
}
|
||||
Buf_AddBytes(buf, wordLen, (Byte *)word);
|
||||
return(TRUE);
|
||||
|
@ -1703,6 +1703,8 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
dynamic = FALSE;
|
||||
start = str;
|
||||
|
||||
varSpace = ' '; /* reset this */
|
||||
|
||||
if (str[1] != '(' && str[1] != '{') {
|
||||
/*
|
||||
* If it's not bounded by braces of some sort, life is much simpler.
|
||||
|
@ -1968,6 +1970,10 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
* :u ("uniq") Remove adjacent duplicate words.
|
||||
* :tu Converts the variable contents to uppercase.
|
||||
* :tl Converts the variable contents to lowercase.
|
||||
* :ts[c] Sets varSpace - the char used to
|
||||
* separate words to 'c'. If 'c' is
|
||||
* omitted then no separation is used.
|
||||
*
|
||||
* :?<true-value>:<false-value>
|
||||
* If the variable evaluates to true, return
|
||||
* true value, else return the second value.
|
||||
|
@ -2025,6 +2031,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
if (DEBUG(VAR)) {
|
||||
printf("Applying :%c to \"%s\"\n", *tstr, nstr);
|
||||
}
|
||||
newStr = var_Error;
|
||||
switch (*tstr) {
|
||||
case ':':
|
||||
|
||||
|
@ -2245,14 +2252,69 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
}
|
||||
case 't':
|
||||
{
|
||||
cp = tstr + 1; /* make sure it is set */
|
||||
if (tstr[1] != endc && tstr[1] != ':') {
|
||||
if (tstr[2] == endc || tstr[2] == ':') {
|
||||
if (tstr[1] == 's') {
|
||||
/*
|
||||
* Use the char (if any) at tstr[2]
|
||||
* as the word separator.
|
||||
*/
|
||||
VarPattern pattern;
|
||||
|
||||
if (tstr[3] == endc || tstr[3] == ':') {
|
||||
varSpace = tstr[2];
|
||||
cp = tstr + 3;
|
||||
} else if (tstr[2] == endc || tstr[2] == ':') {
|
||||
varSpace = 0; /* no separator */
|
||||
cp = tstr + 2;
|
||||
} else if (tstr[2] == '\\') {
|
||||
switch (tstr[3]) {
|
||||
case 'n':
|
||||
varSpace = '\n';
|
||||
cp = tstr + 4;
|
||||
break;
|
||||
case 't':
|
||||
varSpace = '\t';
|
||||
cp = tstr + 4;
|
||||
break;
|
||||
default:
|
||||
if (isdigit(tstr[3])) {
|
||||
char *ep;
|
||||
|
||||
varSpace = strtoul(&tstr[3], &ep, 0);
|
||||
cp = ep;
|
||||
} else {
|
||||
goto bad_modifier;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
break; /* not us */
|
||||
|
||||
termc = *cp;
|
||||
|
||||
/*
|
||||
* We cannot be certain that VarModify
|
||||
* will be used - even if there is a
|
||||
* subsequent modifier, so do a no-op
|
||||
* VarSubstitute now to for str to be
|
||||
* re-expanded without the spaces.
|
||||
*/
|
||||
pattern.flags = VAR_SUB_ONE;
|
||||
pattern.lhs = pattern.rhs = "\032";
|
||||
pattern.leftLen = pattern.rightLen = 1;
|
||||
|
||||
newStr = VarModify(ctxt, str, VarSubstitute,
|
||||
(ClientData)&pattern);
|
||||
} else if (tstr[2] == endc || tstr[2] == ':') {
|
||||
if (tstr[1] == 'u' || tstr[1] == 'l') {
|
||||
newStr = VarChangeCase (nstr, (tstr[1] == 'u'));
|
||||
cp = tstr + 2;
|
||||
termc = *cp;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto bad_modifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2464,6 +2526,7 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
*lengthPtr = cp - start + 1;
|
||||
VarREError(error, &pattern.re, "RE substitution error");
|
||||
free(pattern.replace);
|
||||
varSpace = ' '; /* reset this */
|
||||
return (var_Error);
|
||||
}
|
||||
|
||||
|
@ -2706,9 +2769,15 @@ Var_Parse(const char *str, GNode *ctxt, Boolean err, int *lengthPtr,
|
|||
free((Address)v->name);
|
||||
free((Address)v);
|
||||
}
|
||||
varSpace = ' '; /* reset this */
|
||||
return (nstr);
|
||||
|
||||
bad_modifier:
|
||||
Error("Bad modifier `:%.*s' for %s", (int)strcspn(tstr, ":)}"), tstr,
|
||||
v->name);
|
||||
|
||||
cleanup:
|
||||
varSpace = ' '; /* reset this */
|
||||
*lengthPtr = cp - start + 1;
|
||||
if (*freePtr)
|
||||
free(nstr);
|
||||
|
|
Loading…
Reference in New Issue