5 * Id: cook.c,v 4.10 2007/02/04 17:44:12 bkorb Exp
6 * Time-stamp: "2006-09-24 15:21:02 bkorb"
8 * This file contains the routines that deal with processing quoted strings
9 * into an internal format.
13 * Automated Options copyright 1992-2007 Bruce Korb
15 * Automated Options is free software.
16 * You may redistribute it and/or modify it under the terms of the
17 * GNU General Public License, as published by the Free Software
18 * Foundation; either version 2, or (at your option) any later version.
20 * Automated Options is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Automated Options. See the file "COPYING". If not,
27 * write to: The Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor,
29 * Boston, MA 02110-1301, USA.
31 * As a special exception, Bruce Korb gives permission for additional
32 * uses of the text contained in his release of AutoOpts.
34 * The exception is that, if you link the AutoOpts library with other
35 * files to produce an executable, this does not by itself cause the
36 * resulting executable to be covered by the GNU General Public License.
37 * Your use of that executable is in no way restricted on account of
38 * linking the AutoOpts library code into it.
40 * This exception does not however invalidate any other reasons why
41 * the executable file might be covered by the GNU General Public License.
43 * This exception applies only to the code released by Bruce Korb under
44 * the name AutoOpts. If you copy code from other sources under the
45 * General Public License into a copy of AutoOpts, as the General Public
46 * License permits, the exception does not apply to the code that you add
47 * in this way. To avoid misleading anyone as to the status of such
48 * modified files, you must delete this exception notice from them.
50 * If you write modifications of your own for AutoOpts, it is your choice
51 * whether to permit this exception to apply to your modifications.
52 * If you do not wish that, delete this exception notice.
55 /* = = = START-STATIC-FORWARD = = = */
56 /* static forward declarations maintained by :mkfwd */
57 /* = = = END-STATIC-FORWARD = = = */
59 /*=export_func ao_string_cook_escape_char
62 * what: escape-process a string fragment
63 * arg: + char const* + pzScan + points to character after the escape +
64 * arg: + char* + pRes + Where to put the result byte +
65 * arg: + unsigned int + nl_ch + replacement char if scanned char is \n +
67 * ret-type: unsigned int
68 * ret-desc: The number of bytes consumed processing the escaped character.
72 * This function converts "t" into "\t" and all your other favorite
73 * escapes, including numeric ones: hex and ocatal, too.
74 * The returned result tells the caller how far to advance the
75 * scan pointer (passed in). The default is to just pass through the
76 * escaped character and advance the scan by one.
78 * Some applications need to keep an escaped newline, others need to
79 * suppress it. This is accomplished by supplying a '\n' replacement
80 * character that is different from \n, if need be. For example, use
81 * 0x7F and never emit a 0x7F.
83 * err: @code{NULL} is returned if the string is mal-formed.
86 ao_string_cook_escape_char( char const* pzIn
, char* pRes
, u_int nl
)
90 switch (*pRes
= *pzIn
++) {
91 case NUL
: /* NUL - end of input string */
98 case '\n': /* NL - emit newline */
102 case 'a': *pRes
= '\a'; break;
103 case 'b': *pRes
= '\b'; break;
104 case 'f': *pRes
= '\f'; break;
105 case 'n': *pRes
= '\n'; break;
106 case 'r': *pRes
= '\r'; break;
107 case 't': *pRes
= '\t'; break;
108 case 'v': *pRes
= '\v'; break;
110 case 'x': /* HEX Escape */
111 if (isxdigit( (int)*pzIn
)) {
113 unsigned char ch
= *pzIn
++;
115 if ((ch
>= 'A') && (ch
<= 'F'))
116 val
= 10 + (ch
- 'A');
117 else if ((ch
>= 'a') && (ch
<= 'f'))
118 val
= 10 + (ch
- 'a');
123 if (! isxdigit( ch
)) {
129 if ((ch
>= 'A') && (ch
<= 'F'))
130 val
+= 10 + (ch
- 'A');
131 else if ((ch
>= 'a') && (ch
<= 'f'))
132 val
+= 10 + (ch
- 'a');
133 else val
+= ch
- '0';
142 * IF the character copied was an octal digit,
143 * THEN set the output character to an octal value
145 if (isdigit( (int)*pRes
) && (*pRes
< '8')) {
146 unsigned int val
= *pRes
- '0';
147 unsigned char ch
= *pzIn
++;
150 * IF the second character is *not* an octal digit,
151 * THEN save the value and bail
153 if ((ch
< '0') || (ch
> '7')) {
158 val
= (val
<<3) + (ch
- '0');
163 * IF the THIRD character is *not* an octal digit,
164 * THEN save the value and bail
166 if ((ch
< '0') || (ch
> '7')) {
172 * IF the new value would not be too large,
173 * THEN add on the third and last character value
175 if ((val
<<3) < 0xFF) {
176 val
= (val
<<3) + (ch
- '0');
189 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
191 * A quoted string has been found.
192 * Find the end of it and compress any escape sequences.
194 /*=export_func ao_string_cook
197 * what: concatenate and escape-process strings
198 * arg: + char* + pzScan + The *MODIFIABLE* input buffer +
199 * arg: + int* + pLineCt + The (possibly NULL) pointer to a line count +
202 * ret-desc: The address of the text following the processed strings.
203 * The return value is NULL if the strings are ill-formed.
207 * A series of one or more quoted strings are concatenated together.
208 * If they are quoted with double quotes (@code{"}), then backslash
209 * escapes are processed per the C programming language. If they are
210 * single quote strings, then the backslashes are honored only when they
211 * precede another backslash or a single quote character.
213 * err: @code{NULL} is returned if the string(s) is/are mal-formed.
216 ao_string_cook( char* pzScan
, int* pLineCt
)
222 * It is a quoted string. Process the escape sequence characters
223 * (in the set "abfnrtv") and make sure we find a closing quote.
225 char* pzD
= pzScan
++;
233 * IF the next character is the quote character, THEN we may end the
234 * string. We end it unless the next non-blank character *after* the
235 * string happens to also be a quote. If it is, then we will change
236 * our quote character to the new quote character and continue
240 *pzD
= NUL
; /* This is probably the end of the line */
244 while (isspace((int)*pzS
))
245 if (*(pzS
++) == '\n')
249 * IF the next character is a quote character,
250 * THEN we will concatenate the strings.
259 * Allow for a comment embedded in the concatenated string.
262 default: return NULL
;
265 * Skip to end of line
267 pzS
= strchr( pzS
, '\n' );
275 char* p
= strstr( pzS
+2, "*/" );
277 * Skip to terminating star slash
282 if (*(pzS
++) == '\n')
293 * The next non-whitespace character is not a quote.
294 * The series of quoted strings has come to an end.
299 q
= *(pzS
++); /* assign new quote character and advance scan */
303 * We are inside a quoted string. Copy text.
305 switch (*(pzD
++) = *(pzS
++)) {
315 * IF we are escaping a new line,
316 * THEN drop both the escape and the newline from
326 * ELSE IF the quote character is '"' or '`',
327 * THEN we do the full escape character processing
329 else if (q
!= '\'') {
330 int ct
= ao_string_cook_escape_char( pzS
, pzD
-1, (u_int
)'\n' );
335 } /* if (q != '\'') */
338 * OTHERWISE, we only process "\\", "\'" and "\#" sequences.
339 * The latter only to easily hide preprocessing directives.
347 } /* switch (*(pzD++) = *(pzS++)) */
353 * c-file-style: "stroustrup"
354 * indent-tabs-mode: nil
356 * end of autoopts/cook.c */