145 lines
3.6 KiB
C
145 lines
3.6 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-2011, 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"
|
||
|
#include "pl-codelist.h"
|
||
|
|
||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
codes_or_chars_to_buffer(term_t l, unsigned int flags, int wide, CVT_code *status)
|
||
|
|
||
|
If l represents a list of codes or characters, return a buffer holding
|
||
|
the characters. If wide == TRUE the buffer contains objects of type
|
||
|
pl_wchar_t. Otherwise it contains traditional characters.
|
||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
Buffer
|
||
|
codes_or_chars_to_buffer(term_t l, unsigned int flags, int wide, CVT_result *result)
|
||
|
{ GET_LD
|
||
|
Buffer b;
|
||
|
word list = valHandle(l);
|
||
|
word slow;
|
||
|
Word arg, tail;
|
||
|
int step_slow = TRUE;
|
||
|
enum { CHARS, CODES } type;
|
||
|
|
||
|
if ( isList(list) )
|
||
|
{ intptr_t c = -1;
|
||
|
|
||
|
arg = argTermP(list, 0);
|
||
|
deRef(arg);
|
||
|
|
||
|
if ( isTaggedInt(*arg) )
|
||
|
{ c = valInt(*arg);
|
||
|
type = CODES;
|
||
|
} else
|
||
|
{ c = charCode(*arg);
|
||
|
type = CHARS;
|
||
|
}
|
||
|
|
||
|
result->culprit = *arg;
|
||
|
if ( c < 0 || (!wide && c > 0xff) )
|
||
|
{ if ( canBind(*arg) )
|
||
|
result->status = CVT_partial;
|
||
|
else if ( c < 0 )
|
||
|
result->status = CVT_nocode;
|
||
|
else if ( c > 0xff )
|
||
|
result->status = CVT_wide;
|
||
|
return NULL;
|
||
|
}
|
||
|
} else if ( isNil(list) )
|
||
|
{ return findBuffer(flags);
|
||
|
} else
|
||
|
{ if ( canBind(list) )
|
||
|
result->status = CVT_partial;
|
||
|
else
|
||
|
result->status = CVT_nolist;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
b = findBuffer(flags);
|
||
|
|
||
|
slow = list;
|
||
|
while( isList(list) )
|
||
|
{ intptr_t c = -1;
|
||
|
|
||
|
arg = argTermP(list, 0);
|
||
|
deRef(arg);
|
||
|
|
||
|
switch(type)
|
||
|
{ case CODES:
|
||
|
if ( isTaggedInt(*arg) )
|
||
|
c = valInt(*arg);
|
||
|
break;
|
||
|
case CHARS:
|
||
|
c = charCode(*arg);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( c < 0 || (!wide && c > 0xff) )
|
||
|
{ result->culprit = *arg;
|
||
|
|
||
|
unfindBuffer(flags); /* TBD: check unicode range */
|
||
|
if ( canBind(*arg) )
|
||
|
result->status = CVT_partial;
|
||
|
else if ( c < 0 )
|
||
|
result->status = (type == CODES ? CVT_nocode : CVT_nochar);
|
||
|
else if ( c > 0xff )
|
||
|
result->status = CVT_wide;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if ( wide )
|
||
|
addBuffer(b, (pl_wchar_t)c, pl_wchar_t);
|
||
|
else
|
||
|
addBuffer(b, (unsigned char)c, unsigned char);
|
||
|
|
||
|
tail = argTermP(list, 1);
|
||
|
deRef(tail);
|
||
|
list = *tail;
|
||
|
if ( list == slow ) /* cyclic */
|
||
|
{ unfindBuffer(flags);
|
||
|
result->status = CVT_nolist;
|
||
|
return NULL;
|
||
|
}
|
||
|
if ( (step_slow = !step_slow) )
|
||
|
{ tail = argTermP(slow, 1);
|
||
|
deRef(tail);
|
||
|
slow = *tail;
|
||
|
}
|
||
|
}
|
||
|
if ( !isNil(list) )
|
||
|
{ unfindBuffer(flags);
|
||
|
if ( canBind(list) )
|
||
|
result->status = CVT_partial;
|
||
|
else
|
||
|
result->status = CVT_nolist;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
result->status = CVT_ok;
|
||
|
|
||
|
return b;
|
||
|
}
|