summaryrefslogtreecommitdiff
path: root/Build/source/utils/xindy/rte/ordrules/rxsub.c
blob: 904b9613c72189278959c2634aa3735ce095fec5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* $Id: rxsub.c,v 1.4 2005/05/02 21:39:53 jschrod Exp $
 *------------------------------------------------------------

  This piece of code was inspired from the regsub implementation of
  Henry Spencer. I modified it to make it compatible with the GNU Rx
  library.

 */

#include "rxsub.h"

#include <string.h>

/*
  nrxsub - perform substitutions after a regexp match

  substpat  : a string consisting of ordinary characters and subexpression
              specifiers like `&' and `\0'..`\9'.
  pmatch[]  : the vector of subexpression specifiers into `source'
  source    : the string that was used in the regexec call yielding `pmatch'
  dest      : where to store the result
  nsize     : buffer length

  Returns one of the error codes.
 */

#define chkbuf( x )  if ( x ) return RXSUB_ESPACE;

rxsub_errcode_t
nrxsub  (char   *substpat,
	 regmatch_t pmatch[],
	 char   *source,
	 char   *dest,
	 size_t nsize)
{
  register char *sub;
  register char *dst;
  register char c;
  register int no;
  register size_t len;
  register char* bufend;

  if ( pmatch == NULL || source == NULL ||
       dest   == NULL || substpat == NULL ||
       nsize <= 0 ) {
    return RXSUB_INVAL;
  }

  sub = substpat;
  dst = dest;

  bufend = dst + nsize;    /* compute pointer to bufend */

  while ((c = *sub++) != '\0') {
    if (c == '&')
      no = 0;
    else if (c == '\\' && '0' <= *sub && *sub <= '9')
      no = *sub++ - '0';
    else
      no = -1;

    if (no < 0) {	/* Ordinary character. */
      if (c == '\\' && (*sub == '\\' || *sub == '&'))
	c = *sub++;
      chkbuf( dst >= bufend );
      *dst++ = c;
    } else { /* we found a subexpr specifier */
      if ( pmatch[no].rm_so >= 0 && pmatch[no].rm_eo >= 0 ) {
	len = pmatch[no].rm_eo - pmatch[no].rm_so;
	chkbuf(dst + len >= bufend);
	(void) strncpy( dst, source + pmatch[no].rm_so, len );
	dst += len;
	if (len != 0 && *(dst-1) == '\0') {   /* strncpy hit NULL */
	  return RXSUB_DAMAGE;
	}
      }
	  }
  }
  chkbuf( dst >= bufend );
  *dst++ = '\0';
  return RXSUB_NOERROR;
}


/*
  rxsub - perform substitutions after a regexp match

  substpat  : a string consisting of ordinary characters and subexpression
              specifiers like `&' and `\0'..`\9'.
  pmatch[]  : the vector of subexpression specifiers into `source'
  source    : the string that was used in the regexec call yielding `pmatch'
  dest      : pointer to a char*, which is used to store the pointer of the
              result string

  Returns one of the error codes.
 */

rxsub_errcode_t
rxsub   (char   *substpat,
	 regmatch_t pmatch[],
	 char   *source,
	 char   **dest)
{
  register size_t len;

  if ( pmatch == NULL || source == NULL ||
       dest   == NULL || substpat == NULL ) {
    return RXSUB_INVAL;
  }

  *dest = (char*)malloc( len = rxsub_len( substpat, pmatch ));

  return nrxsub( substpat, pmatch, source, *dest, len );
}



/*
  rxsub_len - calculate the neccessary space to hold the result of the
              rxsub-call.

  substpat  : a string consisting of ordinary characters and subexpression
              specifiers like `&' and `\0'..`\9'.
  pmatch[]  : the vector of subexpression specifiers into `source'

  Returns the length of the string neccessary to hold the substituted
  result with the final '\0' character included, or 0 of a fatal error occured.
  */

extern size_t
rxsub_len (char *substpat,
	   regmatch_t pmatch[])
{
  register char *sub;
  register char c;
  register int no;
  register size_t len;
  register size_t totlen = 0;

  if ( substpat == NULL || pmatch == NULL )
    return 0;

  sub = substpat;

  while ((c = *sub++) != '\0') {
    if (c == '&')
      no = 0;
    else if (c == '\\' && '0' <= *sub && *sub <= '9')
      no = *sub++ - '0';
    else
      no = -1;

    if (no < 0) {	/* Ordinary character. */
      if (c == '\\' && (*sub == '\\' || *sub == '&'))
	c = *sub++;
      totlen++;
    } else { /* we found a subexpr specifier */
      if ( pmatch[no].rm_so >= 0 && pmatch[no].rm_eo >= 0 ) {
	len = pmatch[no].rm_eo - pmatch[no].rm_so;
	totlen += len;
      }
    }
  }
  return ++totlen;
}

/*======================================================================

  $Log: rxsub.c,v $
  Revision 1.4  2005/05/02 21:39:53  jschrod
      xindy run time engine 3.0; as used for CLISP 2.33.2.

*/