about summary refs log tree commit diff
path: root/Src/glob.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/glob.c')
-rw-r--r--Src/glob.c167
1 files changed, 110 insertions, 57 deletions
diff --git a/Src/glob.c b/Src/glob.c
index e81fd1e97..3c19bf0f7 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2050,12 +2050,6 @@ matchpat(char *a, char *b)
 /* do the ${foo%%bar}, ${foo#bar} stuff */
 /* please do not laugh at this code. */
 
-struct repldata {
-    int b, e;			/* beginning and end of chunk to replace */
-    char *replstr;		/* replacement string to use */
-};
-typedef struct repldata *Repldata;
-
 /* Having found a match in getmatch, decide what part of string
  * to return.  The matched part starts b characters into string s
  * and finishes e characters in: 0 <= b <= e <= strlen(s)
@@ -2073,19 +2067,23 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr,
     char buf[80], *r, *p, *rr;
     int ll = 0, l = strlen(s), bl = 0, t = 0, i;
 
-    if (replstr) {
+    if (replstr || (fl & SUB_LIST)) {
 	if (fl & SUB_DOSUBST) {
 	    replstr = dupstring(replstr);
 	    singsub(&replstr);
 	    untokenize(replstr);
 	}
-	if ((fl & SUB_GLOBAL) && repllist) {
+	if ((fl & (SUB_GLOBAL|SUB_LIST)) && repllist) {
 	    /* We are replacing the chunk, just add this to the list */
-	    Repldata rd = (Repldata) zhalloc(sizeof(*rd));
+	    Repldata rd = (Repldata)
+		((fl & SUB_LIST) ? zalloc(sizeof(*rd)) : zhalloc(sizeof(*rd)));
 	    rd->b = b;
 	    rd->e = e;
 	    rd->replstr = replstr;
-	    addlinknode(repllist, rd);
+	    if (fl & SUB_LIST)
+		zaddlinknode(repllist, rd);
+	    else
+		addlinknode(repllist, rd);
 	    return s;
 	}
 	ll += strlen(replstr);
@@ -2214,9 +2212,14 @@ getmatch(char **sp, char *pat, int fl, int n, char *replstr)
     if (!(p = compgetmatch(pat, &fl, &replstr)))
 	return 1;
 
-    return igetmatch(sp, p, fl, n, replstr);
+    return igetmatch(sp, p, fl, n, replstr, NULL);
 }
 
+/*
+ * This is the corresponding function for array variables.
+ * Matching is done with the same pattern on each element.
+ */
+
 /**/
 void
 getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
@@ -2229,10 +2232,47 @@ getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
 
     *ap = pp = hcalloc(sizeof(char *) * (arrlen(arr) + 1));
     while ((*pp = *arr++))
-	if (igetmatch(pp, p, fl, n, replstr))
+	if (igetmatch(pp, p, fl, n, replstr, NULL))
 	    pp++;
 }
 
+/*
+ * Match against str using pattern pp; return a list of
+ * Repldata matches in the linked list *replistp; this is
+ * in permanent storage and to be freed by freematchlist()
+ */
+
+/**/
+mod_export int
+getmatchlist(char *str, Patprog p, LinkList *repllistp)
+{
+    char **sp = &str;
+
+    /*
+     * We don't care if we have longest or shortest match, but SUB_LONG
+     * is cheaper since the pattern code does that by default.
+     * We need SUB_GLOBAL to get all matches.
+     * We need SUB_SUBSTR to scan through for substrings.
+     * We need SUB_LIST to activate the special handling of the list
+     * passed in.
+     */
+    return igetmatch(sp, p, SUB_LONG|SUB_GLOBAL|SUB_SUBSTR|SUB_LIST,
+		     0, NULL, repllistp);
+}
+
+static void
+freerepldata(void *ptr)
+{
+    zfree(ptr, sizeof(struct repldata));
+}
+
+/**/
+mod_export void
+freematchlist(LinkList repllist)
+{
+    freelinklist(repllist, freerepldata);
+}
+
 /**/
 static void
 set_pat_start(Patprog p, int offs)
@@ -2295,7 +2335,8 @@ static int iincchar(char **tp)
 
 /**/
 static int
-igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
+igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
+	  LinkList *repllistp)
 {
     char *s = *sp, *t, *tmatch;
     /*
@@ -2341,7 +2382,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 
     if (fl & SUB_ALL) {
 	int i = matched && pattry(p, s);
-	*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, repllist);
+	*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, NULL);
 	if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
 	    return 0;
 	return 1;
@@ -2387,7 +2428,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 			umlen += iincchar(&t);
 		    }
 		}
-		*sp = get_match_ret(*sp, 0, mlen, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, 0, mlen, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;
@@ -2414,11 +2455,11 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 		umlen -= iincchar(&t);
 	    }
 	    if (tmatch) {
-		*sp = get_match_ret(*sp, tmatch - s, l, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, tmatch - s, l, fl, replstr, NULL);
 		return 1;
 	    }
 	    if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) {
-		*sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;
@@ -2431,7 +2472,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	    for (ioff = 0, t = s, umlen = umltot; t < s + l; ioff++) {
 		set_pat_start(p, t-s);
 		if (pattrylen(p, t, s + l - t, umlen, ioff)) {
-		    *sp = get_match_ret(*sp, t-s, l, fl, replstr, repllist);
+		    *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL);
 		    return 1;
 		}
 		if (fl & SUB_START)
@@ -2439,7 +2480,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 		umlen -= iincchar(&t);
 	    }
 	    if (!(fl & SUB_START) && pattrylen(p, s + l, 0, 0, ioff)) {
-		*sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;
@@ -2448,14 +2489,17 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	    /* Smallest at start, but matching substrings. */
 	    set_pat_start(p, l);
 	    if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) {
-		*sp = get_match_ret(*sp, 0, 0, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, 0, 0, fl, replstr, NULL);
 		return 1;
 	    } /* fall through */
 	case (SUB_SUBSTR|SUB_LONG):
 	    /* longest or smallest at start with substrings */
 	    t = s;
-	    if (fl & SUB_GLOBAL)
-		repllist = newlinklist();
+	    if (fl & SUB_GLOBAL) {
+		repllist = (fl & SUB_LIST) ? znewlinklist() : newlinklist();
+		if (repllistp)
+		     *repllistp = repllist;
+	    }
 	    ioff = 0;		/* offset into string */
 	    umlen = umltot;
 	    mb_metacharinit();
@@ -2539,7 +2583,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	    if (!(fl & SUB_LONG)) {
 		set_pat_start(p, l);
 		if (pattrylen(p, s + l, 0, 0, umltot) && !--n) {
-		    *sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		    *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		    return 1;
 		}
 	    }
