1 /*****************************************************************************
2 
3 	BldStr()
4 
5 	This function "builds" a string.  This means converting string
6 build constructs in the input string into their intended equivalents
7 in the output string.  The string build constructs are as follows:
8 
9 	^Q	use next character literally,  not as a string build char
10 	^R	use next character literally,  not as a string build char
11 	^V	lowercase the next character
12 	^V^V	lowercase all following characters
13 	^W	uppercase the next character
14 	^W^W	uppercase all following characters
15 	^EQq	use string in q-register q here
16 	^EUq	use ASCII char for number in q-register q here
17 
18 	When this function is called,  CBfPtr points to the first character
19 of the input string.  It is assumed that the string is terminated by an ESCAPE
20 character (or something else if the calling command was @-modified).  If the
21 string is not properly terminated this function will die with "unterminated
22 command" when it encounters CStEnd while looking for the terminator character.
23 
24 	When this function returns,  CBfPtr points to the ESCAPE which
25 terminates the string, the built string is in the buffer pointed to by
26 XBfBeg,  and XBfPtr points to the character after the last character in
27 the built string.
28 
29 	The commands which contain a filename (EB, EI, EN, ER and
30 EW) use this function.  The EG command, which exits with an operating system
31 command line, uses this function.  The O command, which jumps to a tag, uses
32 this function.  The search commands (E_, FK, FN, FS, F_, N, S and _) use this
33 function.
34 
35 *****************************************************************************/
36 
37 #include "zport.h"		/* define portability identifiers */
38 #include "tecoc.h"		/* define general identifiers */
39 #include "defext.h"		/* define external global variables */
40 #include "deferr.h"		/* define identifiers for error messages */
41 #include "dchars.h"		/* define identifiers for characters */
42 #include "chmacs.h"		/* define character processing macros */
43 
44 #if USE_PROTOTYPES
45 static DEFAULT DoCtVW(charptr EndArg, unsigned char TmpChr);
46 static DEFAULT DoCtE(charptr EndArg, charptr XBfEnd);
47 #endif
48 
49 static charptr BBfPtr;			/* pointer into XBf */
50 static int CaseCv;			/* case conversion */
51 static unsigned char WVFlag;		/* ^W or ^V flag */
52 
DoCtVW(EndArg,TmpChr)53 static DEFAULT DoCtVW(EndArg, TmpChr)	/* do a control-V or control-W */
54 charptr EndArg;				/* ptr to end of string argument */
55 unsigned char TmpChr;			/* temporary character */
56 {
57     DBGFEN(3,"DoCtVW",NULL);
58 
59     WVFlag = TmpChr;
60     if (++CBfPtr == EndArg) {		/* move past ^W or ^V,  too far? */
61 	ErrMsg(ERR_ISS);		/* yes, illegal search string */
62 	DBGFEX(2,DbgFNm,"FAILURE");
63 	return FAILURE;
64     }
65     if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0)) {
66 	if (++CBfPtr == EndArg) {
67 	    ErrMsg(ERR_ISS);
68 	    DBGFEX(2,DbgFNm,"FAILURE");
69 	    return FAILURE;
70 	}
71 	TmpChr = To_Upper(*CBfPtr);
72 	if ((TmpChr < '@') || (TmpChr > '_')) {
73 	    ErrChr(ERR_IUC, *CBfPtr);
74 	    DBGFEX(2,DbgFNm,"FAILURE");
75 	    return FAILURE;
76 	}
77 	TmpChr &= '\077';
78     } else {
79 	TmpChr = *CBfPtr;
80     }
81     if (WVFlag == CTRL_V) {
82 	if (TmpChr == CTRL_V) {
83 	    CaseCv = LOWER;
84 	} else {
85 	    *BBfPtr++ = To_Lower(TmpChr);
86 	}
87     } else {
88 	if (TmpChr == CTRL_W) {
89 	    CaseCv = UPPER;
90 	} else {
91 	    *BBfPtr++ = To_Upper(TmpChr);
92 	}
93     }
94     WVFlag = '\0';
95     DBGFEX(2,DbgFNm,"SUCCESS");
96     return SUCCESS;
97 }
98 
99 
DoCtE(EndArg,XBfEnd)100 static DEFAULT DoCtE(EndArg, XBfEnd)	/* do a control-E */
101 charptr EndArg;				/* ptr to end of string argument */
102 charptr XBfEnd;				/* end of build-string buffer */
103 {
104     DEFAULT	Status;			/* returned from FindQR */
105     charptr	TCStEn;			/* temporary holder of CStEnd */
106 
107     DBGFEN(3,"DoCtE",NULL);
108     if (++CBfPtr == EndArg) {		/* move past ^E,  too far? */
109 	ErrMsg(ERR_ICE);		/* yes, illegal ^E command */
110 	DBGFEX(2,DbgFNm,"FAILURE");
111 	return FAILURE;
112     }
113     if ((*CBfPtr == 'Q') || (*CBfPtr == 'q')) {
114 	if (++CBfPtr == EndArg) {
115 	    ErrMsg(ERR_ISS);
116 	    DBGFEX(2,DbgFNm,"FAILURE");
117 	    return FAILURE;
118 	}
119 
120 /*
121  * handle filespec buffer and search string buffer
122  */
123 	if (*CBfPtr=='*' || *CBfPtr=='_') {
124 	    charptr  BufPtr, BufBeg;
125 	    if (*CBfPtr=='*') {
126 		BufPtr=FBfPtr;
127 		BufBeg=FBfBeg;
128 	    } else {
129 		BufPtr=SBfPtr;
130 		BufBeg=SBfBeg;
131 	    }
132 	    if ((BufPtr-BufBeg) > (XBfEnd-BBfPtr)) {
133 		ErrMsg(ERR_STL);
134 		DBGFEX(2,DbgFNm,"FAILURE");
135 		return FAILURE;
136 	    }
137 	    MEMMOVE(BBfPtr, BufBeg, (SIZE_T)(BufPtr - BufBeg));
138 	    BBfPtr += BufPtr-BufBeg;
139 	} else {
140 /*
141  * it really must be a Q reg reference after all
142  */
143 	    TCStEn = CStEnd;			/* save CStEnd */
144 	    CStEnd = EndArg;
145 	    Status = FindQR();
146 	    CStEnd = TCStEn;			/* restore CStEnd */
147 	    if (Status == FAILURE) {
148 		DBGFEX(2,DbgFNm,"FAILURE");
149 		return FAILURE;
150 	    }
151 	    if ((QR->End_P1-QR->Start) > (XBfEnd-BBfPtr)) {
152 		ErrMsg(ERR_STL);
153 		DBGFEX(2,DbgFNm,"FAILURE");
154 		return FAILURE;
155 	    }
156 	    MEMMOVE(BBfPtr, QR->Start, (SIZE_T)(QR->End_P1 - QR->Start));
157 	    BBfPtr += QR->End_P1 - QR->Start;
158 	}
159     } else if ((*CBfPtr == 'U') || (*CBfPtr == 'u')) {
160 	if (++CBfPtr == EndArg) {
161 	    ErrMsg(ERR_ISS);
162 	    DBGFEX(2,DbgFNm,"FAILURE");
163 	    return FAILURE;
164 	}
165 	TCStEn = CStEnd;			/* save CStEnd */
166 	CStEnd = EndArg;
167 	Status = FindQR();
168 	CStEnd = TCStEn;			/* restore CStEnd */
169 	if (Status == FAILURE) {
170 	    DBGFEX(2,DbgFNm,"FAILURE");
171 	    return FAILURE;
172 	}
173 	*BBfPtr++ = (char)QR->Number;
174     } else {
175 	*BBfPtr++ = CTRL_E;
176 	*BBfPtr++ = *CBfPtr;
177     }
178     DBGFEX(2,DbgFNm,"SUCCESS");
179     return SUCCESS;
180 }
181 
182 
BldStr(XBfBeg,XBfEnd,XBfPtr)183 DEFAULT BldStr(XBfBeg, XBfEnd, XBfPtr)		/* build a string */
184 charptr XBfBeg;			/* beginning of build-string buffer */
185 charptr XBfEnd;			/* end of build-string buffer */
186 charptr (*XBfPtr);		/* pointer into build-string buffer */
187 {
188     charptr	EndArg;		/* end of input string, plus 1 */
189     unsigned char TmpChr;	/* temporary character */
190 
191     DBGFEN(2,"BldStr",NULL);
192 
193     if (FindES(ESCAPE) == FAILURE) {	/* move CBfPtr to end of argument */
194 	DBGFEX(2,DbgFNm,"FAILURE, FindES(ESCAPE) failed");
195 	return FAILURE;
196     }
197 
198     WVFlag = '\0';		/* initialize ^W and ^V flag */
199     CaseCv = IniSrM;		/* initialize internal search mode */
200     BBfPtr = XBfBeg;		/* initialize ptr into build-string buffer */
201     EndArg = CBfPtr;		/* save pointer to end of argument */
202     CBfPtr = ArgPtr;		/* reset to beginning of argument */
203 
204     while (CBfPtr < EndArg) {
205 	if ((*CBfPtr == '^') && ((EdFlag & ED_CARET_OK) == 0)) {
206 	    if (++CBfPtr == EndArg) {
207 		ErrMsg(ERR_ISS);
208 		DBGFEX(2,DbgFNm,"FAILURE, no char after ^");
209 		return FAILURE;
210 	    }
211 	    TmpChr = To_Upper(*CBfPtr);
212 	    if ((TmpChr < '@') || (TmpChr > '_')) {
213 		ErrChr(ERR_IUC, *CBfPtr);
214 		DBGFEX(2,DbgFNm,"FAILURE, bad char after ^");
215 		return FAILURE;
216 	    }
217 	    TmpChr &= '\077';
218 	} else {
219 	    TmpChr = *CBfPtr;
220 	}
221 
222 	switch (TmpChr) {
223 
224 	    case CTRL_R:
225 	    case CTRL_Q:
226 		if (++CBfPtr == EndArg) {
227 		    ErrMsg(ERR_ISS);
228 		    DBGFEX(2,DbgFNm,"FAILURE");
229 		    return FAILURE;
230 		}
231 		*BBfPtr++ = *CBfPtr;
232 		break;
233 
234 	    case CTRL_V:
235 	    case CTRL_W:
236 		if (DoCtVW(EndArg, TmpChr) == FAILURE) {
237 		    DBGFEX(2,DbgFNm,"FAILURE, DoCtVW failed");
238 		    return FAILURE;
239 		}
240 		break;
241 
242 	    case CTRL_E:
243 		if (DoCtE(EndArg, XBfEnd) == FAILURE) {
244 		    DBGFEX(2,DbgFNm,"FAILURE, DoCtE failed");
245 		    return FAILURE;
246 		}
247 		break;
248 
249 	    default:
250 		if (CaseCv == LOWER) {
251 		    TmpChr = To_Lower(TmpChr);
252 		} else if (CaseCv == UPPER) {
253 		    TmpChr = To_Upper(TmpChr);
254 		}
255 		*BBfPtr++ = TmpChr;
256 	}
257 	if (BBfPtr > XBfEnd) {
258 	    ErrMsg(ERR_STL);	/* string too long */
259 	    DBGFEX(2,DbgFNm,"FAILURE, string too long");
260 	    return FAILURE;
261 	}
262 	++CBfPtr;
263     }
264     *XBfPtr = BBfPtr;
265 
266 #if DEBUGGING
267     sprintf(DbgSBf,"string = \"%.*s\"", (int)(BBfPtr-XBfBeg), XBfBeg);
268     DbgFEx(2,DbgFNm,DbgSBf);
269 #endif
270 
271     return SUCCESS;
272 }
273