xref: /freebsd/stand/ficl/vm.c (revision 2a63c3be158216222d89a073dcbd6a72ee4aab5a)
1*ca987d46SWarner Losh /*******************************************************************
2*ca987d46SWarner Losh ** v m . c
3*ca987d46SWarner Losh ** Forth Inspired Command Language - virtual machine methods
4*ca987d46SWarner Losh ** Author: John Sadler (john_sadler@alum.mit.edu)
5*ca987d46SWarner Losh ** Created: 19 July 1997
6*ca987d46SWarner Losh ** $Id: vm.c,v 1.13 2001/12/05 07:21:34 jsadler Exp $
7*ca987d46SWarner Losh *******************************************************************/
8*ca987d46SWarner Losh /*
9*ca987d46SWarner Losh ** This file implements the virtual machine of FICL. Each virtual
10*ca987d46SWarner Losh ** machine retains the state of an interpreter. A virtual machine
11*ca987d46SWarner Losh ** owns a pair of stacks for parameters and return addresses, as
12*ca987d46SWarner Losh ** well as a pile of state variables and the two dedicated registers
13*ca987d46SWarner Losh ** of the interp.
14*ca987d46SWarner Losh */
15*ca987d46SWarner Losh /*
16*ca987d46SWarner Losh ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
17*ca987d46SWarner Losh ** All rights reserved.
18*ca987d46SWarner Losh **
19*ca987d46SWarner Losh ** Get the latest Ficl release at http://ficl.sourceforge.net
20*ca987d46SWarner Losh **
21*ca987d46SWarner Losh ** I am interested in hearing from anyone who uses ficl. If you have
22*ca987d46SWarner Losh ** a problem, a success story, a defect, an enhancement request, or
23*ca987d46SWarner Losh ** if you would like to contribute to the ficl release, please
24*ca987d46SWarner Losh ** contact me by email at the address above.
25*ca987d46SWarner Losh **
26*ca987d46SWarner Losh ** L I C E N S E  and  D I S C L A I M E R
27*ca987d46SWarner Losh **
28*ca987d46SWarner Losh ** Redistribution and use in source and binary forms, with or without
29*ca987d46SWarner Losh ** modification, are permitted provided that the following conditions
30*ca987d46SWarner Losh ** are met:
31*ca987d46SWarner Losh ** 1. Redistributions of source code must retain the above copyright
32*ca987d46SWarner Losh **    notice, this list of conditions and the following disclaimer.
33*ca987d46SWarner Losh ** 2. Redistributions in binary form must reproduce the above copyright
34*ca987d46SWarner Losh **    notice, this list of conditions and the following disclaimer in the
35*ca987d46SWarner Losh **    documentation and/or other materials provided with the distribution.
36*ca987d46SWarner Losh **
37*ca987d46SWarner Losh ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38*ca987d46SWarner Losh ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39*ca987d46SWarner Losh ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40*ca987d46SWarner Losh ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41*ca987d46SWarner Losh ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42*ca987d46SWarner Losh ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43*ca987d46SWarner Losh ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44*ca987d46SWarner Losh ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45*ca987d46SWarner Losh ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46*ca987d46SWarner Losh ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47*ca987d46SWarner Losh ** SUCH DAMAGE.
48*ca987d46SWarner Losh */
49*ca987d46SWarner Losh 
50*ca987d46SWarner Losh 
51*ca987d46SWarner Losh #ifdef TESTMAIN
52*ca987d46SWarner Losh #include <stdlib.h>
53*ca987d46SWarner Losh #include <stdio.h>
54*ca987d46SWarner Losh #include <ctype.h>
55*ca987d46SWarner Losh #else
56*ca987d46SWarner Losh #include <stand.h>
57*ca987d46SWarner Losh #endif
58*ca987d46SWarner Losh #include <stdarg.h>
59*ca987d46SWarner Losh #include <string.h>
60*ca987d46SWarner Losh #include "ficl.h"
61*ca987d46SWarner Losh 
62*ca987d46SWarner Losh static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
63*ca987d46SWarner Losh 
64*ca987d46SWarner Losh 
65*ca987d46SWarner Losh /**************************************************************************
66*ca987d46SWarner Losh                         v m B r a n c h R e l a t i v e
67*ca987d46SWarner Losh **
68*ca987d46SWarner Losh **************************************************************************/
vmBranchRelative(FICL_VM * pVM,int offset)69*ca987d46SWarner Losh void vmBranchRelative(FICL_VM *pVM, int offset)
70*ca987d46SWarner Losh {
71*ca987d46SWarner Losh     pVM->ip += offset;
72*ca987d46SWarner Losh     return;
73*ca987d46SWarner Losh }
74*ca987d46SWarner Losh 
75*ca987d46SWarner Losh 
76*ca987d46SWarner Losh /**************************************************************************
77*ca987d46SWarner Losh                         v m C r e a t e
78*ca987d46SWarner Losh ** Creates a virtual machine either from scratch (if pVM is NULL on entry)
79*ca987d46SWarner Losh ** or by resizing and reinitializing an existing VM to the specified stack
80*ca987d46SWarner Losh ** sizes.
81*ca987d46SWarner Losh **************************************************************************/
vmCreate(FICL_VM * pVM,unsigned nPStack,unsigned nRStack)82*ca987d46SWarner Losh FICL_VM *vmCreate(FICL_VM *pVM, unsigned nPStack, unsigned nRStack)
83*ca987d46SWarner Losh {
84*ca987d46SWarner Losh     if (pVM == NULL)
85*ca987d46SWarner Losh     {
86*ca987d46SWarner Losh         pVM = (FICL_VM *)ficlMalloc(sizeof (FICL_VM));
87*ca987d46SWarner Losh         assert (pVM);
88*ca987d46SWarner Losh         memset(pVM, 0, sizeof (FICL_VM));
89*ca987d46SWarner Losh     }
90*ca987d46SWarner Losh 
91*ca987d46SWarner Losh     if (pVM->pStack)
92*ca987d46SWarner Losh         stackDelete(pVM->pStack);
93*ca987d46SWarner Losh     pVM->pStack = stackCreate(nPStack);
94*ca987d46SWarner Losh 
95*ca987d46SWarner Losh     if (pVM->rStack)
96*ca987d46SWarner Losh         stackDelete(pVM->rStack);
97*ca987d46SWarner Losh     pVM->rStack = stackCreate(nRStack);
98*ca987d46SWarner Losh 
99*ca987d46SWarner Losh #if FICL_WANT_FLOAT
100*ca987d46SWarner Losh     if (pVM->fStack)
101*ca987d46SWarner Losh         stackDelete(pVM->fStack);
102*ca987d46SWarner Losh     pVM->fStack = stackCreate(nPStack);
103*ca987d46SWarner Losh #endif
104*ca987d46SWarner Losh 
105*ca987d46SWarner Losh     pVM->textOut = ficlTextOut;
106*ca987d46SWarner Losh 
107*ca987d46SWarner Losh     vmReset(pVM);
108*ca987d46SWarner Losh     return pVM;
109*ca987d46SWarner Losh }
110*ca987d46SWarner Losh 
111*ca987d46SWarner Losh 
112*ca987d46SWarner Losh /**************************************************************************
113*ca987d46SWarner Losh                         v m D e l e t e
114*ca987d46SWarner Losh ** Free all memory allocated to the specified VM and its subordinate
115*ca987d46SWarner Losh ** structures.
116*ca987d46SWarner Losh **************************************************************************/
vmDelete(FICL_VM * pVM)117*ca987d46SWarner Losh void vmDelete (FICL_VM *pVM)
118*ca987d46SWarner Losh {
119*ca987d46SWarner Losh     if (pVM)
120*ca987d46SWarner Losh     {
121*ca987d46SWarner Losh         ficlFree(pVM->pStack);
122*ca987d46SWarner Losh         ficlFree(pVM->rStack);
123*ca987d46SWarner Losh #if FICL_WANT_FLOAT
124*ca987d46SWarner Losh         ficlFree(pVM->fStack);
125*ca987d46SWarner Losh #endif
126*ca987d46SWarner Losh         ficlFree(pVM);
127*ca987d46SWarner Losh     }
128*ca987d46SWarner Losh 
129*ca987d46SWarner Losh     return;
130*ca987d46SWarner Losh }
131*ca987d46SWarner Losh 
132*ca987d46SWarner Losh 
133*ca987d46SWarner Losh /**************************************************************************
134*ca987d46SWarner Losh                         v m E x e c u t e
135*ca987d46SWarner Losh ** Sets up the specified word to be run by the inner interpreter.
136*ca987d46SWarner Losh ** Executes the word's code part immediately, but in the case of
137*ca987d46SWarner Losh ** colon definition, the definition itself needs the inner interp
138*ca987d46SWarner Losh ** to complete. This does not happen until control reaches ficlExec
139*ca987d46SWarner Losh **************************************************************************/
vmExecute(FICL_VM * pVM,FICL_WORD * pWord)140*ca987d46SWarner Losh void vmExecute(FICL_VM *pVM, FICL_WORD *pWord)
141*ca987d46SWarner Losh {
142*ca987d46SWarner Losh     pVM->runningWord = pWord;
143*ca987d46SWarner Losh     pWord->code(pVM);
144*ca987d46SWarner Losh     return;
145*ca987d46SWarner Losh }
146*ca987d46SWarner Losh 
147*ca987d46SWarner Losh 
148*ca987d46SWarner Losh /**************************************************************************
149*ca987d46SWarner Losh                         v m I n n e r L o o p
150*ca987d46SWarner Losh ** the mysterious inner interpreter...
151*ca987d46SWarner Losh ** This loop is the address interpreter that makes colon definitions
152*ca987d46SWarner Losh ** work. Upon entry, it assumes that the IP points to an entry in
153*ca987d46SWarner Losh ** a definition (the body of a colon word). It runs one word at a time
154*ca987d46SWarner Losh ** until something does vmThrow. The catcher for this is expected to exist
155*ca987d46SWarner Losh ** in the calling code.
156*ca987d46SWarner Losh ** vmThrow gets you out of this loop with a longjmp()
157*ca987d46SWarner Losh ** Visual C++ 5 chokes on this loop in Release mode. Aargh.
158*ca987d46SWarner Losh **************************************************************************/
159*ca987d46SWarner Losh #if INLINE_INNER_LOOP == 0
vmInnerLoop(FICL_VM * pVM)160*ca987d46SWarner Losh void vmInnerLoop(FICL_VM *pVM)
161*ca987d46SWarner Losh {
162*ca987d46SWarner Losh     M_INNER_LOOP(pVM);
163*ca987d46SWarner Losh }
164*ca987d46SWarner Losh #endif
165*ca987d46SWarner Losh #if 0
166*ca987d46SWarner Losh /*
167*ca987d46SWarner Losh ** Recast inner loop that inlines tokens for control structures, arithmetic and stack operations,
168*ca987d46SWarner Losh ** as well as create does> : ; and various literals
169*ca987d46SWarner Losh */
170*ca987d46SWarner Losh typedef enum
171*ca987d46SWarner Losh {
172*ca987d46SWarner Losh     PATCH = 0,
173*ca987d46SWarner Losh     L0,
174*ca987d46SWarner Losh     L1,
175*ca987d46SWarner Losh     L2,
176*ca987d46SWarner Losh     LMINUS1,
177*ca987d46SWarner Losh     LMINUS2,
178*ca987d46SWarner Losh     DROP,
179*ca987d46SWarner Losh     SWAP,
180*ca987d46SWarner Losh     DUP,
181*ca987d46SWarner Losh     PICK,
182*ca987d46SWarner Losh     ROLL,
183*ca987d46SWarner Losh     FETCH,
184*ca987d46SWarner Losh     STORE,
185*ca987d46SWarner Losh     BRANCH,
186*ca987d46SWarner Losh     CBRANCH,
187*ca987d46SWarner Losh     LEAVE,
188*ca987d46SWarner Losh     TO_R,
189*ca987d46SWarner Losh     R_FROM,
190*ca987d46SWarner Losh     EXIT;
191*ca987d46SWarner Losh } OPCODE;
192*ca987d46SWarner Losh 
193*ca987d46SWarner Losh typedef CELL *IPTYPE;
194*ca987d46SWarner Losh 
195*ca987d46SWarner Losh void vmInnerLoop(FICL_VM *pVM)
196*ca987d46SWarner Losh {
197*ca987d46SWarner Losh     IPTYPE ip = pVM->ip;
198*ca987d46SWarner Losh     FICL_STACK *pStack = pVM->pStack;
199*ca987d46SWarner Losh 
200*ca987d46SWarner Losh     for (;;)
201*ca987d46SWarner Losh     {
202*ca987d46SWarner Losh         OPCODE o = (*ip++).i;
203*ca987d46SWarner Losh         CELL c;
204*ca987d46SWarner Losh         switch (o)
205*ca987d46SWarner Losh         {
206*ca987d46SWarner Losh         case L0:
207*ca987d46SWarner Losh             stackPushINT(pStack, 0);
208*ca987d46SWarner Losh             break;
209*ca987d46SWarner Losh         case L1:
210*ca987d46SWarner Losh             stackPushINT(pStack, 1);
211*ca987d46SWarner Losh             break;
212*ca987d46SWarner Losh         case L2:
213*ca987d46SWarner Losh             stackPushINT(pStack, 2);
214*ca987d46SWarner Losh             break;
215*ca987d46SWarner Losh         case LMINUS1:
216*ca987d46SWarner Losh             stackPushINT(pStack, -1);
217*ca987d46SWarner Losh             break;
218*ca987d46SWarner Losh         case LMINUS2:
219*ca987d46SWarner Losh             stackPushINT(pStack, -2);
220*ca987d46SWarner Losh             break;
221*ca987d46SWarner Losh         case DROP:
222*ca987d46SWarner Losh             stackDrop(pStack, 1);
223*ca987d46SWarner Losh             break;
224*ca987d46SWarner Losh         case SWAP:
225*ca987d46SWarner Losh             stackRoll(pStack, 1);
226*ca987d46SWarner Losh             break;
227*ca987d46SWarner Losh         case DUP:
228*ca987d46SWarner Losh             stackPick(pStack, 0);
229*ca987d46SWarner Losh             break;
230*ca987d46SWarner Losh         case PICK:
231*ca987d46SWarner Losh             c = *ip++;
232*ca987d46SWarner Losh             stackPick(pStack, c.i);
233*ca987d46SWarner Losh             break;
234*ca987d46SWarner Losh         case ROLL:
235*ca987d46SWarner Losh             c = *ip++;
236*ca987d46SWarner Losh             stackRoll(pStack, c.i);
237*ca987d46SWarner Losh             break;
238*ca987d46SWarner Losh         case EXIT:
239*ca987d46SWarner Losh             return;
240*ca987d46SWarner Losh         }
241*ca987d46SWarner Losh     }
242*ca987d46SWarner Losh 
243*ca987d46SWarner Losh     return;
244*ca987d46SWarner Losh }
245*ca987d46SWarner Losh #endif
246*ca987d46SWarner Losh 
247*ca987d46SWarner Losh 
248*ca987d46SWarner Losh 
249*ca987d46SWarner Losh /**************************************************************************
250*ca987d46SWarner Losh                         v m G e t D i c t
251*ca987d46SWarner Losh ** Returns the address dictionary for this VM's system
252*ca987d46SWarner Losh **************************************************************************/
vmGetDict(FICL_VM * pVM)253*ca987d46SWarner Losh FICL_DICT  *vmGetDict(FICL_VM *pVM)
254*ca987d46SWarner Losh {
255*ca987d46SWarner Losh 	assert(pVM);
256*ca987d46SWarner Losh 	return pVM->pSys->dp;
257*ca987d46SWarner Losh }
258*ca987d46SWarner Losh 
259*ca987d46SWarner Losh 
260*ca987d46SWarner Losh /**************************************************************************
261*ca987d46SWarner Losh                         v m G e t S t r i n g
262*ca987d46SWarner Losh ** Parses a string out of the VM input buffer and copies up to the first
263*ca987d46SWarner Losh ** FICL_STRING_MAX characters to the supplied destination buffer, a
264*ca987d46SWarner Losh ** FICL_STRING. The destination string is NULL terminated.
265*ca987d46SWarner Losh **
266*ca987d46SWarner Losh ** Returns the address of the first unused character in the dest buffer.
267*ca987d46SWarner Losh **************************************************************************/
vmGetString(FICL_VM * pVM,FICL_STRING * spDest,char delimiter)268*ca987d46SWarner Losh char *vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter)
269*ca987d46SWarner Losh {
270*ca987d46SWarner Losh     STRINGINFO si = vmParseStringEx(pVM, delimiter, 0);
271*ca987d46SWarner Losh 
272*ca987d46SWarner Losh     if (SI_COUNT(si) > FICL_STRING_MAX)
273*ca987d46SWarner Losh     {
274*ca987d46SWarner Losh         SI_SETLEN(si, FICL_STRING_MAX);
275*ca987d46SWarner Losh     }
276*ca987d46SWarner Losh 
277*ca987d46SWarner Losh     strncpy(spDest->text, SI_PTR(si), SI_COUNT(si));
278*ca987d46SWarner Losh     spDest->text[SI_COUNT(si)] = '\0';
279*ca987d46SWarner Losh     spDest->count = (FICL_COUNT)SI_COUNT(si);
280*ca987d46SWarner Losh 
281*ca987d46SWarner Losh     return spDest->text + SI_COUNT(si) + 1;
282*ca987d46SWarner Losh }
283*ca987d46SWarner Losh 
284*ca987d46SWarner Losh 
285*ca987d46SWarner Losh /**************************************************************************
286*ca987d46SWarner Losh                         v m G e t W o r d
287*ca987d46SWarner Losh ** vmGetWord calls vmGetWord0 repeatedly until it gets a string with
288*ca987d46SWarner Losh ** non-zero length.
289*ca987d46SWarner Losh **************************************************************************/
vmGetWord(FICL_VM * pVM)290*ca987d46SWarner Losh STRINGINFO vmGetWord(FICL_VM *pVM)
291*ca987d46SWarner Losh {
292*ca987d46SWarner Losh     STRINGINFO si = vmGetWord0(pVM);
293*ca987d46SWarner Losh 
294*ca987d46SWarner Losh     if (SI_COUNT(si) == 0)
295*ca987d46SWarner Losh     {
296*ca987d46SWarner Losh         vmThrow(pVM, VM_RESTART);
297*ca987d46SWarner Losh     }
298*ca987d46SWarner Losh 
299*ca987d46SWarner Losh     return si;
300*ca987d46SWarner Losh }
301*ca987d46SWarner Losh 
302*ca987d46SWarner Losh 
303*ca987d46SWarner Losh /**************************************************************************
304*ca987d46SWarner Losh                         v m G e t W o r d 0
305*ca987d46SWarner Losh ** Skip leading whitespace and parse a space delimited word from the tib.
306*ca987d46SWarner Losh ** Returns the start address and length of the word. Updates the tib
307*ca987d46SWarner Losh ** to reflect characters consumed, including the trailing delimiter.
308*ca987d46SWarner Losh ** If there's nothing of interest in the tib, returns zero. This function
309*ca987d46SWarner Losh ** does not use vmParseString because it uses isspace() rather than a
310*ca987d46SWarner Losh ** single  delimiter character.
311*ca987d46SWarner Losh **************************************************************************/
vmGetWord0(FICL_VM * pVM)312*ca987d46SWarner Losh STRINGINFO vmGetWord0(FICL_VM *pVM)
313*ca987d46SWarner Losh {
314*ca987d46SWarner Losh     char *pSrc      = vmGetInBuf(pVM);
315*ca987d46SWarner Losh     char *pEnd      = vmGetInBufEnd(pVM);
316*ca987d46SWarner Losh     STRINGINFO si;
317*ca987d46SWarner Losh     FICL_UNS count = 0;
318*ca987d46SWarner Losh     char ch = 0;
319*ca987d46SWarner Losh 
320*ca987d46SWarner Losh     pSrc = skipSpace(pSrc, pEnd);
321*ca987d46SWarner Losh     SI_SETPTR(si, pSrc);
322*ca987d46SWarner Losh 
323*ca987d46SWarner Losh /*
324*ca987d46SWarner Losh     for (ch = *pSrc; (pEnd != pSrc) && !isspace(ch); ch = *++pSrc)
325*ca987d46SWarner Losh     {
326*ca987d46SWarner Losh         count++;
327*ca987d46SWarner Losh     }
328*ca987d46SWarner Losh */
329*ca987d46SWarner Losh 
330*ca987d46SWarner Losh     /* Changed to make Purify happier.  --lch */
331*ca987d46SWarner Losh     for (;;)
332*ca987d46SWarner Losh     {
333*ca987d46SWarner Losh         if (pEnd == pSrc)
334*ca987d46SWarner Losh             break;
335*ca987d46SWarner Losh         ch = *pSrc;
336*ca987d46SWarner Losh         if (isspace(ch))
337*ca987d46SWarner Losh             break;
338*ca987d46SWarner Losh         count++;
339*ca987d46SWarner Losh         pSrc++;
340*ca987d46SWarner Losh     }
341*ca987d46SWarner Losh 
342*ca987d46SWarner Losh     SI_SETLEN(si, count);
343*ca987d46SWarner Losh 
344*ca987d46SWarner Losh     if ((pEnd != pSrc) && isspace(ch))    /* skip one trailing delimiter */
345*ca987d46SWarner Losh         pSrc++;
346*ca987d46SWarner Losh 
347*ca987d46SWarner Losh     vmUpdateTib(pVM, pSrc);
348*ca987d46SWarner Losh 
349*ca987d46SWarner Losh     return si;
350*ca987d46SWarner Losh }
351*ca987d46SWarner Losh 
352*ca987d46SWarner Losh 
353*ca987d46SWarner Losh /**************************************************************************
354*ca987d46SWarner Losh                         v m G e t W o r d T o P a d
355*ca987d46SWarner Losh ** Does vmGetWord and copies the result to the pad as a NULL terminated
356*ca987d46SWarner Losh ** string. Returns the length of the string. If the string is too long
357*ca987d46SWarner Losh ** to fit in the pad, it is truncated.
358*ca987d46SWarner Losh **************************************************************************/
vmGetWordToPad(FICL_VM * pVM)359*ca987d46SWarner Losh int vmGetWordToPad(FICL_VM *pVM)
360*ca987d46SWarner Losh {
361*ca987d46SWarner Losh     STRINGINFO si;
362*ca987d46SWarner Losh     char *cp = (char *)pVM->pad;
363*ca987d46SWarner Losh     si = vmGetWord(pVM);
364*ca987d46SWarner Losh 
365*ca987d46SWarner Losh     if (SI_COUNT(si) > nPAD)
366*ca987d46SWarner Losh         SI_SETLEN(si, nPAD);
367*ca987d46SWarner Losh 
368*ca987d46SWarner Losh     strncpy(cp, SI_PTR(si), SI_COUNT(si));
369*ca987d46SWarner Losh     cp[SI_COUNT(si)] = '\0';
370*ca987d46SWarner Losh     return (int)(SI_COUNT(si));
371*ca987d46SWarner Losh }
372*ca987d46SWarner Losh 
373*ca987d46SWarner Losh 
374*ca987d46SWarner Losh /**************************************************************************
375*ca987d46SWarner Losh                         v m P a r s e S t r i n g
376*ca987d46SWarner Losh ** Parses a string out of the input buffer using the delimiter
377*ca987d46SWarner Losh ** specified. Skips leading delimiters, marks the start of the string,
378*ca987d46SWarner Losh ** and counts characters to the next delimiter it encounters. It then
379*ca987d46SWarner Losh ** updates the vm input buffer to consume all these chars, including the
380*ca987d46SWarner Losh ** trailing delimiter.
381*ca987d46SWarner Losh ** Returns the address and length of the parsed string, not including the
382*ca987d46SWarner Losh ** trailing delimiter.
383*ca987d46SWarner Losh **************************************************************************/
vmParseString(FICL_VM * pVM,char delim)384*ca987d46SWarner Losh STRINGINFO vmParseString(FICL_VM *pVM, char delim)
385*ca987d46SWarner Losh {
386*ca987d46SWarner Losh     return vmParseStringEx(pVM, delim, 1);
387*ca987d46SWarner Losh }
388*ca987d46SWarner Losh 
vmParseStringEx(FICL_VM * pVM,char delim,char fSkipLeading)389*ca987d46SWarner Losh STRINGINFO vmParseStringEx(FICL_VM *pVM, char delim, char fSkipLeading)
390*ca987d46SWarner Losh {
391*ca987d46SWarner Losh     STRINGINFO si;
392*ca987d46SWarner Losh     char *pSrc      = vmGetInBuf(pVM);
393*ca987d46SWarner Losh     char *pEnd      = vmGetInBufEnd(pVM);
394*ca987d46SWarner Losh     char ch;
395*ca987d46SWarner Losh 
396*ca987d46SWarner Losh     if (fSkipLeading)
397*ca987d46SWarner Losh     {                       /* skip lead delimiters */
398*ca987d46SWarner Losh         while ((pSrc != pEnd) && (*pSrc == delim))
399*ca987d46SWarner Losh             pSrc++;
400*ca987d46SWarner Losh     }
401*ca987d46SWarner Losh 
402*ca987d46SWarner Losh     SI_SETPTR(si, pSrc);    /* mark start of text */
403*ca987d46SWarner Losh 
404*ca987d46SWarner Losh     for (ch = *pSrc; (pSrc != pEnd)
405*ca987d46SWarner Losh                   && (ch != delim)
406*ca987d46SWarner Losh                   && (ch != '\r')
407*ca987d46SWarner Losh                   && (ch != '\n'); ch = *++pSrc)
408*ca987d46SWarner Losh     {
409*ca987d46SWarner Losh         ;                   /* find next delimiter or end of line */
410*ca987d46SWarner Losh     }
411*ca987d46SWarner Losh 
412*ca987d46SWarner Losh                             /* set length of result */
413*ca987d46SWarner Losh     SI_SETLEN(si, pSrc - SI_PTR(si));
414*ca987d46SWarner Losh 
415*ca987d46SWarner Losh     if ((pSrc != pEnd) && (*pSrc == delim))     /* gobble trailing delimiter */
416*ca987d46SWarner Losh         pSrc++;
417*ca987d46SWarner Losh 
418*ca987d46SWarner Losh     vmUpdateTib(pVM, pSrc);
419*ca987d46SWarner Losh     return si;
420*ca987d46SWarner Losh }
421*ca987d46SWarner Losh 
422*ca987d46SWarner Losh 
423*ca987d46SWarner Losh /**************************************************************************
424*ca987d46SWarner Losh                         v m P o p
425*ca987d46SWarner Losh **
426*ca987d46SWarner Losh **************************************************************************/
vmPop(FICL_VM * pVM)427*ca987d46SWarner Losh CELL vmPop(FICL_VM *pVM)
428*ca987d46SWarner Losh {
429*ca987d46SWarner Losh     return stackPop(pVM->pStack);
430*ca987d46SWarner Losh }
431*ca987d46SWarner Losh 
432*ca987d46SWarner Losh 
433*ca987d46SWarner Losh /**************************************************************************
434*ca987d46SWarner Losh                         v m P u s h
435*ca987d46SWarner Losh **
436*ca987d46SWarner Losh **************************************************************************/
vmPush(FICL_VM * pVM,CELL c)437*ca987d46SWarner Losh void vmPush(FICL_VM *pVM, CELL c)
438*ca987d46SWarner Losh {
439*ca987d46SWarner Losh     stackPush(pVM->pStack, c);
440*ca987d46SWarner Losh     return;
441*ca987d46SWarner Losh }
442*ca987d46SWarner Losh 
443*ca987d46SWarner Losh 
444*ca987d46SWarner Losh /**************************************************************************
445*ca987d46SWarner Losh                         v m P o p I P
446*ca987d46SWarner Losh **
447*ca987d46SWarner Losh **************************************************************************/
vmPopIP(FICL_VM * pVM)448*ca987d46SWarner Losh void vmPopIP(FICL_VM *pVM)
449*ca987d46SWarner Losh {
450*ca987d46SWarner Losh     pVM->ip = (IPTYPE)(stackPopPtr(pVM->rStack));
451*ca987d46SWarner Losh     return;
452*ca987d46SWarner Losh }
453*ca987d46SWarner Losh 
454*ca987d46SWarner Losh 
455*ca987d46SWarner Losh /**************************************************************************
456*ca987d46SWarner Losh                         v m P u s h I P
457*ca987d46SWarner Losh **
458*ca987d46SWarner Losh **************************************************************************/
vmPushIP(FICL_VM * pVM,IPTYPE newIP)459*ca987d46SWarner Losh void vmPushIP(FICL_VM *pVM, IPTYPE newIP)
460*ca987d46SWarner Losh {
461*ca987d46SWarner Losh     stackPushPtr(pVM->rStack, (void *)pVM->ip);
462*ca987d46SWarner Losh     pVM->ip = newIP;
463*ca987d46SWarner Losh     return;
464*ca987d46SWarner Losh }
465*ca987d46SWarner Losh 
466*ca987d46SWarner Losh 
467*ca987d46SWarner Losh /**************************************************************************
468*ca987d46SWarner Losh                         v m P u s h T i b
469*ca987d46SWarner Losh ** Binds the specified input string to the VM and clears >IN (the index)
470*ca987d46SWarner Losh **************************************************************************/
vmPushTib(FICL_VM * pVM,char * text,FICL_INT nChars,TIB * pSaveTib)471*ca987d46SWarner Losh void vmPushTib(FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib)
472*ca987d46SWarner Losh {
473*ca987d46SWarner Losh     if (pSaveTib)
474*ca987d46SWarner Losh     {
475*ca987d46SWarner Losh         *pSaveTib = pVM->tib;
476*ca987d46SWarner Losh     }
477*ca987d46SWarner Losh 
478*ca987d46SWarner Losh     pVM->tib.cp = text;
479*ca987d46SWarner Losh     pVM->tib.end = text + nChars;
480*ca987d46SWarner Losh     pVM->tib.index = 0;
481*ca987d46SWarner Losh }
482*ca987d46SWarner Losh 
483*ca987d46SWarner Losh 
vmPopTib(FICL_VM * pVM,TIB * pTib)484*ca987d46SWarner Losh void vmPopTib(FICL_VM *pVM, TIB *pTib)
485*ca987d46SWarner Losh {
486*ca987d46SWarner Losh     if (pTib)
487*ca987d46SWarner Losh     {
488*ca987d46SWarner Losh         pVM->tib = *pTib;
489*ca987d46SWarner Losh     }
490*ca987d46SWarner Losh     return;
491*ca987d46SWarner Losh }
492*ca987d46SWarner Losh 
493*ca987d46SWarner Losh 
494*ca987d46SWarner Losh /**************************************************************************
495*ca987d46SWarner Losh                         v m Q u i t
496*ca987d46SWarner Losh **
497*ca987d46SWarner Losh **************************************************************************/
vmQuit(FICL_VM * pVM)498*ca987d46SWarner Losh void vmQuit(FICL_VM *pVM)
499*ca987d46SWarner Losh {
500*ca987d46SWarner Losh     stackReset(pVM->rStack);
501*ca987d46SWarner Losh     pVM->fRestart    = 0;
502*ca987d46SWarner Losh     pVM->ip          = NULL;
503*ca987d46SWarner Losh     pVM->runningWord = NULL;
504*ca987d46SWarner Losh     pVM->state       = INTERPRET;
505*ca987d46SWarner Losh     pVM->tib.cp      = NULL;
506*ca987d46SWarner Losh     pVM->tib.end     = NULL;
507*ca987d46SWarner Losh     pVM->tib.index   = 0;
508*ca987d46SWarner Losh     pVM->pad[0]      = '\0';
509*ca987d46SWarner Losh     pVM->sourceID.i  = 0;
510*ca987d46SWarner Losh     return;
511*ca987d46SWarner Losh }
512*ca987d46SWarner Losh 
513*ca987d46SWarner Losh 
514*ca987d46SWarner Losh /**************************************************************************
515*ca987d46SWarner Losh                         v m R e s e t
516*ca987d46SWarner Losh **
517*ca987d46SWarner Losh **************************************************************************/
vmReset(FICL_VM * pVM)518*ca987d46SWarner Losh void vmReset(FICL_VM *pVM)
519*ca987d46SWarner Losh {
520*ca987d46SWarner Losh     vmQuit(pVM);
521*ca987d46SWarner Losh     stackReset(pVM->pStack);
522*ca987d46SWarner Losh #if FICL_WANT_FLOAT
523*ca987d46SWarner Losh     stackReset(pVM->fStack);
524*ca987d46SWarner Losh #endif
525*ca987d46SWarner Losh     pVM->base        = 10;
526*ca987d46SWarner Losh     return;
527*ca987d46SWarner Losh }
528*ca987d46SWarner Losh 
529*ca987d46SWarner Losh 
530*ca987d46SWarner Losh /**************************************************************************
531*ca987d46SWarner Losh                         v m S e t T e x t O u t
532*ca987d46SWarner Losh ** Binds the specified output callback to the vm. If you pass NULL,
533*ca987d46SWarner Losh ** binds the default output function (ficlTextOut)
534*ca987d46SWarner Losh **************************************************************************/
vmSetTextOut(FICL_VM * pVM,OUTFUNC textOut)535*ca987d46SWarner Losh void vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut)
536*ca987d46SWarner Losh {
537*ca987d46SWarner Losh     if (textOut)
538*ca987d46SWarner Losh         pVM->textOut = textOut;
539*ca987d46SWarner Losh     else
540*ca987d46SWarner Losh         pVM->textOut = ficlTextOut;
541*ca987d46SWarner Losh 
542*ca987d46SWarner Losh     return;
543*ca987d46SWarner Losh }
544*ca987d46SWarner Losh 
545*ca987d46SWarner Losh 
546*ca987d46SWarner Losh /**************************************************************************
547*ca987d46SWarner Losh                         v m T e x t O u t
548*ca987d46SWarner Losh ** Feeds text to the vm's output callback
549*ca987d46SWarner Losh **************************************************************************/
vmTextOut(FICL_VM * pVM,char * text,int fNewline)550*ca987d46SWarner Losh void vmTextOut(FICL_VM *pVM, char *text, int fNewline)
551*ca987d46SWarner Losh {
552*ca987d46SWarner Losh     assert(pVM);
553*ca987d46SWarner Losh     assert(pVM->textOut);
554*ca987d46SWarner Losh     (pVM->textOut)(pVM, text, fNewline);
555*ca987d46SWarner Losh 
556*ca987d46SWarner Losh     return;
557*ca987d46SWarner Losh }
558*ca987d46SWarner Losh 
559*ca987d46SWarner Losh 
560*ca987d46SWarner Losh /**************************************************************************
561*ca987d46SWarner Losh                         v m T h r o w
562*ca987d46SWarner Losh **
563*ca987d46SWarner Losh **************************************************************************/
vmThrow(FICL_VM * pVM,int except)564*ca987d46SWarner Losh void vmThrow(FICL_VM *pVM, int except)
565*ca987d46SWarner Losh {
566*ca987d46SWarner Losh     if (pVM->pState)
567*ca987d46SWarner Losh         longjmp(*(pVM->pState), except);
568*ca987d46SWarner Losh }
569*ca987d46SWarner Losh 
570*ca987d46SWarner Losh 
vmThrowErr(FICL_VM * pVM,char * fmt,...)571*ca987d46SWarner Losh void vmThrowErr(FICL_VM *pVM, char *fmt, ...)
572*ca987d46SWarner Losh {
573*ca987d46SWarner Losh     va_list va;
574*ca987d46SWarner Losh     va_start(va, fmt);
575*ca987d46SWarner Losh     vsprintf(pVM->pad, fmt, va);
576*ca987d46SWarner Losh     vmTextOut(pVM, pVM->pad, 1);
577*ca987d46SWarner Losh     va_end(va);
578*ca987d46SWarner Losh     longjmp(*(pVM->pState), VM_ERREXIT);
579*ca987d46SWarner Losh }
580*ca987d46SWarner Losh 
581*ca987d46SWarner Losh 
582*ca987d46SWarner Losh /**************************************************************************
583*ca987d46SWarner Losh                         w o r d I s I m m e d i a t e
584*ca987d46SWarner Losh **
585*ca987d46SWarner Losh **************************************************************************/
wordIsImmediate(FICL_WORD * pFW)586*ca987d46SWarner Losh int wordIsImmediate(FICL_WORD *pFW)
587*ca987d46SWarner Losh {
588*ca987d46SWarner Losh     return ((pFW != NULL) && (pFW->flags & FW_IMMEDIATE));
589*ca987d46SWarner Losh }
590*ca987d46SWarner Losh 
591*ca987d46SWarner Losh 
592*ca987d46SWarner Losh /**************************************************************************
593*ca987d46SWarner Losh                         w o r d I s C o m p i l e O n l y
594*ca987d46SWarner Losh **
595*ca987d46SWarner Losh **************************************************************************/
wordIsCompileOnly(FICL_WORD * pFW)596*ca987d46SWarner Losh int wordIsCompileOnly(FICL_WORD *pFW)
597*ca987d46SWarner Losh {
598*ca987d46SWarner Losh     return ((pFW != NULL) && (pFW->flags & FW_COMPILE));
599*ca987d46SWarner Losh }
600*ca987d46SWarner Losh 
601*ca987d46SWarner Losh 
602*ca987d46SWarner Losh /**************************************************************************
603*ca987d46SWarner Losh                         s t r r e v
604*ca987d46SWarner Losh **
605*ca987d46SWarner Losh **************************************************************************/
strrev(char * string)606*ca987d46SWarner Losh char *strrev( char *string )
607*ca987d46SWarner Losh {                               /* reverse a string in-place */
608*ca987d46SWarner Losh     int i = strlen(string);
609*ca987d46SWarner Losh     char *p1 = string;          /* first char of string */
610*ca987d46SWarner Losh     char *p2 = string + i - 1;  /* last non-NULL char of string */
611*ca987d46SWarner Losh     char c;
612*ca987d46SWarner Losh 
613*ca987d46SWarner Losh     if (i > 1)
614*ca987d46SWarner Losh     {
615*ca987d46SWarner Losh         while (p1 < p2)
616*ca987d46SWarner Losh         {
617*ca987d46SWarner Losh             c = *p2;
618*ca987d46SWarner Losh             *p2 = *p1;
619*ca987d46SWarner Losh             *p1 = c;
620*ca987d46SWarner Losh             p1++; p2--;
621*ca987d46SWarner Losh         }
622*ca987d46SWarner Losh     }
623*ca987d46SWarner Losh 
624*ca987d46SWarner Losh     return string;
625*ca987d46SWarner Losh }
626*ca987d46SWarner Losh 
627*ca987d46SWarner Losh 
628*ca987d46SWarner Losh /**************************************************************************
629*ca987d46SWarner Losh                         d i g i t _ t o _ c h a r
630*ca987d46SWarner Losh **
631*ca987d46SWarner Losh **************************************************************************/
digit_to_char(int value)632*ca987d46SWarner Losh char digit_to_char(int value)
633*ca987d46SWarner Losh {
634*ca987d46SWarner Losh     return digits[value];
635*ca987d46SWarner Losh }
636*ca987d46SWarner Losh 
637*ca987d46SWarner Losh 
638*ca987d46SWarner Losh /**************************************************************************
639*ca987d46SWarner Losh                         i s P o w e r O f T w o
640*ca987d46SWarner Losh ** Tests whether supplied argument is an integer power of 2 (2**n)
641*ca987d46SWarner Losh ** where 32 > n > 1, and returns n if so. Otherwise returns zero.
642*ca987d46SWarner Losh **************************************************************************/
isPowerOfTwo(FICL_UNS u)643*ca987d46SWarner Losh int isPowerOfTwo(FICL_UNS u)
644*ca987d46SWarner Losh {
645*ca987d46SWarner Losh     int i = 1;
646*ca987d46SWarner Losh     FICL_UNS t = 2;
647*ca987d46SWarner Losh 
648*ca987d46SWarner Losh     for (; ((t <= u) && (t != 0)); i++, t <<= 1)
649*ca987d46SWarner Losh     {
650*ca987d46SWarner Losh         if (u == t)
651*ca987d46SWarner Losh             return i;
652*ca987d46SWarner Losh     }
653*ca987d46SWarner Losh 
654*ca987d46SWarner Losh     return 0;
655*ca987d46SWarner Losh }
656*ca987d46SWarner Losh 
657*ca987d46SWarner Losh 
658*ca987d46SWarner Losh /**************************************************************************
659*ca987d46SWarner Losh                         l t o a
660*ca987d46SWarner Losh **
661*ca987d46SWarner Losh **************************************************************************/
ltoa(FICL_INT value,char * string,int radix)662*ca987d46SWarner Losh char *ltoa( FICL_INT value, char *string, int radix )
663*ca987d46SWarner Losh {                               /* convert long to string, any base */
664*ca987d46SWarner Losh     char *cp = string;
665*ca987d46SWarner Losh     int sign = ((radix == 10) && (value < 0));
666*ca987d46SWarner Losh     int pwr;
667*ca987d46SWarner Losh 
668*ca987d46SWarner Losh     assert(radix > 1);
669*ca987d46SWarner Losh     assert(radix < 37);
670*ca987d46SWarner Losh     assert(string);
671*ca987d46SWarner Losh 
672*ca987d46SWarner Losh     pwr = isPowerOfTwo((FICL_UNS)radix);
673*ca987d46SWarner Losh 
674*ca987d46SWarner Losh     if (sign)
675*ca987d46SWarner Losh         value = -value;
676*ca987d46SWarner Losh 
677*ca987d46SWarner Losh     if (value == 0)
678*ca987d46SWarner Losh         *cp++ = '0';
679*ca987d46SWarner Losh     else if (pwr != 0)
680*ca987d46SWarner Losh     {
681*ca987d46SWarner Losh         FICL_UNS v = (FICL_UNS) value;
682*ca987d46SWarner Losh         FICL_UNS mask = (FICL_UNS) ~(-1 << pwr);
683*ca987d46SWarner Losh         while (v)
684*ca987d46SWarner Losh         {
685*ca987d46SWarner Losh             *cp++ = digits[v & mask];
686*ca987d46SWarner Losh             v >>= pwr;
687*ca987d46SWarner Losh         }
688*ca987d46SWarner Losh     }
689*ca987d46SWarner Losh     else
690*ca987d46SWarner Losh     {
691*ca987d46SWarner Losh         UNSQR result;
692*ca987d46SWarner Losh         DPUNS v;
693*ca987d46SWarner Losh         v.hi = 0;
694*ca987d46SWarner Losh         v.lo = (FICL_UNS)value;
695*ca987d46SWarner Losh         while (v.lo)
696*ca987d46SWarner Losh         {
697*ca987d46SWarner Losh             result = ficlLongDiv(v, (FICL_UNS)radix);
698*ca987d46SWarner Losh             *cp++ = digits[result.rem];
699*ca987d46SWarner Losh             v.lo = result.quot;
700*ca987d46SWarner Losh         }
701*ca987d46SWarner Losh     }
702*ca987d46SWarner Losh 
703*ca987d46SWarner Losh     if (sign)
704*ca987d46SWarner Losh         *cp++ = '-';
705*ca987d46SWarner Losh 
706*ca987d46SWarner Losh     *cp++ = '\0';
707*ca987d46SWarner Losh 
708*ca987d46SWarner Losh     return strrev(string);
709*ca987d46SWarner Losh }
710*ca987d46SWarner Losh 
711*ca987d46SWarner Losh 
712*ca987d46SWarner Losh /**************************************************************************
713*ca987d46SWarner Losh                         u l t o a
714*ca987d46SWarner Losh **
715*ca987d46SWarner Losh **************************************************************************/
ultoa(FICL_UNS value,char * string,int radix)716*ca987d46SWarner Losh char *ultoa(FICL_UNS value, char *string, int radix )
717*ca987d46SWarner Losh {                               /* convert long to string, any base */
718*ca987d46SWarner Losh     char *cp = string;
719*ca987d46SWarner Losh     DPUNS ud;
720*ca987d46SWarner Losh     UNSQR result;
721*ca987d46SWarner Losh 
722*ca987d46SWarner Losh     assert(radix > 1);
723*ca987d46SWarner Losh     assert(radix < 37);
724*ca987d46SWarner Losh     assert(string);
725*ca987d46SWarner Losh 
726*ca987d46SWarner Losh     if (value == 0)
727*ca987d46SWarner Losh         *cp++ = '0';
728*ca987d46SWarner Losh     else
729*ca987d46SWarner Losh     {
730*ca987d46SWarner Losh         ud.hi = 0;
731*ca987d46SWarner Losh         ud.lo = value;
732*ca987d46SWarner Losh         result.quot = value;
733*ca987d46SWarner Losh 
734*ca987d46SWarner Losh         while (ud.lo)
735*ca987d46SWarner Losh         {
736*ca987d46SWarner Losh             result = ficlLongDiv(ud, (FICL_UNS)radix);
737*ca987d46SWarner Losh             ud.lo = result.quot;
738*ca987d46SWarner Losh             *cp++ = digits[result.rem];
739*ca987d46SWarner Losh         }
740*ca987d46SWarner Losh     }
741*ca987d46SWarner Losh 
742*ca987d46SWarner Losh     *cp++ = '\0';
743*ca987d46SWarner Losh 
744*ca987d46SWarner Losh     return strrev(string);
745*ca987d46SWarner Losh }
746*ca987d46SWarner Losh 
747*ca987d46SWarner Losh 
748*ca987d46SWarner Losh /**************************************************************************
749*ca987d46SWarner Losh                         c a s e F o l d
750*ca987d46SWarner Losh ** Case folds a NULL terminated string in place. All characters
751*ca987d46SWarner Losh ** get converted to lower case.
752*ca987d46SWarner Losh **************************************************************************/
caseFold(char * cp)753*ca987d46SWarner Losh char *caseFold(char *cp)
754*ca987d46SWarner Losh {
755*ca987d46SWarner Losh     char *oldCp = cp;
756*ca987d46SWarner Losh 
757*ca987d46SWarner Losh     while (*cp)
758*ca987d46SWarner Losh     {
759*ca987d46SWarner Losh         if (isupper(*cp))
760*ca987d46SWarner Losh             *cp = (char)tolower(*cp);
761*ca987d46SWarner Losh         cp++;
762*ca987d46SWarner Losh     }
763*ca987d46SWarner Losh 
764*ca987d46SWarner Losh     return oldCp;
765*ca987d46SWarner Losh }
766*ca987d46SWarner Losh 
767*ca987d46SWarner Losh 
768*ca987d46SWarner Losh /**************************************************************************
769*ca987d46SWarner Losh                         s t r i n c m p
770*ca987d46SWarner Losh ** (jws) simplified the code a bit in hopes of appeasing Purify
771*ca987d46SWarner Losh **************************************************************************/
strincmp(char * cp1,char * cp2,FICL_UNS count)772*ca987d46SWarner Losh int strincmp(char *cp1, char *cp2, FICL_UNS count)
773*ca987d46SWarner Losh {
774*ca987d46SWarner Losh     int i = 0;
775*ca987d46SWarner Losh 
776*ca987d46SWarner Losh     for (; 0 < count; ++cp1, ++cp2, --count)
777*ca987d46SWarner Losh     {
778*ca987d46SWarner Losh         i = tolower(*cp1) - tolower(*cp2);
779*ca987d46SWarner Losh         if (i != 0)
780*ca987d46SWarner Losh             return i;
781*ca987d46SWarner Losh         else if (*cp1 == '\0')
782*ca987d46SWarner Losh             return 0;
783*ca987d46SWarner Losh     }
784*ca987d46SWarner Losh     return 0;
785*ca987d46SWarner Losh }
786*ca987d46SWarner Losh 
787*ca987d46SWarner Losh /**************************************************************************
788*ca987d46SWarner Losh                         s k i p S p a c e
789*ca987d46SWarner Losh ** Given a string pointer, returns a pointer to the first non-space
790*ca987d46SWarner Losh ** char of the string, or to the NULL terminator if no such char found.
791*ca987d46SWarner Losh ** If the pointer reaches "end" first, stop there. Pass NULL to
792*ca987d46SWarner Losh ** suppress this behavior.
793*ca987d46SWarner Losh **************************************************************************/
skipSpace(char * cp,char * end)794*ca987d46SWarner Losh char *skipSpace(char *cp, char *end)
795*ca987d46SWarner Losh {
796*ca987d46SWarner Losh     assert(cp);
797*ca987d46SWarner Losh 
798*ca987d46SWarner Losh     while ((cp != end) && isspace(*cp))
799*ca987d46SWarner Losh         cp++;
800*ca987d46SWarner Losh 
801*ca987d46SWarner Losh     return cp;
802*ca987d46SWarner Losh }
803*ca987d46SWarner Losh 
804*ca987d46SWarner Losh 
805