home *** CD-ROM | disk | FTP | other *** search
- #include <windows.h>
- #include <stdio.h>
- #include <math.h>
- #include <assert.h>
- #include <string.h>
- #include <malloc.h>
-
- #include <VM Extension.h>
-
- extern "C" DLLEXPORT char *RTFColorTable()
- {
- return( strdup( "{\\colortbl;"
- "\\red0\\green0\\blue0;"
- "\\red0\\green0\\blue255;"
- "\\red0\\green255\\blue255;"
- "\\red0\\green255\\blue0;"
- "\\red255\\green0\\blue255;"
- "\\red255\\green0\\blue0;"
- "\\red255\\green255\\blue0;"
- "\\red255\\green255\\blue255;"
- "\\red0\\green0\\blue128;"
- "\\red0\\green128\\blue128;"
- "\\red0\\green128\\blue0;"
- "\\red128\\green0\\blue128;"
- "\\red128\\green0\\blue0;"
- "\\red128\\green128\\blue0;"
- "\\red128\\green128\\blue128;"
- "\\red192\\green192\\blue192;}" ) );
- }
-
- static int colortable[][3] = {
- {0,0,0},
- {0,0,255},
- {0,255,255},
- {0,255,0},
- {255,0,255},
- {255,0,0},
- {255,255,0},
- {255,255,255},
- {0,0,128},
- {0,128,128},
- {0,128,0},
- {128,0,128},
- {128,0,0},
- {128,128,0},
- {128,128,128},
- {192,192,192},
- {-1,-1,-1}
- };
-
- extern "C" DLLEXPORT const char *RTFColorMatch( const char *cstr )
- {
- int c;
- sscanf( cstr+1, "%x", &c );
- int red = (c >> 16) & 0xff;
- int green = (c>>8) & 0xff;
- int blue = (c & 0xff);
-
- int bestMatch = 0x7fffffff;
- int bestMatchIndex = -1;
- for ( int i = 0; colortable[i][0] >= 0; i++ ) {
- int diff = abs( red-colortable[i][0] ) +
- abs( green-colortable[i][1] ) +
- abs( blue-colortable[i][2] );
- if ( diff < bestMatch) {
- bestMatch = diff;
- bestMatchIndex = i;
- }
- }
- assert( bestMatchIndex >= 0 );
- char buf[10];
- sprintf( buf, "%d", bestMatchIndex+1 );
- return( strdup( buf ) );
- }
-
- extern "C" DLLEXPORT const char *RTFLoseLastParaMarker( const char *cstr )
- {
- if ( strlen(cstr) <= 4 )
- return strdup( cstr );
- // Bomb( "Not a markup string, '%s'", cstr );
- assert( strlen(cstr) > 4 );
- char *rc = strdup(cstr);
- char *s = rc+strlen(cstr)-4;
- while ( 0 != strnicmp( s, "\\par", 4 ) ) {
- if ( s == rc ) {
- return strdup( cstr );
- // Bomb( "No paragraph marker in '%s'", cstr );
- }
- --s;
- }
- *s = '\0';
- return( rc );
- }
-
- struct AliasBuf {
- char *buffer;
- unsigned int total;
- unsigned int used;
-
- AliasBuf() {
- total = 100;
- used = 0;
- buffer = (char *)malloc( total );
- buffer[0] = '\0';
- }
-
- void AddChar( char c ) {
- if ( used+1 == total ) {
- total *= 2;
- buffer = (char *)realloc( buffer, total );
- }
- buffer[used++] = c;
- buffer[used] = '\0';
- }
- void AddAlias( const char *s, int dotseparated ) {
- char *dot = strchr( s, '.' );
- if ( dot != 0 )
- AddAlias( dot+1, dotseparated );
- const char *firstSub = 0;
- if ( used > 0 )
- AddChar( ';' );
- while ( *s != '\0' ) {
- if ( *s == '.' ) {
- if ( dotseparated )
- AddChar( '.' );
- else {
- AddChar( ':' );
- AddChar( ':' );
- }
- ++s;
- if ( firstSub == 0 )
- firstSub = s;
- }
- else if ( *s == ':' && s[1] == ':' ) {
- if ( dotseparated )
- AddChar( '.' );
- else {
- AddChar( ':' );
- AddChar( ':' );
- }
- s += 2;
- if ( firstSub == 0 )
- firstSub = s;
- }
- else {
- AddChar( *s );
- ++s;
- }
- }
- if ( firstSub != 0 )
- AddAlias( firstSub, dotseparated );
- }
- };
-
- extern "C" DLLEXPORT const char *RTFAliasListToKeywordList
- ( const char *fullname, const char *aliases )
- {
- // What we get in is something like Foo.Bar;Foo.Baz;Zoobie
- // what we want to put out is "Foo::Bar;Bar;Foo::Baz;Baz;Zoobie"
- // That is, we break it into semicolon-separated strings, then
- // we add every possible sub-context.
-
- // We need fullname to find out if this is the sort of object
- // that is :: separated or . separated...
- int dotseparated = (0 == strstr( fullname, "::" ));
-
- AliasBuf buf;
-
- const char *s = aliases;
- while ( s != 0 ) {
- const char *nexts = strchr( s, ';' );
- if ( nexts != 0 )
- *(char *)nexts = '\0';
- buf.AddAlias( s, dotseparated );
- if ( nexts != 0 ) {
- *(char *)nexts = ';';
- s = nexts+1;
- }
- else
- s = 0;
- }
- return( buf.buffer );
- }
-
- extern "C" DLLEXPORT const char *RTFRemoveMarkups( const char *text )
- {
- char *rc = strdup( text );
- char *r = rc;
- const char *s = text;
- bool realStuffSeen = false;
- while ( *s != '\0' ) {
- if ( s[0] == '{' && s[1] == '\\' && s[2] == 'b' && s[3] == ' ' ) {
- s += 4;
- while ( *s != '}' )
- *r++ = *s++;
- ++s;
- }
- else if ( s[0] == '{' && s[1] == '\\' &&
- s[2] == 'u' && s[3] == 'l' &&
- s[4] == 'd' && s[5] == 'b' && s[6] == ' ' ) {
- s += 7;
- while ( *s != '}' )
- *r++ = *s++;
- ++s;
- while ( *s != '}' )
- ++s;
- ++s;
- }
- else if ( s[0] == '\\' && s[1] == 'p' && s[2] == 'a' &&
- s[3] == 'r' && !isalnum(s[4]) ) {
- *r++ = '\\';
- *r++ = 'l';
- *r++ = 'i';
- *r++ = 'n';
- *r++ = 'e';
- s += 4;
- }
- else if ( s[0] == '\\' && s[1] == 'l' && s[2] == 'i' &&
- s[3] == 'n' && s[4] == 'e' && !isalnum(s[5]) ) {
- *r++ = '\\';
- *r++ = 'l';
- *r++ = 'i';
- *r++ = 'n';
- *r++ = 'e';
- s += 5;
- }
- else if ( s[0] == '\\' && isalnum(s[1]) ) {
- s += 2;
- while ( isalnum(*s) )
- ++s;
- }
- else if ( s[0] == '\\' ) {
- realStuffSeen = true;
- *r++ = *s++;
- *r++ = *s++;
- }
- else if ( s[0] == '{' || s[0] == '}' ||
- s[0] == '\r' || s[0] == '\n' ) {
- ++s;
- }
- else if ( s[0] == ' ' && !realStuffSeen ) {
- ++s;
- }
- else if ( s[0] == '\r' || s[0] == '\n' ) {
- *r++ = *s++;
- }
- else {
- *r++ = *s++;
- realStuffSeen = true;
- }
- }
- *r = '\0';
- bool doAgain;
- do {
- if ( r > rc && r[-1] == ' ' ) {
- --r;
- *r = '\0';
- doAgain = true;
- }
- else if ( r-4 > rc && 0 == strcmp( r-5, "\\line" ) ) {
- r -= 5;
- *r = '\0';
- doAgain = true;
- }
- else
- doAgain = false;
- } while ( doAgain );
- return( rc );
- }
-
- extern "C" DLLEXPORT const char *RTFGuestimateColumnWidth( int argc, char **argv )
- {
- double outliers = .1; // percentage which we can treat as abnormally long.
- double mainBody = .7; // percentage which we would like to see always fit
- // in the column.
- unsigned int acceptableWidth = 3600; // If the table gets bigger than this, start looking
- // for breakpoints
- unsigned int maxWidth = 4800; // The largest value which we can return
- double widthPerCharacter = 100.0;
-
- if ( argc == 2 )
- sscanf( argv[1], "%d,%d,%lg,%lg,%lg", &acceptableWidth, &maxWidth,
- &widthPerCharacter, &mainBody, &outliers );
-
- unsigned int numRows;
- unsigned int *widths;
- unsigned int widestRow;
-
- // columns (argv[0]) is a newline separated list of strings that'll be the
- // left-hand side of a column in a table.
- numRows = 1;
- for ( const char *s = argv[0]; *s != '\0'; ++s )
- if ( *s == '\n' )
- ++numRows;
-
- widths = new unsigned int[numRows];
- char *dup = strdup( argv[0] );
-
- unsigned int i = 0;
- for ( s = strtok( dup, "\n" ); s != 0; s = strtok( 0, "\n" ) )
- widths[i++] = (unsigned int)(strlen(s) * widthPerCharacter);
-
- numRows = i;
-
- for ( i = 0; i < numRows; ++i )
- for ( unsigned int j = i+1; j < numRows; ++j )
- if ( widths[i] > widths[j] ) {
- unsigned int t = widths[i];
- widths[i] = widths[j];
- widths[j] = t;
- }
-
- free( dup );
-
-
- unsigned int mainWidth = widths[ (unsigned int)(numRows * mainBody) ];
-
- unsigned int solution;
- widestRow = widths[numRows-1];
- if ( numRows < 3 || // Trivial case
- widestRow < acceptableWidth || // Within normal bounds
- mainWidth > 0.75 * widestRow ) { // No advantage to breaking it
- solution = widestRow;
- }
- else {
- // Look for the biggest gap between numRows*mainBody and numRows*outliers,
- // use that as the width.
-
- unsigned int bigBreak = 0;
- unsigned int bigBreakIndex;
- for ( i = (unsigned int)(numRows * mainBody);
- i < numRows * (1.0-outliers) + .5 && i < numRows-1;
- ++i )
- if ( widths[i+1] - widths[i] > bigBreak ) {
- bigBreak = widths[i+1] - widths[i];
- bigBreakIndex = i;
- }
-
- if ( bigBreak == 0 )
- solution = widestRow;
- else
- solution = widths[bigBreakIndex];
- }
-
- delete[numRows] widths;
- if ( solution > maxWidth )
- solution = maxWidth;
-
- char buf[16];
- sprintf( buf, "%d", solution );
- return( strdup( buf ) );
- }
-
-
-
- START_DECLARE_FUNCTIONS()
- DECLARE_NOARG_FUNCTION(RTFColorTable)
- DECLARE_1ARG_FUNCTION(RTFColorMatch)
- DECLARE_1ARG_FUNCTION(RTFLoseLastParaMarker)
- DECLARE_2ARG_FUNCTION(RTFAliasListToKeywordList)
- DECLARE_1ARG_FUNCTION(RTFRemoveMarkups)
- DECLARE_VARARG_FUNCTION(RTFGuestimateColumnWidth,1,2)
- END_DECLARE_FUNCTIONS()
-
-