Blame lib/Xm/Picture.c

Packit b099d7
/* 
Packit b099d7
 * Motif
Packit b099d7
 *
Packit b099d7
 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are free software; you can
Packit b099d7
 * redistribute them and/or modify them under the terms of the GNU
Packit b099d7
 * Lesser General Public License as published by the Free Software
Packit b099d7
 * Foundation; either version 2 of the License, or (at your option)
Packit b099d7
 * any later version.
Packit b099d7
 *
Packit b099d7
 * These libraries and programs are distributed in the hope that
Packit b099d7
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
Packit b099d7
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
Packit b099d7
 * PURPOSE. See the GNU Lesser General Public License for more
Packit b099d7
 * details.
Packit b099d7
 *
Packit b099d7
 * You should have received a copy of the GNU Lesser General Public
Packit b099d7
 * License along with these librararies and programs; if not, write
Packit b099d7
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
Packit b099d7
 * Floor, Boston, MA 02110-1301 USA
Packit b099d7
*/
Packit b099d7
Packit b099d7
#include <Xm/PictureP.h>
Packit b099d7
Packit b099d7
static XmPictureNode* _XiGetNewNode(XmPictureRec*);
Packit b099d7
static void _XmPictureParseNode(XmPictureRec*, char**, XmPictureNode**,
Packit b099d7
				XmPictureNode**, Boolean);
Packit b099d7
static XmPictureTransition* _XiGetNewTransition(XmTransType,
Packit b099d7
						XmPictureNode*,
Packit b099d7
						XmPictureNode*);
Packit b099d7
static void _XmPictureSetState(unsigned char*, int);
Packit b099d7
static char _XmPictureGetState(unsigned char*, int);
Packit b099d7
static void _XmPictureFollowTransitions(XmPictureStateRec*, char, XmPictureNode*);
Packit b099d7
static XmPictureNode *_XmPictureCopySubGraph(XmPictureRec*, int,
Packit b099d7
					     XmPictureNode*, XmPictureNode*);
Packit b099d7
static void _XmPictureTagNodes(XmPictureRec*, XmPictureNode**, int);
Packit b099d7
static void _XmPictureFillTraverse(XmPictureRec*, int, XmAutoFill*);
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Parses the given string into an XmPicture object.  Returns NULL on a
Packit b099d7
 * mal-formed picture
Packit b099d7
 */
