]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * tclAssem.c -- | |
3 | * | |
4 | * This file contains procedures to help assemble Tcl commands | |
5 | * from an input source where commands may arrive in pieces, e.g. | |
6 | * several lines of type-in corresponding to one command. | |
7 | * | |
8 | * Copyright 1990-1991 Regents of the University of California | |
9 | * Permission to use, copy, modify, and distribute this | |
10 | * software and its documentation for any purpose and without | |
11 | * fee is hereby granted, provided that the above copyright | |
12 | * notice appear in all copies. The University of California | |
13 | * makes no representations about the suitability of this | |
14 | * software for any purpose. It is provided "as is" without | |
15 | * express or implied warranty. | |
16 | */ | |
17 | ||
18 | #ifndef lint | |
19 | static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclAssem.c,v 1.9 92/07/02 09:14:05 ouster Exp $ SPRITE (Berkeley)"; | |
20 | #endif /* not lint */ | |
21 | ||
22 | #include "tclint.h" | |
23 | ||
24 | /* | |
25 | * The structure below is the internal representation for a command | |
26 | * buffer, which is used to hold a piece of a command until a full | |
27 | * command is available. When a full command is available, it will | |
28 | * be returned to the user, but it will also be retained in the buffer | |
29 | * until the NEXT call to Tcl_AssembleCmd, at which point it will be | |
30 | * removed. | |
31 | */ | |
32 | ||
33 | typedef struct { | |
34 | char *buffer; /* Storage for command being assembled. | |
35 | * Malloc-ed, and grows as needed. */ | |
36 | int bufSize; /* Total number of bytes in buffer. */ | |
37 | int bytesUsed; /* Number of bytes in buffer currently | |
38 | * occupied (0 means there is not a | |
39 | * buffered incomplete command). */ | |
40 | } CmdBuf; | |
41 | ||
42 | /* | |
43 | * Default amount of space to allocate in command buffer: | |
44 | */ | |
45 | ||
46 | #define CMD_BUF_SIZE 100 | |
47 | \f | |
48 | /* | |
49 | *---------------------------------------------------------------------- | |
50 | * | |
51 | * Tcl_CreateCmdBuf -- | |
52 | * | |
53 | * Allocate and initialize a command buffer. | |
54 | * | |
55 | * Results: | |
56 | * The return value is a token that may be passed to | |
57 | * Tcl_AssembleCmd and Tcl_DeleteCmdBuf. | |
58 | * | |
59 | * Side effects: | |
60 | * Memory is allocated. | |
61 | * | |
62 | *---------------------------------------------------------------------- | |
63 | */ | |
64 | ||
65 | Tcl_CmdBuf | |
66 | Tcl_CreateCmdBuf() | |
67 | { | |
68 | register CmdBuf *cbPtr; | |
69 | ||
70 | cbPtr = (CmdBuf *) ckalloc(sizeof(CmdBuf)); | |
71 | cbPtr->buffer = (char *) ckalloc(CMD_BUF_SIZE); | |
72 | cbPtr->buffer[0] = '\0'; | |
73 | cbPtr->bufSize = CMD_BUF_SIZE; | |
74 | cbPtr->bytesUsed = 0; | |
75 | return (Tcl_CmdBuf) cbPtr; | |
76 | } | |
77 | \f | |
78 | /* | |
79 | *---------------------------------------------------------------------- | |
80 | * | |
81 | * Tcl_DeleteCmdBuf -- | |
82 | * | |
83 | * Release all of the resources associated with a command buffer. | |
84 | * The caller should never again use buffer again. | |
85 | * | |
86 | * Results: | |
87 | * None. | |
88 | * | |
89 | * Side effects: | |
90 | * Memory is released. | |
91 | * | |
92 | *---------------------------------------------------------------------- | |
93 | */ | |
94 | ||
95 | void | |
96 | Tcl_DeleteCmdBuf(buffer) | |
97 | Tcl_CmdBuf buffer; /* Token for command buffer (return value | |
98 | * from previous call to Tcl_CreateCmdBuf). */ | |
99 | { | |
100 | register CmdBuf *cbPtr = (CmdBuf *) buffer; | |
101 | ||
102 | ckfree(cbPtr->buffer); | |
103 | ckfree((char *) cbPtr); | |
104 | } | |
105 | \f | |
106 | /* | |
107 | *---------------------------------------------------------------------- | |
108 | * | |
109 | * Tcl_AssembleCmd -- | |
110 | * | |
111 | * This is a utility procedure to assist in situations where | |
112 | * commands may be read piece-meal from some input source. Given | |
113 | * some input text, it adds the text to an input buffer and returns | |
114 | * whole commands when they are ready. | |
115 | * | |
116 | * Results: | |
117 | * If the addition of string to any currently-buffered information | |
118 | * results in one or more complete Tcl commands, then the return value | |
119 | * is a pointer to the complete command(s). The command value will | |
120 | * only be valid until the next call to this procedure with the | |
121 | * same buffer. If the addition of string leaves an incomplete | |
122 | * command at the end of the buffer, then NULL is returned. | |
123 | * | |
124 | * Side effects: | |
125 | * If string leaves a command incomplete, the partial command | |
126 | * information is buffered for use in later calls to this procedure. | |
127 | * Once a command has been returned, that command is deleted from | |
128 | * the buffer on the next call to this procedure. | |
129 | * | |
130 | *---------------------------------------------------------------------- | |
131 | */ | |
132 | ||
133 | char * | |
134 | Tcl_AssembleCmd(buffer, string) | |
135 | Tcl_CmdBuf buffer; /* Token for a command buffer previously | |
136 | * created by Tcl_CreateCmdBuf. */ | |
137 | char *string; /* Bytes to be appended to command stream. | |
138 | * Note: if the string is zero length, | |
139 | * then whatever is buffered will be | |
140 | * considered to be a complete command | |
141 | * regardless of whether parentheses are | |
142 | * matched or not. */ | |
143 | { | |
144 | register CmdBuf *cbPtr = (CmdBuf *) buffer; | |
145 | int length, totalLength; | |
146 | register char *p; | |
147 | ||
148 | /* | |
149 | * If an empty string is passed in, just pretend the current | |
150 | * command is complete, whether it really is or not. | |
151 | */ | |
152 | ||
153 | length = strlen(string); | |
154 | if (length == 0) { | |
155 | cbPtr->bytesUsed = 0; | |
156 | return cbPtr->buffer; | |
157 | } | |
158 | ||
159 | /* | |
160 | * Add the new information to the buffer. If the current buffer | |
161 | * isn't large enough, grow it by at least a factor of two, or | |
162 | * enough to hold the new text. | |
163 | */ | |
164 | ||
165 | length = strlen(string); | |
166 | totalLength = cbPtr->bytesUsed + length + 1; | |
167 | if (totalLength > cbPtr->bufSize) { | |
168 | unsigned int newSize; | |
169 | char *newBuf; | |
170 | ||
171 | newSize = cbPtr->bufSize*2; | |
172 | if (newSize < totalLength) { | |
173 | newSize = totalLength; | |
174 | } | |
175 | newBuf = (char *) ckalloc(newSize); | |
176 | strcpy(newBuf, cbPtr->buffer); | |
177 | ckfree(cbPtr->buffer); | |
178 | cbPtr->buffer = newBuf; | |
179 | cbPtr->bufSize = newSize; | |
180 | } | |
181 | strcpy(cbPtr->buffer+cbPtr->bytesUsed, string); | |
182 | cbPtr->bytesUsed += length; | |
183 | ||
184 | /* | |
185 | * See if there is now a complete command in the buffer. | |
186 | */ | |
187 | ||
188 | p = cbPtr->buffer; | |
189 | while (1) { | |
190 | int gotNewLine = 0; | |
191 | ||
192 | while (isspace(*p)) { | |
193 | if (*p == '\n') { | |
194 | gotNewLine = 1; | |
195 | } | |
196 | p++; | |
197 | } | |
198 | if (*p == 0) { | |
199 | if (gotNewLine) { | |
200 | cbPtr->bytesUsed = 0; | |
201 | return cbPtr->buffer; | |
202 | } | |
203 | return NULL; | |
204 | } | |
205 | p = TclWordEnd(p, 0); | |
206 | } | |
207 | } |