f2114379bf4bffb584ee7e01620f5b62ef5118fe
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimParser.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrimParser.c /main/2 1999/10/15 12:23:41 mgreess $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1996 Digital Equipment Corporation.                    *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #include <Xm/Xm.h>
40 #include "TermPrimDebug.h"
41 #include "TermPrimP.h"
42 #include "TermPrimParserP.h"
43 #include "TermPrimBuffer.h"
44
45 #if defined (__hpux)
46 /*
47  * On HP MAXINT is defined in both <values.h> and <sys/param.h>
48  */
49 #undef MAXINT
50 #endif
51 #if defined(CSRG_BASED)
52 #define MAXINT INT_MAX
53 #else
54 #include  <values.h>
55 #endif
56
57 #ifdef  BBA
58 #pragma BBA_IGNORE
59 #endif  /*BBA*/
60 static void
61 ParseTrap()
62 {
63     static int count = 0;
64
65     (void) count++;
66 }
67
68 /*
69 ** Parse the character, tell the calling routine if we are not
70 ** in the start state.
71 */
72 Boolean
73 _DtTermPrimParse
74 (
75     Widget          w,
76     unsigned char  *parseChar,
77     int             parseCharLen
78 )
79 {
80     ParserContext   context = GetParserContext(w);
81     StateEntry      thisEntry;
82     StateEntry      thisPreParseEntry;
83
84 #ifdef    NOCODE
85     /*
86     ** This decision should be made somewhere else.
87     */
88     if (tp->t_modes.disp_func == 1)
89     {
90         in_disp_func();
91         return(False);
92     }
93 #endif /* NOCODE */
94
95     if (parseCharLen == 1) {
96         *context->inputChar = *parseChar;
97     } else {
98         (void) memmove(context->inputChar, parseChar, parseCharLen);
99     }
100     context->inputCharLen = parseCharLen;
101
102     if (isDebugFSet('p', 1)) {
103 #ifdef  BBA
104 #pragma BBA_IGNORE
105 #endif  /*BBA*/
106         static unsigned char debugChar;
107         static Boolean first = True;
108         char *c;
109
110         if (parseCharLen == 1) {
111             _DtTermProcessLock();
112             if (first) {
113                 if (!(c = getenv("dttermDebugParseChar"))) {
114                     c = "0x03";
115                 }
116                 debugChar = strtol(c, (char **) 0, 0);
117                 first = False;
118             }
119             _DtTermProcessUnlock();
120
121             if (*parseChar == debugChar) {
122                 ParseTrap();
123                 return;
124             }
125         }
126     }
127         
128     /*
129     ** Determine which state entry to use.
130     */
131     thisPreParseEntry = context->stateTable->statePreParseEntry;
132     thisEntry = context->stateTable->stateEntry;
133
134     /* first run through the preParse entry... */
135     if (thisPreParseEntry && (parseCharLen == 1)) {
136         while ((*parseChar < thisPreParseEntry->lower) ||
137                 (*parseChar > thisPreParseEntry->upper)) {
138             thisPreParseEntry++;
139         }
140         /* if we hit the end, ignore it... */
141         if ((0x00 == thisPreParseEntry->lower) &&
142                 (0xff == thisPreParseEntry->upper)) {
143             thisPreParseEntry = (StateEntry) 0;
144         }
145     }
146
147     /* if we hit a valid preParseEntry, then let's execute it and
148      * return...
149      */
150     if (thisPreParseEntry) {
151         /*
152         ** Now change states.  If the next state is NULL, stay in the
153         ** current state.  This is for parse entries that do not break us
154         ** out of the current parse thread.  If we need to bail out of the
155         ** current parse thread, then we have a new state specified and
156         ** will switch to it.  We do this before we execute the function
157         ** incase the function needs to change the state as well...
158         */
159         if (thisPreParseEntry->nextState) {
160             context->stateTable = thisPreParseEntry->nextState;
161         }
162
163         /*
164         ** Execute the action associated with the entry.
165         */
166         if (thisPreParseEntry->action) {
167             (*thisPreParseEntry->action)(w);
168         }
169
170         return(!context->stateTable->startState);
171     }
172
173     /* HACK ALERT!!!!
174      *
175      * We need two different search algorithms - the first to deal
176      * with single byte characters, the second to deal with multi-byte
177      * characters.  For now, we will match multi-byte character with
178      * the parse entry that covers 0..255.  If we find that this will
179      * not work for everything, we may need to rethink this.
180      */
181     if (parseCharLen == 1) {
182         while ((*parseChar < thisEntry->lower) ||
183                 (*parseChar > thisEntry->upper))
184         {
185             thisEntry++;
186         }
187     } else {
188         while ((0x00 != thisEntry->lower) ||
189                 (0xff != thisEntry->upper))
190         {
191             thisEntry++;
192         }
193     }
194         
195     /*
196     ** Now change states.  We do this before we execute the function incase
197     ** the function needs to change the state as well...
198     */
199     context->stateTable = thisEntry->nextState;
200
201     /*
202     ** Execute the action associated with the entry.
203     */
204     if (thisEntry->action) {
205         (*thisEntry->action)(w);
206     }
207
208     return(!context->stateTable->startState);
209 }
210
211 /*
212 **
213 **  _DtTermPrimParserClrStrParm()
214 **
215 **  clrStrParm clears the string parameters.
216 **
217 */
218 void
219 _DtTermPrimParserClrStrParm
220 (
221     Widget w
222 )
223 {
224     ParserContext   context = GetParserContext(w);
225
226     context->stringParms[0].length = 0;
227     (void) memset(context->stringParms[0].str, 0x00, STR_SIZE + 1);
228
229     context->stringParms[1].length = 0;
230     (void) memset(context->stringParms[1].str, 0x00, STR_SIZE + 1);
231 }
232
233 /*
234 **
235 **  _DtTermPrimParserNextState()
236 **
237 **  nextState is a do nothing routine.  It is called when the only
238 **  action that needs to be preformed is changing states in the
239 **  state machine.
240 **
241 */
242 void
243 _DtTermPrimParserNextState
244 (
245     Widget w
246 )
247 {
248 }
249
250 /*
251 **
252 **  _DtTermPrimParserClearParm()
253 **
254 **  _DtTermPrimParserClearParm clears all common parameters.
255 **
256 */
257 void
258 _DtTermPrimParserClearParm
259 (
260     Widget w
261 )
262 {
263     ParserContext  context = GetParserContext(w);
264     int             i;
265
266     for (i = 0; i < NUM_PARMS; i++) {
267         context->parms[i] = 0;
268     }
269     context->workingNum = 0;
270     context->workingNumIsDefault = True;
271     context->sign = TermPARSER_SIGNnone;
272 }
273
274 /*
275 **
276 **  enterNum()
277 **
278 **  enterNum enters a numerical parameter.
279 **
280 */
281 void
282 _DtTermPrimParserEnterNum
283 (
284     Widget w
285 )
286 {
287     ParserContext   context = GetParserContext(w);
288
289     if ( context->workingNum < MAXINT>>4 ) 
290         context->workingNum = context->workingNum * 10 +
291             (*context->inputChar - '0');
292     context->workingNumIsDefault = False;
293 }
294
295 void
296 _DtTermPrimParserSaveSign
297 (
298     Widget w
299 )
300 {
301     ParserContext   context = GetParserContext(w);
302
303     SetSign(context, (*GetInputChar(context) == '-') ? TermPARSER_SIGNnegative :
304             TermPARSER_SIGNpositive);
305 }
306
307 /*
308 **
309 **  _DtTermPrimParserNumParmPush()
310 **
311 **  _DtTermPrimParserNumParmPush() takes the number in workingNum and 
312 **   stores it in parm[parmNum].
313 **
314 */
315 void
316 _DtTermPrimParserNumParmPush
317 (
318     Widget w,
319     int    parmNum
320 )
321 {
322     ParserContext   context = GetParserContext(w);
323
324     if ( parmNum < NUM_PARMS ) {
325       context->parms[parmNum] = context->workingNum;
326       context->workingNum     = 0;
327       context->workingNumIsDefault = False;
328     }
329 }
330
331 /*
332 ** Initialize the context of the parser.
333 */
334 void
335 _DtTermPrimParserInitContext
336 (
337     Widget w
338 )
339 {
340     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
341     DtTermPrimData tpd = tw->term.tpd;
342
343     tpd->context = (ParserContext) XtMalloc(sizeof(ParserContextRec));
344     (void) memset(tpd->context, '\0', sizeof(ParserContextRec));
345
346     tpd->context->stateTable =
347             *(((DtTermPrimitiveClassRec *) (tw->core.widget_class))->
348             term_primitive_class.parser_start_state);
349     tpd->context->stateName  = START;
350 }
351
352 #ifdef TEST
353
354 #include <ctype.h>
355
356 #define testFunction(f) \
357 void f ( Widget w ) {printf(#f " called.\n");}
358
359 int cursor_col, cursor_row;
360 int logical_col, logical_row;
361
362 testFunction(_termCR)
363 testFunction(_termLF)
364 testFunction(_termTab)
365 testFunction(_termBackspace)
366 testFunction(RecordDC1Rcvd)
367 testFunction(_termWriteChar)
368 testFunction(_DtTermPrimBell)
369 testFunction(_termShiftOut)
370 testFunction(_termShiftIn)
371 testFunction(set_tab)
372 testFunction(clear_tab)
373 testFunction(clr_all_tab)
374 testFunction(set_left_marg)
375 testFunction(set_right_marg)
376 testFunction(clear_marg)
377 testFunction(curs_up)
378 testFunction(curs_down)
379 testFunction(curs_right)
380 testFunction(curs_left)
381 testFunction(home_down)
382 testFunction(home_up)
383 testFunction(clr_display)
384 testFunction(clear_line)
385 testFunction(insert_line)
386 testFunction(delete_line)
387 testFunction(delete_char)
388 testFunction(insert_char)
389 testFunction(off_insert_char)
390 testFunction(roll_up)
391 testFunction(roll_down)
392 testFunction(next_page)
393 testFunction(prev_page)
394 testFunction(format_mode_on)
395 testFunction(format_mode_off)
396 testFunction(display_func)
397 testFunction(term_status)
398 testFunction(rel_curs_pos)
399 testFunction(abs_curs_pos)
400 testFunction(enable_key)
401 testFunction(disable_key)
402 testFunction(enter_line)
403 testFunction(back_tab)
404 testFunction(user_key_menu_on)
405 testFunction(user_key_menu_off)
406 testFunction(second_status)
407 testFunction(mlock_on)
408 testFunction(mlock_off)
409 testFunction(start_unprotect)
410 testFunction(stop_field)
411
412 void
413 _parserPrintContext
414 (
415     ParserContext   context
416 )
417 {
418     printf("    inputChar  : ");
419     if (isprint(*context->inputChar))
420     {
421         printf("'%c'\n", *context->inputChar);
422     }
423     else
424     {
425         printf("\x2X\n", *context->inputChar);
426     }
427     for (i = 0; i < 9; i++)
428     {
429         printf("    parm[%d]      : %d\n", i, context->parm[i]);
430     }
431     printf("    workingNum : %d\n", context->workingNum);
432 }
433
434 void
435 parseString
436 (
437     Widget          w;
438     unsigned char  *string
439 )
440 {
441     ParserContext   context = GetParserContext(w);
442     int i;
443
444     _parserPrintContext(context);
445     for (i = 0; i < strlen((char *)string); i++)
446     {
447         _DtTermPrimParse(context, string[i]);
448         _parserPrintContext(context);
449     }
450 }
451
452 /* the following is to allow for a single main function in the code... */
453 #define parserMain      main
454 parserMain()
455 {
456     parserContext   context;
457
458     _parserInitContext(&context);
459
460     cursor_col = 0;
461     cursor_row = 0;
462
463     logical_col = 5;
464     logical_row = 5;
465
466     printf("\nparsing <esc>&a5r5C\n");
467     parseString(&context, (unsigned char *)"\033&a5r5C");
468
469     printf("\nparsing <esc>a5r35C\n");
470     parseString(&context, (unsigned char *)"\033&a5r35C");
471
472     printf("\nparsing <esc>&a5r3r4c5C\n");
473     parseString(&context, (unsigned char *)"\033&a5r3r4c5C");
474
475     printf("\nparsing <esc>&arC\n");
476     parseString(&context, (unsigned char *)"\033&arC");
477
478     printf("\nparsing <esc>&a5C\n");
479     parseString(&context, (unsigned char *)"\033&a5C");
480
481     printf("\nparsing <esc>&a+5C\n");
482     parseString(&context, (unsigned char *)"\033&a+5C");
483 }
484 #endif /* TEST */