181 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*  $Id$
 | 
						|
 | 
						|
    Part of SWI-Prolog
 | 
						|
 | 
						|
    Author:        Jan Wielemaker
 | 
						|
    E-mail:        J.Wielemaker@uva.nl
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 1985-2008, University of Amsterdam
 | 
						|
 | 
						|
    This library is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU Lesser General Public
 | 
						|
    License as published by the Free Software Foundation; either
 | 
						|
    version 2.1 of the License, or (at your option) any later version.
 | 
						|
 | 
						|
    This library is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
    Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
						|
*/
 | 
						|
 | 
						|
#include "pl-incl.h"
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
Variable argument list:
 | 
						|
 | 
						|
	atom_t	name
 | 
						|
	int	type	OPT_ATOM, OPT_STRING, OPT_BOOL, OPT_INT, OPT_LONG
 | 
						|
	pointer	value
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
#define MAXOPTIONS 32
 | 
						|
 | 
						|
typedef union
 | 
						|
{ bool *b;				/* boolean value */
 | 
						|
  long *l;				/* long value */
 | 
						|
  int  *i;				/* integer value */
 | 
						|
  uintptr_t *sz;			/* size_t value */
 | 
						|
  char **s;				/* string value */
 | 
						|
  word *a;				/* atom value */
 | 
						|
  term_t *t;				/* term-reference */
 | 
						|
  void *ptr;				/* anonymous pointer */
 | 
						|
} optvalue;
 | 
						|
 | 
						|
 | 
						|
bool
 | 
						|
scan_options(term_t options, int flags, atom_t optype,
 | 
						|
	     const opt_spec *specs, ...)
 | 
						|
{ GET_LD
 | 
						|
  va_list args;
 | 
						|
  const opt_spec *s;
 | 
						|
  optvalue values[MAXOPTIONS];
 | 
						|
  term_t list = PL_copy_term_ref(options);
 | 
						|
  term_t head = PL_new_term_ref();
 | 
						|
  term_t tmp  = PL_new_term_ref();
 | 
						|
  term_t val  = PL_new_term_ref();
 | 
						|
  int n;
 | 
						|
 | 
						|
  if ( truePrologFlag(PLFLAG_ISO) )
 | 
						|
    flags |= OPT_ALL;
 | 
						|
 | 
						|
  va_start(args, specs);
 | 
						|
  for( n=0, s = specs; s->name; s++, n++ )
 | 
						|
    values[n].ptr = va_arg(args, void *);
 | 
						|
  va_end(args);
 | 
						|
 | 
						|
  while ( PL_get_list(list, head, list) )
 | 
						|
  { atom_t name;
 | 
						|
    int arity;
 | 
						|
 | 
						|
    if ( PL_get_name_arity(head, &name, &arity) )
 | 
						|
    { if ( name == ATOM_equals && arity == 2 )
 | 
						|
      { _PL_get_arg(1, head, tmp);
 | 
						|
 | 
						|
	if ( !PL_get_atom(tmp, &name) )
 | 
						|
	  goto itemerror;
 | 
						|
	_PL_get_arg(2, head, val);
 | 
						|
      } else if ( arity == 1 )
 | 
						|
      { _PL_get_arg(1, head, val);
 | 
						|
      } else if ( arity == 0 )
 | 
						|
	PL_put_atom(val, ATOM_true);
 | 
						|
    } else if ( PL_is_variable(head) )
 | 
						|
    { return PL_error(NULL, 0, NULL, ERR_INSTANTIATION);
 | 
						|
    } else
 | 
						|
    { itemerror:
 | 
						|
      return PL_error(NULL, 0, NULL, ERR_DOMAIN, optype, head);
 | 
						|
    }
 | 
						|
 | 
						|
    for( n=0, s = specs; s->name; n++, s++ )
 | 
						|
    { if ( s->name == name )
 | 
						|
      { switch((s->type & OPT_TYPE_MASK))
 | 
						|
	{ case OPT_BOOL:
 | 
						|
	  { atom_t aval;
 | 
						|
 | 
						|
	    if ( !PL_get_atom(val, &aval) )
 | 
						|
	      fail;
 | 
						|
	    if ( aval == ATOM_true || aval == ATOM_on )
 | 
						|
	      *values[n].b = TRUE;
 | 
						|
	    else if ( aval == ATOM_false || aval == ATOM_off )
 | 
						|
	      *values[n].b = FALSE;
 | 
						|
	    else
 | 
						|
	      goto itemerror;
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_INT:
 | 
						|
	  { if ( !PL_get_integer(val, values[n].i) )
 | 
						|
	      goto itemerror;
 | 
						|
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_LONG:
 | 
						|
	  { if ( !PL_get_long(val, values[n].l) )
 | 
						|
	    { if ( (s->type & OPT_INF) && PL_is_inf(val) )
 | 
						|
		*values[n].l = LONG_MAX;
 | 
						|
	      else
 | 
						|
		goto itemerror;
 | 
						|
	    }
 | 
						|
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_NATLONG:
 | 
						|
	  { if ( !PL_get_long(val, values[n].l) )
 | 
						|
	      goto itemerror;
 | 
						|
	    if ( *(values[n].l) <= 0 )
 | 
						|
	      return PL_error(NULL, 0, NULL, ERR_DOMAIN,
 | 
						|
			      ATOM_not_less_than_one, val);
 | 
						|
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_SIZE:
 | 
						|
	  { if ( !PL_get_uintptr(val, values[n].sz) )
 | 
						|
	    { if ( (s->type & OPT_INF) && PL_is_inf(val) )
 | 
						|
		*values[n].sz = (size_t)-1;
 | 
						|
	      else
 | 
						|
		goto itemerror;
 | 
						|
	    }
 | 
						|
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_STRING:
 | 
						|
	  { char *str;
 | 
						|
 | 
						|
	    if ( !PL_get_chars(val, &str, CVT_ALL) ) /* copy? */
 | 
						|
	      goto itemerror;
 | 
						|
	    *values[n].s = str;
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_ATOM:
 | 
						|
	  { atom_t a;
 | 
						|
 | 
						|
	    if ( !PL_get_atom(val, &a) )
 | 
						|
	      goto itemerror;
 | 
						|
	    *values[n].a = a;
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  case OPT_TERM:
 | 
						|
	  { *values[n].t = val;
 | 
						|
	    val = PL_new_term_ref();	/* can't reuse anymore */
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
	  default:
 | 
						|
	    assert(0);
 | 
						|
	    fail;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if ( !s->name && (flags & OPT_ALL) )
 | 
						|
      goto itemerror;
 | 
						|
  }
 | 
						|
 | 
						|
  if ( !PL_get_nil(list) )
 | 
						|
    return PL_error(NULL, 0, NULL, ERR_TYPE, ATOM_list, list);
 | 
						|
 | 
						|
  succeed;
 | 
						|
}
 |