@@ -2595,12 +2639,12 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 		    }
 		}
 		*sp = get_match_ret(*sp, tmatch-s, mpos-s, fl,
-				    replstr, repllist);
+				    replstr, NULL);
 		return 1;
 	    }
 	    set_pat_start(p, l);
 	    if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, umltot) && !--n) {
-		*sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;
@@ -2611,34 +2655,39 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	/* Put all the bits of a global search and replace together. */
 	LinkNode nd;
 	Repldata rd;
-	int lleft = 0;		/* size of returned string */
+	int lleft;
 	char *ptr, *start;
 	int i;
 
-	i = 0;			/* start of last chunk we got from *sp */
-	for (nd = firstnode(repllist); nd; incnode(nd)) {
-	    rd = (Repldata) getdata(nd);
-	    lleft += rd->b - i; /* previous chunk of *sp */
-	    lleft += strlen(rd->replstr);	/* the replaced bit */
-	    i = rd->e;		/* start of next chunk of *sp */
-	}
-	lleft += l - i;	/* final chunk from *sp */
-	start = t = zhalloc(lleft+1);
-	i = 0;
-	for (nd = firstnode(repllist); nd; incnode(nd)) {
-	    rd = (Repldata) getdata(nd);
-	    memcpy(t, s + i, rd->b - i);
-	    t += rd->b - i;
-	    ptr = rd->replstr;
-	    while (*ptr)
-		*t++ = *ptr++;
-	    i = rd->e;
+	if (!(fl & SUB_LIST)) {
+	    lleft = 0;		/* size of returned string */
+	    i = 0;			/* start of last chunk we got from *sp */
+	    for (nd = firstnode(repllist); nd; incnode(nd)) {
+		rd = (Repldata) getdata(nd);
+		lleft += rd->b - i; /* previous chunk of *sp */
+		lleft += strlen(rd->replstr);	/* the replaced bit */
+		i = rd->e;		/* start of next chunk of *sp */
+	    }
+	    lleft += l - i;	/* final chunk from *sp */
+	    start = t = zhalloc(lleft+1);
+	    i = 0;
+	    for (nd = firstnode(repllist); nd; incnode(nd)) {
+		rd = (Repldata) getdata(nd);
+		memcpy(t, s + i, rd->b - i);
+		t += rd->b - i;
+		ptr = rd->replstr;
+		while (*ptr)
+		    *t++ = *ptr++;
+		i = rd->e;
+	    }
+	    memcpy(t, s + i, l - i);
+	    start[lleft] = '\0';
+	    *sp = (char *)start;
 	}
-	memcpy(t, s + i, l - i);
-	start[lleft] = '\0';
-	*sp = (char *)start;
 	return 1;
     }
+    if (fl & SUB_LIST)		/* safety: don't think this can happen */
+	return 0;
 
     /* munge the whole string: no match, so no replstr */
     *sp = get_match_ret(*sp, 0, 0, fl, 0, 0);
@@ -2656,7 +2705,8 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 
 /**/
 static int
-igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
+igetmatch(char **sp, Patprog p, int fl, int n, char *replstr,
+	  LinkList *replistp)
 {
     char *s = *sp, *t;
     /*
@@ -2695,7 +2745,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 
     if (fl & SUB_ALL) {
 	int i = matched && pattry(p, s);
-	*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, repllist);
+	*sp = get_match_ret(*sp, 0, i ? l : 0, fl, i ? replstr : 0, NULL);
 	if (! **sp && (((fl & SUB_MATCH) && !i) || ((fl & SUB_REST) && i)))
 	    return 0;
 	return 1;
@@ -2724,7 +2774,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 			}
 		    }
 		}
-		*sp = get_match_ret(*sp, 0, mlen, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, 0, mlen, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;
@@ -2739,7 +2789,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 		    t--;
 		set_pat_start(p, t-s);
 		if (pattrylen(p, t, s + l - t, umlen, ioff)) {
-		    *sp = get_match_ret(*sp, t - s, l, fl, replstr, repllist);
+		    *sp = get_match_ret(*sp, t - s, l, fl, replstr, NULL);
 		    return 1;
 		}
 		if (t > s+1 && t[-2] == Meta)
@@ -2755,7 +2805,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 		 ioff++, METAINC(t), umlen--) {
 		set_pat_start(p, t-s);
 		if (pattrylen(p, t, s + l - t, umlen, ioff)) {
-		    *sp = get_match_ret(*sp, t-s, l, fl, replstr, repllist);
+		    *sp = get_match_ret(*sp, t-s, l, fl, replstr, NULL);
 		    return 1;
 		}
 		if (*t == Meta)
@@ -2767,14 +2817,17 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	    /* Smallest at start, but matching substrings. */
 	    set_pat_start(p, l);
 	    if (!(fl & SUB_GLOBAL) && pattry(p, s + l) && !--n) {
-		*sp = get_match_ret(*sp, 0, 0, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, 0, 0, fl, replstr, NULL);
 		return 1;
 	    } /* fall through */
 	case (SUB_SUBSTR|SUB_LONG):
 	    /* longest or smallest at start with substrings */
 	    t = s;
-	    if (fl & SUB_GLOBAL)
+	    if (fl & SUB_GLOBAL) {
 		repllist = newlinklist();
+		if (repllistp)
+		    *repllistp = repllist;
+	    }
 	    ioff = 0;		/* offset into string */
 	    umlen = uml;
 	    do {
@@ -2849,7 +2902,7 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 	    if (!(fl & SUB_LONG)) {
 		set_pat_start(p, l);
 		if (pattrylen(p, s + l, 0, 0, uml) && !--n) {
-		    *sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		    *sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		    return 1;
 		}
 	    }
@@ -2874,13 +2927,13 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
 			}
 		    }
 		    *sp = get_match_ret(*sp, t-s, mpos-s, fl,
-					replstr, repllist);
+					replstr, NULL);
 		    return 1;
 		}
 	    }
 	    set_pat_start(p, l);
 	    if ((fl & SUB_LONG) && pattrylen(p, s + l, 0, 0, uml) && !--n) {
-		*sp = get_match_ret(*sp, l, l, fl, replstr, repllist);
+		*sp = get_match_ret(*sp, l, l, fl, replstr, NULL);
 		return 1;
 	    }
 	    break;