Files
harbour-core/extras/gfspell/spellc.c
Przemysław Czerpak 96ca3fe470 2014-01-21 20:41 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl)
* Makefile
  * config/*
  * contrib/*
  * doc/*
  * extras/*
  * include/*
  * lib/*
  * package/*
  * src/*
  * tests/*
  * utils/*
    * removed empty lines left after removed '$' + 'Id' + '$' identifiers
2014-01-21 20:41:05 +01:00

891 lines
27 KiB
C

#include "hbapi.h"
#include "hbapifs.h"
#include "hbapiitm.h"
#define HB_ABS( a ) ( ( ( a ) > 0 ) ? ( a ) : -( a ) )
static const char * s_cSearch = "INEDTIERESTEON";
static const char * s_cRepl = "[\\]^_`a";
/**
* Function: XForm()
* Purpose: Internal function to translate words to dictionary
* Arguments: cWord - upper case word to format
* Returns: cXformed - translated word
*
* Notes: I'm assuming that the passed word won't exceed 128 bytes.
*/
HB_FUNC( XFORM )
{
char cRet[ 128 ];
char * cPtr = cRet;
HB_ISIZ iRetLen = 0;
const char * cWord = hb_parc( 1 ) + 2;
HB_ISIZ iWordLen = hb_parclen( 1 ) - 2;
HB_ISIZ x;
HB_UINT iKey;
while( --iWordLen >= 1 && iRetLen < 128 )
{
iKey = *( ( HB_UINT * ) cWord );
for( x = 0; x < 14; x += 2 )
{
if( *( ( HB_UINT * ) ( s_cSearch + x ) ) == iKey )
{
if( x == 0 )
{
if( *( cWord + 2 ) != 'G' )
{
x = 14;
break;
}
else
{
iWordLen--;
cWord++;
}
}
iWordLen--;
cWord += 2;
*cPtr++ = *( s_cRepl + ( x >> 1 ) );
break;
}
}
if( x >= 14 )
*cPtr++ = *cWord++;
iRetLen++;
}
if( iWordLen == 0 && iRetLen < 128 )
{
*cPtr++ = *cWord;
iRetLen++;
}
for( x = iRetLen - 2; x >= 0; x-- )
*( cRet + x ) -= 30;
*( cRet + iRetLen - 1 ) += 128;
hb_retclen( cRet, iRetLen );
}
/**
* Function: XUnForm()
* Purpose: Internal function to translate words from dictionary
* Arguments: cWord - formatted word
* Returns: cXformed - unformatted word
*
* Notes: I'm assuming that the returned word won't exceed 128 bytes.
*/
HB_FUNC( XUNFORM )
{
char cRet[ 128 ];
char * cPtr = cRet;
HB_ISIZ iRetLen = 0;
char c;
const char * cWord = hb_parc( 1 );
HB_ISIZ iWordLen = hb_parclen( 1 );
HB_ISIZ x;
while( iWordLen > 0 && iRetLen < 128 )
{
iWordLen--;
iRetLen++;
c = *cWord++;
if( iWordLen )
c += 30;
else
c -= 128;
if( ( x = ( HB_ISIZ ) memchr( s_cRepl, c, 7 ) ) <= 6 )
{
if( x == 0 )
{
if( iRetLen < 127 )
{
*cPtr++ = 'I';
*cPtr++ = 'N';
*cPtr++ = 'G';
iRetLen += 2;
}
}
else if( iRetLen < 128 )
{
x = x << 1;
*cPtr++ = *( s_cSearch + x++ );
*cPtr++ = *( s_cSearch + x );
iRetLen++;
}
}
else
*cPtr++ = c;
}
hb_retclen( cRet, iRetLen );
}
/**
* Function: Sp_Rate()
* Syntax: cRating := Sp_Rate( cFound, cWord )
* Purpose: Returns a letter code indicating how similar the two
* words are. This is primarily used to sort the list
* of suggested words.
* Arguments: cFound - Word from dictionary
* cWord - Word to compare with dictionary word
* Returns: cRating - Letter A-I or Z
* Category: INTERNAL
* Called by: Sp_Suggest()
* Notes: Sp_Rate() assigns a rating based upon how likely the
* word matches the dictionary word. It compares the
* first 5 letters of the boths word, then the last 5,
* down to 2 letters. This results in a rating from A-H.
* If none of these matched, then the function will return
* either an I if the words are the same length, or a Z.
*
* C Notes: I'm assuming the words passed are already trimmed.
*/
HB_FUNC( SP_RATE )
{
const char * cFound = hb_parc( 1 );
HB_ISIZ nFound = hb_parclen( 1 );
const char * cWord = hb_parc( 2 );
HB_ISIZ nWord = hb_parclen( 2 );
HB_ISIZ nMinLen = HB_MIN( nFound, nWord );
HB_ISIZ x = HB_ABS( nFound - nWord );
HB_ISIZ lim = HB_MIN( nMinLen, 5 );
char * cRating = hb_strdup( "nZZ" );
*cRating = ( char ) ( HB_MIN( x, 9 ) + '0' );
for( x = 0; x < lim; x++ )
{
if( *( cFound + x ) != *( cWord + x ) )
break;
*( cRating + 1 ) = ( char ) ( 'A' - 1 + lim - x );
}
cFound = cFound + nFound - 1;
cWord = cWord + nWord - 1;
for( x = 0; x < lim; x++ )
{
if( *cFound != *cWord )
break;
*( cRating + 2 ) = ( char ) ( 'A' - 1 + lim - x );
cFound--;
cWord--;
}
hb_retclen_buffer( cRating, 3 );
}
/**
* Author: Clayton Neff
* Copyright (c) 1992 by CoN Computer Consultants
*
* Revision: 1.0 Last Revised: 8/23/1992 at 16:47
* Description: Original Creation.
*---------------------------- ALL RIGHTS RESERVED ----------------------------*/
/*
This function replaces the ft_Metaph() that Joe Booth used in his
spelling checker article in the Aquarium.*/
HB_FUNC( C_METAFONE )
{
char * sReturn; /* Pointer to the return string. */
char * sMeta; /* Pointer to the passed string. */
HB_SIZE iRetLen; /* Length of the return string. */
HB_SIZE iStrLen; /* Length of the passed string. */
HB_SIZE iRetPtr; /* Pointer into the return string. */
HB_SIZE iStrPtr; /* Pointer into the passed string. */
/* If no string was passed then return an empty string. */
if( hb_pcount() == 0 )
{
sMeta = hb_xgrab( 1 );
sMeta[ 1 ] = '\0';
iStrLen = 0;
iRetLen = 4;
}
/* If no return lenght was passed, default to 4. */
else if( hb_pcount() == 1 )
{
hb_itemGetWriteCL( hb_param( 1, HB_IT_STRING ), &sMeta, &iStrLen );
iRetLen = 4;
}
else
{
hb_itemGetWriteCL( hb_param( 1, HB_IT_STRING ), &sMeta, &iStrLen );
iRetLen = hb_parns( 2 );
}
/* Set up the buffer to hold the return string.
Be sure to make it 1 character longer than needed
so there is space for the null terminator. */
sReturn = hb_xgrab( iRetLen + 1 );
iRetPtr = 0;
iStrPtr = 0;
/* Handle the special prefixes. */
switch( sMeta[ iStrPtr ] )
{
/* Since "KN" and "PN" both translate into 'N', we just stack their
case statements with no break, and they will all execute the same
block of code. We cannot place "GN" here because we must test
for "GI" as well. */
/* KN->N */
case 'K':
/* PN->N */
case 'P':
if( sMeta[ iStrPtr + 1 ] == 'N' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'N';
iStrPtr += 2;
}
break;
/* AE->E */
case 'A':
if( sMeta[ iStrPtr + 1 ] == 'E' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'E';
iStrPtr += 2;
}
break;
/* X->S */
case 'X':
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'S';
iStrPtr++;
break;
/* We have three different possibilities for 'W'... */
case 'W':
/* WR->R */
if( sMeta[ iStrPtr + 1 ] == 'R' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'R';
iStrPtr += 2;
}
/* WHO->H */
else if( sMeta[ iStrPtr + 1 ] == 'H' &&
sMeta[ iStrPtr + 2 ] == 'O' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'H';
iStrPtr += 3;
}
/* WH->W */
else if( sMeta[ iStrPtr + 1 ] == 'H' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'W';
iStrPtr += 2;
}
break;
/* Checking for Celtic prefixes... */
case 'M':
/* MCG->MK or MC->MK */
if( sMeta[ iStrPtr + 1 ] == 'C' )
{
/* Put in the first return characters and increment the pointer. */
sReturn[ iRetPtr++ ] = 'M';
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += ( sMeta[ iStrPtr + 2 ] == 'G' ) ? 3 : 2;
}
/* MACH->MX */
else if( sMeta[ iStrPtr + 1 ] == 'A' &&
sMeta[ iStrPtr + 2 ] == 'C' &&
sMeta[ iStrPtr + 3 ] == 'H' )
{
/* Put in the first return characters and increment the pointer. */
sReturn[ iRetPtr++ ] = 'M';
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += 4;
}
/* MACG->MK or MAC->MK */
else if( sMeta[ iStrPtr + 1 ] == 'A' &&
sMeta[ iStrPtr + 2 ] == 'C' )
{
/* Put in the first return characters and increment the pointer. */
sReturn[ iRetPtr++ ] = 'M';
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += ( sMeta[ iStrPtr + 3 ] == 'G' ) ? 4 : 3;
}
break;
case 'G':
/* GN -> N */
if( sMeta[ iStrPtr + 1 ] == 'N' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'N';
iStrPtr += 2;
}
else if( sMeta[ iStrPtr + 1 ] == 'I' )
{
/* Put in the first return character and increment the pointer. */
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += 2;
}
break;
} /* End of prefix switch...case. */
/* Now we want to loop until we have stepped through the entire
passed string or we have filled the return string. */
while( iStrPtr < iStrLen && iRetPtr < iRetLen )
{
/* Use a switch...case statement for each character combination. */
switch( sMeta[ iStrPtr ] )
{
/* If it is a vowel other than 'I', skip it if it isn't the
first character of the passed string. */
case 'A':
case 'E':
case 'O':
case 'U':
if( iStrPtr == 0 )
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr ];
iStrPtr++;
break;
/* If it is 'I', copy it if it is the first character.
In addition, check for "ISCH" and replace it with "X". */
case 'I':
if( iStrPtr == 0 )
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr ];
if( sMeta[ iStrPtr + 1 ] == 'S' &&
sMeta[ iStrPtr + 2 ] == 'C' &&
sMeta[ iStrPtr + 3 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += 3;
}
iStrPtr++;
break;
/* Skip B if it is the last character and after an 'M'. */
case 'B':
if( ( ( iStrPtr == iStrLen - 1 ) ||
sMeta[ iStrPtr + 1 ] == ' ' ) &&
sMeta[ iStrPtr - 1 ] == 'M' )
{
iStrPtr++;
continue;
}
/* B, F, K, L. M. N, R - Skip the second occurance of a double.
Otherwise, just copy the letter over. */
case 'F':
case 'K':
case 'L':
case 'M':
case 'N':
case 'R':
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
break;
/* D - Many differnt sounds possible. */
case 'D':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
/* DGE, DGI, DGY -> J */
if( sMeta[ iStrPtr + 1 ] == 'G' )
{
if( sMeta[ iStrPtr + 2 ] == 'E' ||
sMeta[ iStrPtr + 2 ] == 'I' ||
sMeta[ iStrPtr + 2 ] == 'Y' )
{
sReturn[ iRetPtr++ ] = 'J';
iStrPtr += 3;
}
/* If not one of those three, transform to T. */
else
{
sReturn[ iRetPtr++ ] = 'T';
iStrPtr++;
}
}
/* D tranforms to T. */
else
{
sReturn[ iRetPtr++ ] = 'T';
iStrPtr++;
}
break;
/* G - Many differnt sounds possible. */
case 'G':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
/* GE, GI, GY -> J (if not following a double). */
if( ( sMeta[ iStrPtr + 1 ] == 'E' ||
sMeta[ iStrPtr + 1 ] == 'I' ||
sMeta[ iStrPtr + 1 ] == 'Y' ) &&
sMeta[ iStrPtr - 1 ] != 'G' )
{
sReturn[ iRetPtr++ ] = 'J';
iStrPtr += 2;
}
/* vGHT -> T or vGH, vGHTH -> W leaving TH to be processed. */
else if( sMeta[ iStrPtr + 1 ] == 'H' &&
( sMeta[ iStrPtr - 1 ] == 'A' ||
sMeta[ iStrPtr - 1 ] == 'E' ||
sMeta[ iStrPtr - 1 ] == 'I' ||
sMeta[ iStrPtr - 1 ] == 'O' ||
sMeta[ iStrPtr - 1 ] == 'U' ) )
{
if( sMeta[ iStrPtr + 2 ] == 'T' &&
! ( sMeta[ iStrPtr + 3 ] == 'H' ) )
{
sReturn[ iRetPtr++ ] = 'T';
iStrPtr += 3;
}
else
{
/* OUGH -> F */
if( sMeta[ iStrPtr - 2 ] == 'O' &&
sMeta[ iStrPtr - 1 ] == 'U' )
{
sReturn[ iRetPtr++ ] = 'F';
iStrPtr += 2;
}
else
{
sReturn[ iRetPtr++ ] = 'W';
iStrPtr += 2;
}
}
}
/* GHv -> K */
else if( sMeta[ iStrPtr + 1 ] == 'H' &&
( sMeta[ iStrPtr + 2 ] == 'A' ||
sMeta[ iStrPtr + 2 ] == 'E' ||
sMeta[ iStrPtr + 2 ] == 'I' ||
sMeta[ iStrPtr + 2 ] == 'O' ||
sMeta[ iStrPtr + 2 ] == 'U' ) )
{
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += 2;
}
/* GN -> N */
else if( sMeta[ iStrPtr + 1 ] == 'N' )
{
sReturn[ iRetPtr++ ] = 'N';
iStrPtr += 2;
}
/* The suffix NG is skipped. */
else if( ( ( iStrPtr == iStrLen - 1 ) ||
sMeta[ iStrPtr + 1 ] == ' ' ) &&
sMeta[ iStrPtr - 1 ] == 'N' )
iStrPtr++;
/* G -> K */
else
{
sReturn[ iRetPtr++ ] = 'K';
iStrPtr++;
}
break;
/* J, W - Direct replacement. */
case 'J':
case 'W':
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
break;
/* P - Check for PH. */
case 'P':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
if( sMeta[ iStrPtr + 1 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'F';
iStrPtr += 2;
}
else
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
break;
/* Q -> K */
case 'Q':
sReturn[ iRetPtr++ ] = 'K';
iStrPtr++;
break;
/* S - Many differnt sounds possible. */
case 'S':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
/* SCH -> SK */
if( sMeta[ iStrPtr + 1 ] == 'C' &&
sMeta[ iStrPtr + 2 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'S';
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += 3;
}
/* SIO, SIA, SH -> X */
else if( ( sMeta[ iStrPtr + 1 ] == 'I' &&
( sMeta[ iStrPtr + 2 ] == 'A' ||
sMeta[ iStrPtr + 2 ] == 'O' ) ) ||
sMeta[ iStrPtr + 1 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += ( sMeta[ iStrPtr + 1 ] == 'H' ) ? 2 : 3;
}
/* SCE, SCI, SCY -> S */
else if( sMeta[ iStrPtr + 1 ] == 'C' )
{
if( sMeta[ iStrPtr + 2 ] == 'E' ||
sMeta[ iStrPtr + 2 ] == 'I' ||
sMeta[ iStrPtr + 2 ] == 'Y' )
{
sReturn[ iRetPtr++ ] = 'S';
iStrPtr += 3;
}
/* If not one of those three, just copy it over. */
else
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
}
/* Just copy the letter over. */
else
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
break;
/* T - Many different sounds possible. */
case 'T':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
/* TIA, TIO, TCH -> X */
if( ( sMeta[ iStrPtr + 1 ] == 'I' &&
( sMeta[ iStrPtr + 2 ] == 'A' ||
sMeta[ iStrPtr + 2 ] == 'O' ) ) ||
( sMeta[ iStrPtr + 1 ] == 'C' &&
sMeta[ iStrPtr + 2 ] == 'H' ) )
{
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += 3;
}
/* TH -> 0 */
else if( sMeta[ iStrPtr + 1 ] == 'H' )
{
sReturn[ iRetPtr++ ] = '0';
iStrPtr += 2;
}
/* Copy the letter over. */
else
sReturn[ iRetPtr++ ] = sMeta[ iStrPtr++ ];
break;
/* V -> F */
case 'V':
sReturn[ iRetPtr++ ] = 'F';
iStrPtr++;
break;
/* X -> KS */
case 'X':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
sReturn[ iRetPtr++ ] = 'K';
/* Now we have to check for all the S possibilities, since
we want to add one to the string. */
/* If the followed by an S, skip over it. */
if( sMeta[ iStrPtr + 1 ] == 'S' )
iStrPtr++;
/* SCH -> SK */
if( sMeta[ iStrPtr + 1 ] == 'C' &&
sMeta[ iStrPtr + 2 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'S';
sReturn[ iRetPtr++ ] = 'K';
iStrPtr += 3;
}
/* SIO, SIA, SH -> X */
else if( ( sMeta[ iStrPtr + 1 ] == 'I' &&
( sMeta[ iStrPtr + 2 ] == 'A' ||
sMeta[ iStrPtr + 2 ] == 'O' ) ) ||
sMeta[ iStrPtr + 1 ] == 'H' )
{
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += ( sMeta[ iStrPtr + 1 ] == 'H' ) ? 2 : 3;
}
/* SCE, SCI, SCY -> S */
else if( sMeta[ iStrPtr + 1 ] == 'C' )
{
if( sMeta[ iStrPtr + 2 ] == 'E' ||
sMeta[ iStrPtr + 2 ] == 'I' ||
sMeta[ iStrPtr + 2 ] == 'Y' )
{
sReturn[ iRetPtr++ ] = 'S';
iStrPtr += 3;
}
/* If not one of those three, just copy it over. */
else
{
sReturn[ iRetPtr++ ] = 'S';
iStrPtr++;
}
}
/* Just copy an 'S' over. */
else
{
sReturn[ iRetPtr++ ] = 'S';
iStrPtr++;
}
break;
/* Z -> S */
case 'Z':
/* If the letter is doubled, skip the first one. */
if( sMeta[ iStrPtr + 1 ] == sMeta[ iStrPtr ] )
iStrPtr++;
sReturn[ iRetPtr++ ] = 'S';
iStrPtr++;
break;
/* C - More sounds than any one letter should be allowed! */
case 'C':
/* CC, CH, CIA -> X */
if( sMeta[ iStrPtr + 1 ] == 'C' ||
sMeta[ iStrPtr + 1 ] == 'H' ||
( sMeta[ iStrPtr + 1 ] == 'I' &&
sMeta[ iStrPtr + 2 ] == 'A' ) )
{
sReturn[ iRetPtr++ ] = 'X';
iStrPtr += ( sMeta[ iStrPtr + 1 ] == 'I' ) ? 3 : 2;
}
/* CE, CI, CY -> S */
else if( sMeta[ iStrPtr + 1 ] == 'E' ||
sMeta[ iStrPtr + 1 ] == 'I' ||
sMeta[ iStrPtr + 1 ] == 'Y' )
{
sReturn[ iRetPtr++ ] = 'S';
iStrPtr += 2;
}
/* CK - Skip. */
else if( sMeta[ iStrPtr + 1 ] == 'K' )
iStrPtr++;
/* C -> K */
else
{
sReturn[ iRetPtr++ ] = 'K';
iStrPtr++;
}
break;
/* Y - If not followed by a vowel, skip it. */
case 'Y':
if( sMeta[ iStrPtr + 1 ] == 'A' ||
sMeta[ iStrPtr + 1 ] == 'E' ||
sMeta[ iStrPtr + 1 ] == 'I' ||
sMeta[ iStrPtr + 1 ] == 'O' ||
sMeta[ iStrPtr + 1 ] == 'U' )
sReturn[ iRetPtr++ ] = 'Y';
iStrPtr++;
break;
/* H - Skip if preceeded by and not followed by a vowel. */
case 'H':
if( ( sMeta[ iStrPtr - 1 ] == 'A' ||
sMeta[ iStrPtr - 1 ] == 'E' ||
sMeta[ iStrPtr - 1 ] == 'I' ||
sMeta[ iStrPtr - 1 ] == 'O' ||
sMeta[ iStrPtr - 1 ] == 'U' ) && !
( sMeta[ iStrPtr + 1 ] == 'A' ||
sMeta[ iStrPtr + 1 ] == 'E' ||
sMeta[ iStrPtr + 1 ] == 'I' ||
sMeta[ iStrPtr + 1 ] == 'O' ||
sMeta[ iStrPtr + 1 ] == 'U' ) )
iStrPtr++;
else
{
sReturn[ iRetPtr++ ] = 'H';
iStrPtr++;
}
break;
/* Default action, skip it. */
default:
iStrPtr++;
}
}
/* Return the prepared string. Return only the lenght that we know
is good so we don't return any uninitialized part of memory. */
hb_retclen( sReturn, iRetPtr );
/* Release the memory that we allocated for the return string. */
hb_xfree( sReturn );
}
/**
* Purpose: Sets the given bit in a passed bit string. Returns the previous
* value. Be sure to pass the string by reference. NOTE. In order
* to stay as fast as possible, minimal parameter checking is
* performed. It is up to the user to not be too stupid.
*
* Syntax: bit( @<OptC String>, <OptN (1...n) Offset> [, <OptL Set/Clear>] )
*/
HB_FUNC( BIT )
{
HB_UCHAR mask;
char * ptr;
HB_SIZE loc;
HB_SIZE offset = hb_parns( 2 ) - 1;
HB_SIZE res = 0;
loc = offset / 8;
if( loc < hb_parclen( 1 ) )
{
HB_SIZE nLen;
hb_itemGetWriteCL( hb_param( 1, HB_IT_STRING ), &ptr, &nLen );
ptr += loc;
loc = offset % 8;
res = ( HB_UCHAR ) *ptr << loc & 0x80;
if( hb_pcount() > 2 )
{
mask = ( HB_UCHAR ) 0x80 >> loc;
if( hb_parl( 3 ) )
*ptr = ( HB_UCHAR ) *ptr | mask;
else
*ptr = ( HB_UCHAR ) *ptr & ~mask;
}
}
hb_retl( res != 0 );
}
static HB_BOOL WordSep( HB_UCHAR c )
{
return c <= ' ' ||
( c != 39 && ( c > ' ' && c < '0' ) ) ||
( c > '9' && c < 'A' ) ||
( c > 'Z' && c < 'a' ) ||
( c > 'z' && c < 128 ); /* Support international characters, too. */
}
/**
* Author: John F. Kaster
* Notes: Copyright (c) 1994 by John F. Kaster and Joseph D. Booth
* Written for Grumpfish Speller to make it way faster than Prolixity.
*
* Syntax: Sp_Line( <cText>, @<nOffset>, <nLineLen> ) -> cLine
*
* Arguments:
* <cText> Text from which to retrieve a wrapped line
* <nOffset> Offset (usually passed by reference) for start of wrapped line.
* Will be set to 0 when the end of the string is encountered.
* Defaults to start of string.
* <nLineLen> Maximum wrap length for line. Defaults to 75.
*/
HB_FUNC( SP_LINE )
{
int nArgs = hb_pcount();
HB_BOOL bLineBreak = HB_FALSE;
HB_ISIZ nCount = 0;
HB_ISIZ nWrap = 0;
HB_SIZE nOffset = 0;
const char * cIn;
const char * p;
HB_BYTE cTest;
HB_ISIZ nLineLen;
HB_SIZE nStop;
if( nArgs > 0 && HB_ISCHAR( 1 ) )
{
cIn = hb_parc( 1 );
nStop = hb_parclen( 1 );
if( nArgs > 1 && HB_ISNUM( 2 ) )
{
nOffset = hb_parns( 2 );
if( nOffset > 0 )
nOffset--;
}
if( nOffset < nStop ) /* In string somewhere */
{
/* Default line len to 75 */
nLineLen = nArgs > 2 && HB_ISNUM( 3 ) ? hb_parns( 3 ) - 1 : 75;
p = &cIn[ nOffset ]; /* Starting pointer */
if( nOffset + nLineLen > nStop ) /* Past end of string? */
nLineLen = nStop - nOffset; /* Limit to end of string */
while( ! bLineBreak && nCount++ < nLineLen )
{
cTest = *p++;
if( cTest == 13 || cTest == 141 ) /* Hard or soft return? */
bLineBreak = HB_TRUE;
else if( WordSep( cTest ) ) /* Wrappable character? */
nWrap = nCount - 1;
}
if( ! bLineBreak && nWrap > 0 ) /* Back up to wrap pos */
nCount = nWrap;
hb_retclen( &( cIn[ nOffset ] ), nCount + 1 - ( bLineBreak ? 2 : 0 ) );
nOffset += nCount + 1;
if( ! bLineBreak )
{
while( cIn[ nOffset ] == ' ' ) /* Remove leading spaces */
nOffset++;
}
nOffset++; /* +1 for Harbour string */
}
else
{
nOffset = 0;
hb_retc_null();
}
}
else
hb_retc_null();
hb_storns( nOffset, 2 );
}