Packit b099d7
XmPicture
Packit b099d7
XmParsePicture(char *input)
Packit b099d7
{
Packit b099d7
    XmPictureRec *picture;
Packit b099d7
    XmPictureNode *root_node;
Packit b099d7
    XmPictureNode *end_node;
Packit b099d7
Packit b099d7
    picture = XtNew(XmPictureRec);
Packit b099d7
Packit b099d7
    picture->source = XtNewString(input);
Packit b099d7
    picture->num_nodes = 0;
Packit b099d7
    picture->nodes_alloced = NODE_START_COUNT;
Packit b099d7
    picture->nodes = (XmPictureNode**)
Packit b099d7
	             XtMalloc(NODE_START_COUNT * sizeof(XmPictureNode*));
Packit b099d7
Packit b099d7
    _XmPictureParseNode(picture, &input, &root_node, &end_node, False);
Packit b099d7
Packit b099d7
    picture->start_node = root_node->index;
Packit b099d7
    picture->final_node = end_node->index;
Packit b099d7
    
Packit b099d7
    return picture;
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Creates a new XmPictureState.  The memory allocated must be freed by the
Packit b099d7
 * user with XtFree()
Packit b099d7
 */
Packit b099d7
XmPictureState
Packit b099d7
XmGetNewPictureState(XmPicture picture)
Packit b099d7
{
Packit b099d7
    int i;
Packit b099d7
    XmPictureStateRec *state;
Packit b099d7
Packit b099d7
    state = XtNew(XmPictureStateRec);
Packit b099d7
Packit b099d7
    state->statesize = 1 + (picture->num_nodes * sizeof(char) / 8);
Packit b099d7
Packit b099d7
    state->picture = picture;
Packit b099d7
Packit b099d7
    state->state = (unsigned char*) XtMalloc(state->statesize);
Packit b099d7
    state->newstate = (unsigned char*) XtMalloc(state->statesize);
Packit b099d7
    for(i=0; i<state->statesize; i++) {
Packit b099d7
	state->state[i] = 0;
Packit b099d7
	state->newstate[i] = 0;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    _XmPictureSetState(state->state, picture->start_node);
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * BAD BAD BAD HACK
Packit b099d7
     * This just allocates a static 1024 character array.  While this will
Packit b099d7
     * be fine for the DataField, because only one state per widget will
Packit b099d7
     * be allocated and because the strings will never get that long,
Packit b099d7
     * this makes this library useless for generalized database stuff.
Packit b099d7
     * DON'T attempt to make lots of these or use them for very long
Packit b099d7
     * regexps until I get this fixed -- Andy
Packit b099d7
     * Sigh, additionally, this is a security problem.  Feeding this
Packit b099d7
     * thing very long RE's and strings will therefore make the
Packit b099d7
     * program crash, which is not something our customers want
Packit b099d7
     */
Packit b099d7
    state->current_string = XtMalloc(1024 * sizeof(char));
Packit b099d7
    state->current_string[0] = '\0';
Packit b099d7
    state->append = state->current_string;
Packit b099d7
Packit b099d7
    return state;
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Processes a single character.  Returns a pointer to the current
Packit b099d7
 * value of the string (which may have been auto-filled, if
Packit b099d7
 * do_auto_fill is specified).  If the current state vector contains
Packit b099d7
 * the final state, it places True in is_finished, otherwise False.
Packit b099d7
 */
Packit b099d7
char*
Packit b099d7
XmPictureProcessCharacter(XmPictureState state, char in, Boolean *is_finished)
Packit b099d7
{
Packit b099d7
    int i;
Packit b099d7
    char status;
Packit b099d7
    unsigned char *temp;
Packit b099d7
    char *save_start;
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Reset the current-processing info
Packit b099d7
     */
Packit b099d7
    state->current = '\0';
Packit b099d7
    state->upcase  = False;
Packit b099d7
    for(i=0; i<state->statesize; i++)
Packit b099d7
	state->newstate[i] = 0;
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * For each node in the state set, try to follow all transitions
Packit b099d7
     * (recursing on NullTransitions of course)
Packit b099d7
     */    
Packit b099d7
    for(i=0; i<state->picture->num_nodes; i++) {
Packit b099d7
	if(_XmPictureGetState(state->state, i)) {
Packit b099d7
	    _XmPictureFollowTransitions(state, in, state->picture->nodes[i]);
Packit b099d7
	}
Packit b099d7
    }
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Swap the states
Packit b099d7
     */
Packit b099d7
    temp = state->state;
Packit b099d7
    state->state = state->newstate;
Packit b099d7
    state->newstate = temp;
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Append whatever we accepted (which might have been upcased)
Packit b099d7
     */
Packit b099d7
    save_start = state->append;
Packit b099d7
    if(state->current) {
Packit b099d7
	*state->append = state->current;
Packit b099d7
	state->append++;
Packit b099d7
	*state->append = '\0';
Packit b099d7
    }
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * If we didn't find _any_ transitions, return NULL
Packit b099d7
     */
Packit b099d7
    for(i=0; i<state->statesize; i++)
Packit b099d7
	if(state->state[i] != 0)
Packit b099d7
	    break;
Packit b099d7
    if(i == state->statesize) {
Packit b099d7
	*is_finished = True;
Packit b099d7
	return NULL;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * If our set contains the final state, set is_finished to true
Packit b099d7
     */
Packit b099d7
    status = _XmPictureGetState(state->state, state->picture->final_node);
Packit b099d7
    if(status) *is_finished = True;
Packit b099d7
    else *is_finished = False;
Packit b099d7
Packit b099d7
    return save_start;
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
XmPictureDelete(XmPicture p)
Packit b099d7
{
Packit b099d7
    int i;
Packit b099d7
    XmPictureTransition *trans, *delete_me;
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * First walk all the nodes, deleting the transitions then the
Packit b099d7
     * nodes themselves
Packit b099d7
     */
Packit b099d7
    for(i=0; i<p->num_nodes; i++) {
Packit b099d7
	trans = p->nodes[i]->transitions;
Packit b099d7
	while(trans) {
Packit b099d7
	    delete_me = trans;
Packit b099d7
	    trans = trans->next;
Packit b099d7
	    XtFree((char*)delete_me);
Packit b099d7
	}
Packit b099d7
	XtFree((char*)p->nodes[i]);
Packit b099d7
    }
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Now the node table and finally the picture itself
Packit b099d7
     */
Packit b099d7
    XtFree((char*)p->nodes);
Packit b099d7
    XtFree(p->source);
Packit b099d7
    XtFree((char*)p);
Packit b099d7
}
Packit b099d7
Packit b099d7
void
Packit b099d7
XmPictureDeleteState(XmPictureState s)
Packit b099d7
{
Packit b099d7
    XtFree(s->current_string);
Packit b099d7
    XtFree((char*)s->state);
Packit b099d7
    XtFree((char*)s->newstate);
Packit b099d7
    XtFree((char*)s);
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
char*
Packit b099d7
XmPictureGetCurrentString(XmPictureState s)
Packit b099d7
{
Packit b099d7
    return s->current_string;
Packit b099d7
}
Packit b099d7
Packit b099d7
char*
Packit b099d7
XmPictureDoAutoFill(XmPictureState state)
Packit b099d7
{
Packit b099d7
    XmAutoFill fill;
Packit b099d7
    int i;
Packit b099d7
    Boolean finished = False;
Packit b099d7
Packit b099d7
    while(1) {
Packit b099d7
Packit b099d7
	fill.reject = False;
Packit b099d7
	fill.c      = '\0';
Packit b099d7
	fill.digit  = False;
Packit b099d7
	fill.upcase = False;
Packit b099d7
	fill.letter = False;
Packit b099d7
	fill.hexdigit = False;
Packit b099d7
	fill.octaldigit = False;
Packit b099d7
Packit b099d7
	for(i=0; i<state->picture->num_nodes; i++)
Packit b099d7
	    if(_XmPictureGetState(state->state, i))
Packit b099d7
		_XmPictureFillTraverse(state->picture, i, &fill;;
Packit b099d7
Packit b099d7
	if(fill.c == '\0')
Packit b099d7
	    fill.reject = True;
Packit b099d7
	if(fill.digit && (isdigit(fill.c) == 0))
Packit b099d7
	    fill.reject = True;
Packit b099d7
	if(fill.hexdigit && (isxdigit(fill.c) == 0))
Packit b099d7
	    fill.reject = True;
Packit b099d7
	if(fill.octaldigit && (fill.c < '0' || fill.c > '7'))
Packit b099d7
	    fill.reject = True;
Packit b099d7
	if(fill.letter && (isalpha(fill.c) == 0))
Packit b099d7
	    fill.reject = True;
Packit b099d7
	if(fill.upcase && islower(fill.c))
Packit b099d7
	    fill.reject = True;
Packit b099d7
Packit b099d7
	if(fill.reject) return state->current_string;
Packit b099d7
Packit b099d7
	XmPictureProcessCharacter(state, fill.c, &finished);
Packit b099d7
Packit b099d7
	if(finished) return state->current_string;
Packit b099d7
    }
Packit b099d7
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Parses a single "node" of the regular expression.  If returnNOW is true,
Packit b099d7
 * this means only the very first complete RE encountered (a hack, to allow
Packit b099d7
 * for the weird closure precedence:  *ab should parse like {*a}b and not
Packit b099d7
 * *{ab}), otherwise it reads until the end of the RE, be it a close brace
Packit b099d7
 * or EOS.
Packit b099d7
 */
Packit b099d7
static void
Packit b099d7
_XmPictureParseNode(XmPictureRec *picture, char **in_string,
Packit b099d7
		    XmPictureNode **start_return,
Packit b099d7
		    XmPictureNode **end_return,
Packit b099d7
		    Boolean returnNOW)
Packit b099d7
{
Packit b099d7
    XmPictureNode *start_node;
Packit b099d7
    XmPictureNode *current_node;
Packit b099d7
    XmPictureNode *start_node_2;
Packit b099d7
    XmPictureNode *current_node_2;
Packit b099d7
    XmPictureNode *newnode;
Packit b099d7
    int node_idx;
Packit b099d7
    XmPictureTransition *newtrans;
Packit b099d7
    char inc;
Packit b099d7
    int count;
Packit b099d7
    char *endcount;
Packit b099d7
Packit b099d7
    start_node = _XiGetNewNode(picture);
Packit b099d7
    node_idx = start_node->index;
Packit b099d7
    current_node = start_node;
Packit b099d7
Packit b099d7
    while((inc = *((*in_string)++))) {
Packit b099d7
	switch(inc) {
Packit b099d7
	    /*
Packit b099d7
	     * These are the "normal" single-character tokens that
Packit b099d7
	     * behave (more or less) like literals in the state
Packit b099d7
	     * machine.
Packit b099d7
	     */
Packit b099d7
	case NUMDIGIT:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(NumericDigit,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case HEXDIGIT:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(HexDigit,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case OCTALDIGIT:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(OctalDigit,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case NONCASELETTER:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(AnyLetter,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case UPCASELETTER:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(UpCaseLetter,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case NONCASECHAR:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(AnyCharacter,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	case UPCASECHAR:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(UpCaseCharacter,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * The weird stuff.
Packit b099d7
	     */
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * Read a numeric specifier, if it exists, then read the
Packit b099d7
	     * next _single_ R.E. (i.e., not a string of concatenated
Packit b099d7
	     * ones!); Add a transition from the current end state to the
Packit b099d7
	     * end (!) state of the new closure states, and a transition
Packit b099d7
	     * from that end to it's beginning.
Packit b099d7
	     */
Packit b099d7
	case CLOSURE: /* CR03602 picture should formatted to *nx;
Packit b099d7
			n is no. of time repeat; x is the specified
Packit b099d7
			character going to be display */
Packit b099d7
	    count = strtol(*in_string, &endcount, 0);
Packit b099d7
	    if(count)
Packit b099d7
		*in_string = endcount;		
Packit b099d7
	    _XmPictureParseNode(picture, in_string,
Packit b099d7
				&start_node_2, &current_node_2,
Packit b099d7
				True);
Packit b099d7
	    if(count) {
Packit b099d7
		newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					       current_node, start_node_2);
Packit b099d7
		current_node = _XmPictureCopySubGraph(picture, count-1,
Packit b099d7
						      start_node_2,
Packit b099d7
						      current_node_2);
Packit b099d7
	    } else {
Packit b099d7
		newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					       current_node_2, start_node_2);
Packit b099d7
		newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					       current_node, current_node_2);
Packit b099d7
		
Packit b099d7
		current_node = current_node_2;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * Read the next (NOT singleton, this time) R.E.; create a _new_
Packit b099d7
	     * initial state which has null-transitions to both the
Packit b099d7
	     * current and new R.E.'s, and a new final state to which
Packit b099d7
	     * both trails lead.
Packit b099d7
	     */
Packit b099d7
	case ALTERNATIVE: /* CR03656 CR03359 a major overhaul */
Packit b099d7
	    _XmPictureParseNode(picture, in_string,
Packit b099d7
				&start_node_2, &current_node_2,
Packit b099d7
				True);
Packit b099d7
            newtrans = _XiGetNewTransition(NullTransition, current_node,
Packit b099d7
					   current_node_2);
Packit b099d7
            if (current_node->index)
Packit b099d7
              picture->nodes[current_node->index - 1]->transitions->next =
Packit b099d7
		start_node_2->transitions;
Packit b099d7
            current_node = current_node_2;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * This actually is a special case of ALTERNATIVE.  The
Packit b099d7
	     * stuff inside the brackets becomes one chain, and a
Packit b099d7
	     * null-transition becomes the second.  Just read the
Packit b099d7
	     * (NON-singleton) RE until the close-bracket.
Packit b099d7
	     */
Packit b099d7
	case LBRACKET:
Packit b099d7
	    _XmPictureParseNode(picture, in_string,
Packit b099d7
				&start_node_2, &current_node_2,
Packit b099d7
				False);
Packit b099d7
	    
Packit b099d7
	    newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					   current_node, current_node_2);
Packit b099d7
	    newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					   current_node, start_node_2);
Packit b099d7
Packit b099d7
	    current_node = current_node_2;
Packit b099d7
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * The easiest special case to handle.  Just read a
Packit b099d7
	     * non-singleton R.E. until the close-brace and stick it
Packit b099d7
	     * in as a "literal".
Packit b099d7
	     */
Packit b099d7
	case LBRACE:
Packit b099d7
	    _XmPictureParseNode(picture, in_string,
Packit b099d7
				&start_node_2, &current_node_2,
Packit b099d7
				False);
Packit b099d7
Packit b099d7
	    newtrans = _XiGetNewTransition(NullTransition,
Packit b099d7
					   current_node, start_node_2);
Packit b099d7
	    
Packit b099d7
	    current_node = current_node_2;
Packit b099d7
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * Deal with both end-of-subexpression tokens in the same
Packit b099d7
	     * way.  This will accept stuff like {...] and [...}, but that's
Packit b099d7
	     * probably OK, since it will only parse stuff incorrectly
Packit b099d7
	     * for things like: [...{...]...} which aren't legal
Packit b099d7
	     * anyway.  I.E., we accept a superset of legal pictures,
Packit b099d7
	     * but parse all legal pictures correctly.
Packit b099d7
	     */
Packit b099d7
	case RBRACE:
Packit b099d7
	case RBRACKET:
Packit b099d7
	    returnNOW = True;
Packit b099d7
	    break;
Packit b099d7
	    
Packit b099d7
	    /*
Packit b099d7
	     * Special case handling for the ';' escape character.
Packit b099d7
	     * Make sure dumb users haven't escaped the end of the string
Packit b099d7
	     * then advance the pointer and fall through to the (default)
Packit b099d7
	     * handling for a literal.
Packit b099d7
	     */
Packit b099d7
	case ESCAPE:
Packit b099d7
	    inc = **in_string;
Packit b099d7
	    if(inc == '\0') break;
Packit b099d7
	    else (*in_string)++;
Packit b099d7
	    /*
Packit b099d7
	     * It's not a special character, so it must be a literal
Packit b099d7
	     */
Packit b099d7
	default:
Packit b099d7
	    newnode = _XiGetNewNode(picture);
Packit b099d7
	    newtrans = _XiGetNewTransition(LiteralCharacter,
Packit b099d7
					   current_node, newnode);
Packit b099d7
	    newtrans->c = inc;
Packit b099d7
	    current_node = newnode;
Packit b099d7
	    break;
Packit b099d7
	}
Packit b099d7
Packit b099d7
	/*
Packit b099d7
	 * Break out if we have to
Packit b099d7
	 */
Packit b099d7
	if(returnNOW == True) break;
Packit b099d7
    }
Packit b099d7
    *start_return = start_node;
Packit b099d7
    *end_return = current_node;
Packit b099d7
}
Packit b099d7
Packit b099d7
static XmPictureTransition*
Packit b099d7
_XiGetNewTransition(XmTransType type,
Packit b099d7
		    XmPictureNode *src, XmPictureNode *dest)
Packit b099d7
{
Packit b099d7
    XmPictureTransition *t = XtNew(XmPictureTransition);
Packit b099d7
    t->destination = dest->index;
Packit b099d7
    t->type = type;
Packit b099d7
    t->next = src->transitions;
Packit b099d7
    src->transitions = t;
Packit b099d7
    return t;
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Allocates a new state machine node
Packit b099d7
 */
Packit b099d7
static XmPictureNode*
Packit b099d7
_XiGetNewNode(XmPictureRec *picture)
Packit b099d7
{
Packit b099d7
    XmPictureNode *new_node;
Packit b099d7
Packit b099d7
    new_node = XtNew(XmPictureNode);
Packit b099d7
    new_node->transitions = NULL;
Packit b099d7
    new_node->index = picture->num_nodes++;
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Handle growing the picture past it's boundary
Packit b099d7
     */
Packit b099d7
    if(picture->num_nodes > picture->nodes_alloced) {
Packit b099d7
	int newsize = picture->nodes_alloced * 2;
Packit b099d7
Packit b099d7
	picture->nodes = (XmPictureNode**)
Packit b099d7
	                 XtRealloc((char*)picture->nodes,
Packit b099d7
				   newsize * sizeof(XmPictureNode*));
Packit b099d7
	picture->nodes_alloced = newsize;
Packit b099d7
    }
Packit b099d7
Packit b099d7
    picture->nodes[new_node->index] = new_node;
Packit b099d7
Packit b099d7
    return new_node;
Packit b099d7
}
Packit b099d7
Packit b099d7
static void
Packit b099d7
_XmPictureSetState(unsigned char *v, int i)
Packit b099d7
{
Packit b099d7
    int base = i / 8;
Packit b099d7
    int offset = i % 8;
Packit b099d7
Packit b099d7
    v[base] |= 1 << offset;
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Do I need this at all?
Packit b099d7
 *
Packit b099d7
static void
Packit b099d7
_XmPictureClearState(char *v, int i)
Packit b099d7
{
Packit b099d7
    int base = i / 8;
Packit b099d7
    int offset = i % 8;
Packit b099d7
Packit b099d7
    v[base] &= ~(1 << offset);
Packit b099d7
}
Packit b099d7
*/
Packit b099d7
Packit b099d7
static char
Packit b099d7
_XmPictureGetState(unsigned char *v, int i)
Packit b099d7
{
Packit b099d7
    int base = i / 8;
Packit b099d7
    int offset = i % 8;
Packit b099d7
    int result = v[base] & (1 << offset);
Packit b099d7
Packit b099d7
    if(result) return 1;
Packit b099d7
    else return 0;
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * The inc parameter gets set to '\0' if we are following a null
Packit b099d7
 * transition after already having read the character.
Packit b099d7
 */
Packit b099d7
static void
Packit b099d7
_XmPictureFollowTransitions(XmPictureStateRec *state, char inc,
Packit b099d7
			    XmPictureNode *node)
Packit b099d7
{
Packit b099d7
    XmPictureTransition *curr = node->transitions;
Packit b099d7
    char follow_c, changed_c;
Packit b099d7
    Boolean found = False;
Packit b099d7
    Boolean accepted = True;
Packit b099d7
Packit b099d7
    while(curr) {
Packit b099d7
	follow_c = '\0';
Packit b099d7
	changed_c = '\0';
Packit b099d7
	switch(curr->type) {
Packit b099d7
	case NullTransition:
Packit b099d7
	    follow_c = inc;
Packit b099d7
	    found = True;
Packit b099d7
	    if(inc != '\0')
Packit b099d7
		accepted = False;
Packit b099d7
	    break;
Packit b099d7
	case NumericDigit:
Packit b099d7
	    if(isdigit(inc)) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case HexDigit:
Packit b099d7
	    if(isdigit(inc) ||
Packit b099d7
		(inc >= 'a' && inc <= 'f') ||
Packit b099d7
		(inc >= 'A' && inc <= 'F')) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case OctalDigit:
Packit b099d7
	    if((inc >= '0') && (inc <= '7')) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case AnyLetter:
Packit b099d7
	    if(isalpha(inc)) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case UpCaseLetter:
Packit b099d7
	    if(isalpha(inc)) {
Packit b099d7
		changed_c = toupper(inc);
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case AnyCharacter:
Packit b099d7
	    if(isalnum(inc)) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case UpCaseCharacter:
Packit b099d7
	    if(isalnum(inc)) {
Packit b099d7
		changed_c = toupper(inc);
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	case LiteralCharacter:
Packit b099d7
	    if(inc == curr->c) {
Packit b099d7
		found = True;
Packit b099d7
	    }
Packit b099d7
	    break;
Packit b099d7
	}
Packit b099d7
Packit b099d7
	if(found) {
Packit b099d7
	    if(changed_c) {
Packit b099d7
		state->current = changed_c;
Packit b099d7
	    } else if(inc) {
Packit b099d7
		state->current = inc;
Packit b099d7
	    }
Packit b099d7
	    if(accepted)
Packit b099d7
		_XmPictureSetState(state->newstate, curr->destination);
Packit b099d7
	    _XmPictureFollowTransitions(state, follow_c,
Packit b099d7
					state->picture
Packit b099d7
					  ->nodes[curr->destination]);
Packit b099d7
	}
Packit b099d7
	found = False;
Packit b099d7
	curr = curr->next;
Packit b099d7
    }
Packit b099d7
}
Packit b099d7
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Recursively traverses a subgraph, tagging all indices in table with
Packit b099d7
 * a non-null value.
Packit b099d7
 */
Packit b099d7
static void
Packit b099d7
_XmPictureTagNodes(XmPictureRec *picture, XmPictureNode **table, int start)
Packit b099d7
{
Packit b099d7
    XmPictureTransition *trans = picture->nodes[start]->transitions;
Packit b099d7
Packit b099d7
    table[start] = (XmPictureNode*)0x1;
Packit b099d7
Packit b099d7
    while(trans) {
Packit b099d7
	_XmPictureTagNodes(picture, table, trans->destination);
Packit b099d7
	trans = trans->next;
Packit b099d7
    }
Packit b099d7
}
Packit b099d7
Packit b099d7
/*
Packit b099d7
 * Makes a string of n copies of the subgraph indicated, chaining them
Packit b099d7
 * end-to-end.  It returns the new end node for the multiplied
Packit b099d7
 * subgraph (the start node is the unchanged, of course)
Packit b099d7
 */
Packit b099d7
static XmPictureNode*
Packit b099d7
_XmPictureCopySubGraph(XmPictureRec *picture, int n,
Packit b099d7
		       XmPictureNode *start, XmPictureNode *end)
Packit b099d7
{
Packit b099d7
    XmPictureNode **table;
Packit b099d7
    XmPictureTransition *trans, *newtrans;
Packit b099d7
    int i, j, tablesize, end_index;
Packit b099d7
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Bail if the user did a repeat count of 1
Packit b099d7
     */
Packit b099d7
    if(n < 1) return end;
Packit b099d7
    
Packit b099d7
    /*
Packit b099d7
     * First allocate a pointer array of the same size as the current
Packit b099d7
     * picture.  This will hold NULL for nodes not in the subgraph and
Packit b099d7
     * the XmPictureNode for the newest copy.
Packit b099d7
     */
Packit b099d7
    tablesize = picture->num_nodes;
Packit b099d7
    table = (XmPictureNode**)
Packit b099d7
	    XtMalloc(tablesize * sizeof(XmPictureNode*));
Packit b099d7
    for(i=0; i<picture->num_nodes; i++)
Packit b099d7
	table[i] = NULL;
Packit b099d7
    
Packit b099d7
    /*
Packit b099d7
     * Now recursively tag the ones in our subgraph with non-NULL
Packit b099d7
     * values
Packit b099d7
     */
Packit b099d7
    _XmPictureTagNodes(picture, table, start->index);
Packit b099d7
Packit b099d7
    /*
Packit b099d7
     * Now loop:  for each non-NULL, allocate a new node in its
Packit b099d7
     * place; then go through each transition from the _original_
Packit b099d7
     * nodes, and put equivalent ones in the new table's nodes.
Packit b099d7
     * Finally chain it to the end of the previous node.
Packit b099d7
     */
Packit b099d7
    end_index = end->index;
Packit b099d7
    for(i=0; i
Packit b099d7
Packit b099d7
	/* Allocate the new nodes */
Packit b099d7
	for(j=0; j
Packit b099d7
	    if(table[j]) table[j] = _XiGetNewNode(picture);
Packit b099d7
Packit b099d7
	/* Fill them in */
Packit b099d7
	for(j=0; j
Packit b099d7
	    if(table[j]) {
Packit b099d7
		trans = picture->nodes[j]->transitions;
Packit b099d7
		while(trans) {
Packit b099d7
		    /*
Packit b099d7
		     * Hack to make sure we don't follow transitions
Packit b099d7
                     * into the newly created nodes
Packit b099d7
		     */
Packit b099d7
		    if(trans->destination >= tablesize) {
Packit b099d7
			trans = trans->next;
Packit b099d7
			continue;
Packit b099d7
		    }
Packit b099d7
Packit b099d7
		    newtrans = _XiGetNewTransition(trans->type,
Packit b099d7
						   table[j],
Packit b099d7
						   table[trans->destination]);
Packit b099d7
		    newtrans->c = trans->c;
Packit b099d7
		    trans = trans->next;
Packit b099d7
		}
Packit b099d7
	    }
Packit b099d7
	}
Packit b099d7
Packit b099d7
	_XiGetNewTransition(NullTransition, end, table[start->index]);
Packit b099d7
	end = table[end_index];
Packit b099d7
    }
Packit b099d7
    
Packit b099d7
    XtFree((void*)table);
Packit b099d7
Packit b099d7
    return end;
Packit b099d7
}
Packit b099d7
Packit b099d7
static void
Packit b099d7
_XmPictureFillTraverse(XmPictureRec *picture, int start, XmAutoFill *fill)
Packit b099d7
{
Packit b099d7
    XmPictureTransition *trans = picture->nodes[start]->transitions;
Packit b099d7
Packit b099d7
    while(trans) {
Packit b099d7
	switch(trans->type) {
Packit b099d7
	case NullTransition:
Packit b099d7
	    _XmPictureFillTraverse(picture, trans->destination, fill);
Packit b099d7
	    break;
Packit b099d7
	case NumericDigit:
Packit b099d7
	    fill->digit = True;
Packit b099d7
	    break;
Packit b099d7
	case HexDigit:
Packit b099d7
	    fill->hexdigit = True;
Packit b099d7
	    break;
Packit b099d7
	case OctalDigit:
Packit b099d7
	    fill->octaldigit = True;
Packit b099d7
	    break;
Packit b099d7
	case AnyLetter:
Packit b099d7
	    fill->letter = True;
Packit b099d7
	    break;
Packit b099d7
	case UpCaseLetter:
Packit b099d7
	    fill->letter = True;
Packit b099d7
	    fill->upcase = True;
Packit b099d7
	    break;
Packit b099d7
	case UpCaseCharacter:
Packit b099d7
	    fill->upcase = True;
Packit b099d7
	    break;
Packit b099d7
	case LiteralCharacter:
Packit b099d7
	    if(fill->c == '\0')
Packit b099d7
		fill->c = trans->c;
Packit b099d7
	    else if(fill->c != trans->c)
Packit b099d7
		fill->reject = True;
Packit b099d7
	    break;
Packit b099d7
	    /* gr... AnyCharacter isn't handled, and gcc issues a warning. */
Packit b099d7
	default:
Packit b099d7
	    break;
Packit b099d7
	}
Packit b099d7
	trans = trans->next;
Packit b099d7
    }
Packit b099d7
}
Packit b099d7
Packit b099d7
#ifdef DEBUG
Packit b099d7
static void
Packit b099d7
_XiPrintStateVector(XmPictureStateRec *state)
Packit b099d7
{
Packit b099d7
    int i;
Packit b099d7
    char c;
Packit b099d7
Packit b099d7
    for(i=0; i<state->picture->num_nodes; i++) {
Packit b099d7
	if(_XmPictureGetState(state->state, i))
Packit b099d7
	    c = '1';
Packit b099d7
	else
Packit b099d7
	    c = '0';
Packit b099d7
	printf("%c", c);
Packit b099d7
    }
Packit b099d7
    printf("\n");
Packit b099d7
}
Packit b099d7
#endif