/* * html.c * * by Joern Thyssen , 2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: html.c,v 1.159 2004/04/21 21:11:13 mormegil Exp $ */ #include "config.h" #include #include #include #include #include #include #if HAVE_UNISTD_H #include #endif #include #define USES_badSkill #include "analysis.h" #include "backgammon.h" #include "drawboard.h" #include "format.h" #include "export.h" #include "eval.h" #include "positionid.h" #include "matchid.h" #include "record.h" #include "path.h" #include "formatgs.h" #if HAVE_LIBGEN_H #include #elif ! defined(HAVE_BASENAME) && ! defined (HAVE_DIRNAME ) #include "simplelibgen.h" #endif #include "i18n.h" typedef enum _stylesheetclass { CLASS_MOVETABLE, CLASS_MOVEHEADER, CLASS_MOVENUMBER, CLASS_MOVEPLY, CLASS_MOVEMOVE, CLASS_MOVEEQUITY, CLASS_MOVETHEMOVE, CLASS_MOVEODD, CLASS_BLUNDER, CLASS_JOKER, CLASS_STATTABLE, CLASS_STATTABLEHEADER, CLASS_RESULT, CLASS_TINY, CLASS_CUBEDECISION, CLASS_CUBEDECISIONHEADER, CLASS_COMMENT, CLASS_COMMENTHEADER, CLASS_NUMBER, CLASS_FONT_FAMILY, CLASS_BLOCK, CLASS_PERCENT, CLASS_POSITIONID, CLASS_CUBE_EQUITY, CLASS_CUBE_ACTION, CLASS_CUBE_PLY, CLASS_CUBE_PROBABILITIES, CLASS_CUBE_CUBELESS_TEXT, NUM_CLASSES } stylesheetclass; static char *aaszStyleSheetClasses[ NUM_CLASSES ][ 2 ] = { { "movetable", "background-color: #ddddee" }, { "moveheader", "background-color: #89d0e2; padding: 0.5em" }, { "movenumber", "width: 2em; text-align: right" }, { "moveply", "width: 5em; text-align: center" }, { "movemove", "width: 20em; text-align: left" }, { "moveequity", "width: 10em; text-align: left" }, { "movethemove", "background-color: #ffffcc" }, { "moveodd", "background-color: #d0d0d0" }, { "blunder", "background-color: red; color: yellow" }, { "joker", "background-color: red; color: yellow" }, { "stattable", "text-align: left; width: 40em; background-color: #fff2cc; " "border: 0px; padding: 0px" }, { "stattableheader", "background-color: #d15b34" }, { "result", "background-color: yellow; font-weight: bold; text-align: center; " "color: black; width: 40em; padding: 0.2em" }, { "tiny", "font-size: 25%" }, { "cubedecision", "background-color: #ddddee; text-align: left;" }, { "cubedecisionheader", "background-color: #89d0e2; text-align: center; padding: 0.5em" }, { "comment", "background-color: #ccffcc; width: 39.5em; padding: 0.5em" }, { "commentheader", "background-color: #6f9915; font-weight: bold; text-align: center; " "width: 40em; padding: 0.25em" }, { "number", "text-align: center; font-weight: bold; font-size: 60%; " "font-family: sans-serif" }, { "fontfamily", "font-family: sans-serif" }, { "block", "display: block" }, { "percent", "text-align: right" }, { "positionid", "font-size: 75%; color: #787878" }, { "cubeequity", "font-weight: bold" }, { "cubeaction", "color: red" }, { "cubeply", "font-weight: bold" }, { "cubeprobs", "font-weight: bold" }, { "cubecubelesstext", "font-style: italic" } }; #define FORMATHTMLPROB(f) \ ( ( f ) < 1.0f ) ? " " : "", \ ( ( f ) < 0.1f ) ? " " : "", \ ( f ) * 100.0f char *aszHTMLExportType[ NUM_HTML_EXPORT_TYPES ] = { "gnu", "bbs", "fibs2html" }; char *aszHTMLExportCSS[ NUM_HTML_EXPORT_CSS ] = { N_("in "), N_("inline (inside tags)"), N_("external file (\"gnubg.css\")") }; char *aszHTMLExportCSSCommand[ NUM_HTML_EXPORT_CSS ] = { "head", "inline", "external" }; /* text for links on html page */ static char *aszLinkText[] = { N_ ("[First Game]"), N_ ("[Previous Game]"), N_ ("[Next Game]"), N_ ("[Last Game]") }; static const char* bullet = "• "; static void WriteStyleSheet ( FILE *pf, const htmlexportcss hecss ) { int i; if ( hecss == HTML_EXPORT_CSS_HEAD ) fputs ( "\n", pf ); else if ( hecss == HTML_EXPORT_CSS_EXTERNAL ) fputs( _("\n" "/* end of file */\n"), pf ); } static char * GetStyle ( const stylesheetclass ssc, const htmlexportcss hecss ) { static char sz[ 200 ]; switch ( hecss ) { case HTML_EXPORT_CSS_INLINE: sprintf ( sz, "style=\"%s\"", aaszStyleSheetClasses[ ssc ][ 1 ] ); break; case HTML_EXPORT_CSS_EXTERNAL: case HTML_EXPORT_CSS_HEAD: sprintf ( sz, "class=\"%s\"", aaszStyleSheetClasses[ ssc ][ 0 ] ); break; default: strcpy ( sz, "" ); break; } return sz; } static char * GetStyleGeneral( const htmlexportcss hecss, ... ) { static char sz[ 2048 ]; va_list val; stylesheetclass ssc; int i = 0; int j; va_start( val, hecss ); switch ( hecss ) { case HTML_EXPORT_CSS_INLINE: strcpy( sz, "style=\"" ); break; case HTML_EXPORT_CSS_EXTERNAL: case HTML_EXPORT_CSS_HEAD: strcpy( sz, "class=\"" ); break; default: strcpy ( sz, "" ); break; } while ( ( j = va_arg( val, int ) ) > -1 ) { ssc = (stylesheetclass) j; switch ( hecss ) { case HTML_EXPORT_CSS_INLINE: if ( i ) strcat( sz, "; " ); strcat( sz, aaszStyleSheetClasses[ ssc ][ 1 ] ); break; case HTML_EXPORT_CSS_EXTERNAL: case HTML_EXPORT_CSS_HEAD: if ( i ) strcat( sz, " " ); strcat( sz, aaszStyleSheetClasses[ ssc ][ 0 ] ); break; default: break; } ++i; } va_end( val ); strcat( sz, "\"" ); return sz; } static void HTMLPrintLegend( FILE *pf, const htmlexportcss hecss ) { /* WRITE ME */ } #if 0 static void WriteStyle ( FILE *pf, const stylesheetclass ssc, const htmlexportcss hecss ) { fputs ( GetStyle ( ssc, hecss ), pf ); } #endif static void printRolloutTable ( FILE *pf, char asz[][ 1024 ], float aarOutput[][ NUM_ROLLOUT_OUTPUTS ], float aarStdDev[][ NUM_ROLLOUT_OUTPUTS ], const cubeinfo aci[], const int cci, const int fCubeful, const int fHeader, const htmlexportcss hecss ) { int ici; fputs ( "\n", pf ); if ( fHeader ) { fputs ( "", pf ); if ( asz ) fputs ( "", pf ); fprintf ( pf, "" "" "" "" "" "" "" "", _("Win"), _("W g"), _("W bg"), _("Lose"), _("L g"), _("L bg"), _("Cubeless") ); if ( fCubeful ) fprintf ( pf, "", _("Cubeful") ); fputs ( "\n", pf ); } for ( ici = 0; ici < cci; ici++ ) { fputs ( "", pf ); /* output */ if ( asz ) fprintf ( pf, "", asz[ ici ] ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarOutput[ ici ][ OUTPUT_WIN ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarOutput[ ici ][ OUTPUT_WINGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarOutput[ ici ][ OUTPUT_WINBACKGAMMON ] ) ); fputs ( "", pf ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( 1.0f - aarOutput[ ici ][ OUTPUT_WIN ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarOutput[ ici ][ OUTPUT_LOSEGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarOutput[ ici ][ OUTPUT_LOSEBACKGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputEquityScale ( aarOutput[ ici ][ OUTPUT_EQUITY ], &aci[ ici ], &aci[ 0 ], TRUE ) ); if ( fCubeful ) fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputMWC ( aarOutput[ ici ][ OUTPUT_CUBEFUL_EQUITY ], &aci[ 0 ], TRUE ) ); fputs ( "\n", pf ); /* stddev */ fputs ( "", pf ); if ( asz ) fprintf ( pf, "", _("Standard error") ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_WIN ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_WINGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_WINBACKGAMMON ] ) ); fputs ( "", pf ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_WIN ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_LOSEGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputPercent ( aarStdDev[ ici ][ OUTPUT_LOSEBACKGAMMON ] ) ); fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputEquityScale ( aarStdDev[ ici ][ OUTPUT_EQUITY ], &aci[ ici ], &aci[ 0 ], FALSE ) ); if ( fCubeful ) fprintf ( pf, "", GetStyle ( CLASS_PERCENT, hecss ), OutputMWC ( aarStdDev[ ici ][ OUTPUT_CUBEFUL_EQUITY ], &aci[ 0 ], FALSE ) ); fputs ( "\n", pf ); } fputs ( "
 %s%s%s %s%s%s%s%s
%s%s%s%s-%s%s%s%s%s
%s%s%s%s-%s%s%s%s%s
\n", pf ); } static void printStatTableHeader ( FILE *pf, const htmlexportcss hecss, const char *format, ... ) { va_list val; va_start( val, format ); fprintf ( pf, "\n" "", GetStyle ( CLASS_STATTABLEHEADER, hecss ) ); vfprintf ( pf, format, val ); fputs ( "\n\n", pf ); va_end( val ); } static void printStatTableRow ( FILE *pf, const char *format1, const char *format2, ... ) { va_list val; char *sz; int l = 100 + strlen ( format1 ) + 2 * strlen ( format2 ); va_start( val, format2 ); sprintf ( sz = (char *) malloc ( l ), "\n" "%s\n" "%s\n" "%s\n" "\n", format1, format2, format2 ); vfprintf ( pf, sz, val ); free ( sz ); va_end( val ); } /* * Print img tag. * * Input: * pf : write to file * szImageDir: path (URI) to images * szImage: the image to print * szExtension: extension of the image (e.g. gif or png) * */ static void printImage ( FILE *pf, const char *szImageDir, const char *szImage, const char *szExtension, const char *szAlt, const htmlexportcss hecss, const htmlexporttype het ) { fprintf ( pf, "\"%s\"", ( szImageDir ) ? szImageDir : "", ( ! szImageDir || szImageDir[ strlen ( szImageDir ) - 1 ] == '/' ) ? "" : "/", szImage, szExtension, ( het == HTML_EXPORT_TYPE_GNU ) ? GetStyle ( CLASS_BLOCK, hecss ) : "", ( szAlt ) ? szAlt : "" ); } /* * print image for a point * * Input: * pf : write to file * szImageDir: path (URI) to images * szImage: the image to print * szExtension: extension of the image (e.g. gif or png) * anBoard: the board * iPoint: the point to draw * fColor: color * fUp: upper half or lower half of board * */ static void printPointBBS ( FILE *pf, const char *szImageDir, const char *szExtension, int iPoint0, int iPoint1, const int fColor, const int fUp, const htmlexportcss hecss ) { char sz[ 100 ]; char szAlt[ 100 ]; char *aasz[ 2 ][ 2 ] = { { "dd", "dn" }, { "ud", "up" } }; if ( iPoint0 ) { /* player 0 owns the point */ sprintf ( sz, "p_%s_w_%d", aasz[ fUp ][ fColor ], iPoint0 ); sprintf ( szAlt, "%1xX", iPoint0 ); } else if ( iPoint1 ) { /* player 1 owns the point */ sprintf ( sz, "p_%s_b_%d", aasz[ fUp ][ fColor ], iPoint1 ); sprintf ( szAlt, "%1xO", iPoint1 ); } else { /* empty point */ sprintf ( sz, "p_%s_0", aasz[ fUp ][ fColor ] ); sprintf ( szAlt, " '" ); } printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_BBS ); } static void printHTMLBoardBBS ( FILE *pf, matchstate *pms, int fTurn, const char *szImageDir, const char *szExtension, const htmlexportcss hecss ) { int anBoard[ 2 ][ 25 ]; int anPips[ 2 ]; int acOff[ 2 ]; int i, j; char sz[ 1024 ]; memcpy ( anBoard, pms->anBoard, sizeof ( anBoard ) ); if ( pms->fMove ) SwapSides ( anBoard ); PipCount ( anBoard, anPips ); for( i = 0; i < 2; i++ ) { acOff[ i ] = 15; for ( j = 0; j < 25; j++ ) acOff[ i ] -= anBoard[ i ][ j ]; } /* avoid page break when printing */ fputs( "

", pf ); /* * Top row */ printImage ( pf, szImageDir, fTurn ? "n_high" : "n_low", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); fputs ( "
\n", pf ); /* chequers off */ sprintf ( sz, "o_w_%d", acOff[ 1 ] ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); /* player 0's inner board */ for ( i = 0; i < 6; i++ ) printPointBBS ( pf, szImageDir, szExtension, anBoard[ 1 ][ i ], anBoard[ 0 ][ 23 - i ], ! ( i % 2 ), TRUE, hecss ); /* player 0's chequers on the bar */ sprintf ( sz, "b_up_%d", anBoard[ 0 ][ 24 ] ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); /* player 0's outer board */ for ( i = 0; i < 6; i++ ) printPointBBS ( pf, szImageDir, szExtension, anBoard[ 1 ][ i + 6 ], anBoard[ 0 ][ 17 - i ], ! ( i % 2 ), TRUE, hecss ); /* player 0 owning cube */ if ( ! pms->fCubeOwner ) { sprintf ( sz, "c_up_%d", pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); } else printImage ( pf, szImageDir, "c_up_0", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); fputs ( "
\n", pf ); /* end of first row */ /* * center row (dice) */ if ( pms->anDice[ 0 ] ) { /* dice rolled */ sprintf ( sz, "b_center%d%d%s", ( pms->anDice[ 0 ] < pms->anDice[ 1 ] ) ? pms->anDice[ 0 ] : pms->anDice[ 1 ], ( pms->anDice[ 0 ] < pms->anDice[ 1 ] ) ? pms->anDice[ 1 ] : pms->anDice[ 0 ], pms->fMove ? "right" : "left" ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); } else /* no dice rolled */ printImage ( pf, szImageDir, "b_center", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); /* center cube */ if ( pms->fCubeOwner == -1 ) printImage ( pf, szImageDir, "c_center", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); else printImage ( pf, szImageDir, "c_blank", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); fputs ( "
\n", pf ); /* end of center row */ /* * Bottom row */ /* player 1's chequers off */ sprintf ( sz, "o_b_%d", acOff[ 0 ] ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); /* player 1's inner board */ for ( i = 0; i < 6; i++ ) printPointBBS ( pf, szImageDir, szExtension, anBoard[ 1 ][ 23 - i ], anBoard[ 0 ][ i ], ( i % 2 ), FALSE, hecss ); /* player 1's chequers on the bar */ sprintf ( sz, "b_dn_%d", anBoard[ 1 ][ 24 ] ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); /* player 1's outer board */ for ( i = 0; i < 6; i++ ) printPointBBS ( pf, szImageDir, szExtension, anBoard[ 1 ][ 17 - i ], anBoard[ 0 ][ i + 6 ], ( i % 2 ), FALSE, hecss ); /* player 1 owning cube */ if ( pms->fCubeOwner == 1 ) { sprintf ( sz, "c_dn_%d", pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); } else printImage ( pf, szImageDir, "c_dn_0", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); fputs ( "
\n", pf ); /* point numbers */ printImage ( pf, szImageDir, fTurn ? "n_low" : "n_high", szExtension, NULL, hecss, HTML_EXPORT_TYPE_BBS ); fputs( "

\n", pf ); /* pip counts */ fputs ( "

", pf ); PipCount ( anBoard, anPips ); fprintf ( pf, _("Pip counts: %s %d, %s %d
\n"), ap[ 0 ].szName, anPips[ 1 ], ap[ 1 ].szName, anPips[ 0 ] ); /* position ID */ fprintf( pf, "", GetStyle ( CLASS_POSITIONID, hecss ) ); fprintf ( pf, _("Position ID: %s Match ID: %s
\n"), PositionID ( pms->anBoard ), MatchIDFromMatchState ( pms ) ); fprintf( pf, "
" ); fputs ( "

\n", pf ); } /* * print image for a point * * Input: * pf : write to file * szImageDir: path (URI) to images * szImage: the image to print * szExtension: extension of the image (e.g. gif or png) * anBoard: the board * iPoint: the point to draw * fColor: color * fUp: upper half or lower half of board * */ static void printPointF2H ( FILE *pf, const char *szImageDir, const char *szExtension, int iPoint0, int iPoint1, const int fColor, const int fUp, const htmlexportcss hecss ) { char sz[ 100 ]; char szAlt[ 100 ]; if ( iPoint0 ) { /* player 0 owns the point */ sprintf ( sz, "b-%c%c-o%d", fColor ? 'g' : 'y', fUp ? 'd' : 'u', ( iPoint0 >= 11 ) ? 11 : iPoint0 ); sprintf ( szAlt, "%1xX", iPoint0 ); } else if ( iPoint1 ) { /* player 1 owns the point */ sprintf ( sz, "b-%c%c-x%d", fColor ? 'g' : 'y', fUp ? 'd' : 'u', ( iPoint1 >= 11 ) ? 11 : iPoint1 ); sprintf ( szAlt, "%1xO", iPoint1 ); } else { /* empty point */ sprintf ( sz, "b-%c%c", fColor ? 'g' : 'y', fUp ? 'd' : 'u' ); sprintf ( szAlt, " '" ); } printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } static void printHTMLBoardF2H ( FILE *pf, matchstate *pms, int fTurn, const char *szImageDir, const char *szExtension, const htmlexportcss hecss ) { char sz[ 100 ]; char szAlt[ 100 ]; int fColor; int i; char *aszDieO[] = { "b-odie1", "b-odie2", "b-odie3", "b-odie4", "b-odie5", "b-odie6" }; char *aszDieX[] = { "b-xdie1", "b-xdie2", "b-xdie3", "b-xdie4", "b-xdie5", "b-xdie6" }; int anBoard[ 2 ][ 25 ]; int anPips[ 2 ]; memcpy ( anBoard, pms->anBoard, sizeof ( anBoard ) ); if ( pms->fMove ) SwapSides ( anBoard ); /* top line with board numbers */ fprintf ( pf, "

\n" ); printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); sprintf ( sz, "b-%stop%s", fTurn ? "hi" : "lo", fClockwise ? "" : "r"); printImage ( pf, szImageDir, sz, szExtension, fTurn ? "+-13-14-15-16-17-18-+---+-19-20-21-22-23-24-+" : "+-12-11-10--9--8--7-+---+--6--5--4--3--2--1-+", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); /* cube image */ if ( pms->fDoubled ) { /* questionmark with cube (if player 0 is doubled) */ if ( ! pms->fTurn ) { sprintf ( sz, "b-dup%d", 2 * pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else printImage (pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else { /* display arrow */ if ( pms->fCubeOwner == -1 || pms->fCubeOwner ) printImage (pf, szImageDir, fTurn ? "b-topdn" : "b-topup", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); else { sprintf ( sz, "%s%d", fTurn ? "b-tdn" : "b-tup", pms->nCube ); printImage (pf, szImageDir, sz, szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } } /* display left border */ printImage ( pf, szImageDir, "b-left", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); /* display player 0's outer quadrant */ fColor = 1; for ( i = 0; i < 6; i++ ) { printPointF2H ( pf, szImageDir, szExtension, anBoard[ 1 ][ 11 - i ], anBoard[ 0 ][ 12 + i], fColor, TRUE, hecss); fColor = ! fColor; } /* display bar */ if ( anBoard[ 0 ][ 24 ] ) { sprintf ( sz, "b-bar-x%d", ( anBoard[ 0 ][ 24 ] > 4 ) ? 4 : anBoard[ 0 ][ 24 ] ); sprintf ( szAlt, "|%1X |", anBoard[ 0 ][ 24 ] ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else printImage ( pf, szImageDir, "b-bar", szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); /* display player 0's home quadrant */ fColor = 1; for ( i = 0; i < 6; i++ ) { printPointF2H ( pf, szImageDir, szExtension, anBoard[ 1 ][ 5 - i ], anBoard[ 0 ][ 18 + i], fColor, TRUE, hecss ); fColor = ! fColor; } /* right border */ printImage ( pf, szImageDir, "b-right", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); /* center of board */ if ( pms->anDice[ 0 ] && pms->anDice[ 1 ] ) { printImage ( pf, szImageDir, "b-midin", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midl", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? "b-midg" : "b-midg2", szExtension, "        " "         ", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? "b-midc" : aszDieO [ pms->anDice[ 0 ] - 1 ], szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? "b-midg2" : aszDieO [ pms->anDice[ 1 ] - 1 ], szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? aszDieX [ pms->anDice[ 0 ] - 1 ] : "b-midg2", szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? aszDieX [ pms->anDice[ 1 ] - 1 ] : "b-midc", szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, fTurn ? "b-midg2" : "b-midg", szExtension, "        " "         ", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midr", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); } else { if ( pms->fDoubled ) printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); else printImage ( pf, szImageDir, "b-midin", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midl", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midg", szExtension, "        " "         ", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midc", szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midg", szExtension, "        " "         ", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); printImage ( pf, szImageDir, "b-midr", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); } /* cube image */ if ( pms->fDoubled ) { /* questionmark with cube (if player 0 is doubled) */ if ( pms->fTurn ) { sprintf ( sz, "b-ddn%d", 2 * pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else printImage (pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else { /* display cube */ if ( pms->fCubeOwner == -1 || ! pms->fCubeOwner ) printImage (pf, szImageDir, fTurn ? "b-botdn" : "b-botup", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); else { sprintf ( sz, "%s%d", fTurn ? "b-bdn" : "b-bup", pms->nCube ); printImage (pf, szImageDir, sz, szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } } printImage ( pf, szImageDir, "b-left", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); /* display player 1's outer quadrant */ fColor = 0; for ( i = 0; i < 6; i++ ) { printPointF2H ( pf, szImageDir, szExtension, anBoard[ 1 ][ 12 + i ], anBoard[ 0 ][ 11 - i], fColor, FALSE, hecss ); fColor = ! fColor; } /* display bar */ if ( anBoard[ 1 ][ 24 ] ) { sprintf ( sz, "b-bar-o%d", ( anBoard[ 1 ][ 24 ] > 4 ) ? 4 : anBoard[ 1 ][ 24 ] ); sprintf ( szAlt, "| %1dO|", anBoard[ 1 ][ 24 ] ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_FIBS2HTML ); } else printImage ( pf, szImageDir, "b-bar", szExtension, "|   |", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); /* display player 1's outer quadrant */ fColor = 0; for ( i = 0; i < 6; i++ ) { printPointF2H ( pf, szImageDir, szExtension, anBoard[ 1 ][ 18 + i ], anBoard[ 0 ][ 5 - i], fColor, FALSE, hecss ); fColor = ! fColor; } /* right border */ printImage ( pf, szImageDir, "b-right", szExtension, "|", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); /* bottom */ printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); sprintf ( sz, "b-%sbot%s", fTurn ? "lo" : "hi", fClockwise ? "" : "r"); printImage ( pf, szImageDir, sz, szExtension, fTurn ? "+-12-11-10--9--8--7-+---+--6--5--4--3--2--1-+" : "+-13-14-15-16-17-18-+---+-19-20-21-22-23-24-+", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf ( pf, "
\n" ); /* pip counts */ printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); PipCount ( anBoard, anPips ); fprintf ( pf, _("Pip counts: %s %d, %s %d
\n"), ap[ 0 ].szName, anPips[ 1 ], ap[ 1 ].szName, anPips[ 0 ] ); /* position ID */ printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, HTML_EXPORT_TYPE_FIBS2HTML ); fprintf( pf, "", GetStyle ( CLASS_POSITIONID, hecss ) ); fprintf ( pf, _("Position ID: %s Match ID: %s
\n"), PositionID ( pms->anBoard ), MatchIDFromMatchState ( pms ) ); fprintf( pf, "
" ); fprintf ( pf, "

\n" ); } /* * print image for a point * * Input: * pf : write to file * szImageDir: path (URI) to images * szImage: the image to print * szExtension: extension of the image (e.g. gif or png) * anBoard: the board * iPoint: the point to draw * fColor: color * fUp: upper half or lower half of board * */ static void printPointGNU ( FILE *pf, const char *szImageDir, const char *szExtension, int iPoint0, int iPoint1, const int fColor, const int fUp, const htmlexportcss hecss ) { char sz[ 100 ]; char szAlt[ 100 ]; if ( iPoint0 ) { /* player 0 owns the point */ sprintf ( sz, "b-%c%c-x%d", fColor ? 'g' : 'r', fUp ? 'd' : 'u', iPoint0 ); sprintf ( szAlt, "%1xX", iPoint0 ); } else if ( iPoint1 ) { /* player 1 owns the point */ sprintf ( sz, "b-%c%c-o%d", fColor ? 'g' : 'r', fUp ? 'd' : 'u', iPoint1 ); sprintf ( szAlt, "%1xO", iPoint1 ); } else { /* empty point */ sprintf ( sz, "b-%c%c", fColor ? 'g' : 'r', fUp ? 'd' : 'u' ); sprintf ( szAlt, " '" ); } printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); } static void printHTMLBoardGNU ( FILE *pf, matchstate *pms, int fTurn, const char *szImageDir, const char *szExtension, const htmlexportcss hecss ) { char sz[ 1000 ]; char szAlt[ 1000 ]; int i, j; int anBoard[ 2 ][ 25 ]; int anPips[ 2 ]; int acOff[ 2 ]; memcpy ( anBoard, pms->anBoard, sizeof ( anBoard ) ); if ( pms->fMove ) SwapSides ( anBoard ); for( i = 0; i < 2; i++ ) { acOff[ i ] = 15; for ( j = 0; j < 25; j++ ) acOff[ i ] -= anBoard[ i ][ j ]; } /* top line with board numbers */ fputs ( "\n", pf ); fputs ( "", pf ); fputs ( "\n", pf ); /* display left bearoff tray */ fputs ( "", pf ); fputs ( "", pf ); /* display player 0's outer quadrant */ for ( i = 0; i < 6; i++ ) { fputs ( "", pf ); } /* display cube */ fputs ( "", pf ); /* display player 0's home quadrant */ for ( i = 0; i < 6; i++ ) { fputs ( "", pf ); } /* right bearoff tray */ fputs ( "", pf ); fputs ( "\n", pf ); /* display bar */ fputs ( "", pf ); fputs ( "", pf ); fputs ( "\n", pf ); /* center of board */ fputs ( "", pf ); /* left part of bar */ fputs ( "", pf ); /* center of board */ fputs ( "", pf ); /* centered cube */ if ( pms->fCubeOwner == -1 && ! pms->fDoubled ) { sprintf ( sz, "b-midc-%d", pms->nCube ); sprintf ( szAlt, "|%2d |", pms->nCube ); } else { strcpy ( sz, "b-midc" ); strcpy(szAlt, "|   |"); } fputs ( "", pf ); /* player 1 */ fputs ( "", pf ); /* right part of bar */ fputs ( "", pf ); fputs ( "\n", pf ); /* display left bearoff tray */ fputs ( "", pf ); fputs ( "", pf ); /* display player 1's outer quadrant */ for ( i = 0; i < 6; i++ ) { fputs ( "", pf ); } /* display bar */ fputs ( "", pf ); /* display player 1's outer quadrant */ for ( i = 0; i < 6; i++ ) { fputs ( "", pf ); } /* right bearoff tray */ fputs ( "", pf ); fputs ( "\n", pf ); /* display cube */ fputs ( "", pf ); fputs ( "", pf ); fputs ( "\n", pf ); /* bottom */ fputs ( "", pf ); fputs ( "", pf ); fputs ( "", pf ); fputs ( "
", pf ); sprintf ( sz, "b-%stop%s", fTurn ? "hi" : "lo", fClockwise ? "" : "r"); printImage ( pf, szImageDir, sz, szExtension, fClockwise ? (fTurn ? "+-24-23-22-21-20-19-+---+-18-17-16-15-14-13-+" : "+--1--2--3--4--5--6-+---+--7--8--9-10-11-12-+") : (fTurn ? "+-13-14-15-16-17-18-+---+-19-20-21-22-23-24-+" : "+-12-11-10--9--8--7-+---+--6--5--4--3--2--1-+"), hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); if ( fClockwise ) /* Use roff as loff not generated (and probably not needed) */ sprintf ( sz, "b-roff-x%d", acOff[ 1 ] ); else strcpy ( sz, "b-loff-x0" ); printImage ( pf, szImageDir, sz, szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( fClockwise ) printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ i ], anBoard[ 0 ][ 23 - i ], ! (i % 2), TRUE, hecss ); else printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 11 - i ], anBoard[ 0 ][ 12 + i], ! (i % 2), TRUE, hecss ); fputs ( "", pf ); if ( ! pms->fCubeOwner ) { sprintf ( sz, "b-ct-%d", pms->nCube ); sprintf ( szAlt, "|%2d |", pms->nCube ); } else { strcpy ( sz, "b-ct" ); strcpy ( szAlt, "|   |" ); } printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( fClockwise ) printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ i + 6 ], anBoard[ 0 ][ 17 - i ], ! ( i % 2 ), TRUE, hecss ); else printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 5 - i ], anBoard[ 0 ][ 18 + i], ! ( i % 2 ), TRUE, hecss ); fputs ( "", pf ); if ( ! fClockwise ) sprintf ( sz, "b-roff-x%d", acOff[ 1 ] ); else strcpy ( sz, "b-roff-x0" ); printImage ( pf, szImageDir, sz, szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); sprintf ( sz, "b-bar-o%d", anBoard[ 1 ][ 24 ] ); if ( anBoard[ 1 ][ 24 ] ) sprintf ( szAlt, "|                   " "| %1XX|" "                   |", anBoard[ 1 ][ 24 ] ); else strcpy ( szAlt, "|                   " "|   |" "                   |"); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); if ( fClockwise ) printImage ( pf, szImageDir, "b-midlb", szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); else printImage ( pf, szImageDir, fTurn ? "b-midlb-o" : "b-midlb-x", szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( ! pms->fMove && pms->anDice[ 0 ] && pms->anDice[ 1 ] ) { /* player has rolled the dice */ sprintf ( sz, "b-midl-x%d%d", pms->anDice[ 0 ], pms->anDice[ 1 ] ); sprintf ( szAlt, "       %d %d       ", pms->anDice[ 0 ], pms->anDice[ 1 ] ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); } else if ( ! pms->fMove && pms->fDoubled ) { /* player 0 has doubled */ sprintf ( sz, "b-midl-c%d", 2 * pms->nCube ); sprintf ( szAlt, "       [%d]       ", 2 * pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); } else { /* player 0 on roll */ printImage ( pf, szImageDir, "b-midl", szExtension, "                 ", hecss, HTML_EXPORT_TYPE_GNU ); } fputs ( "", pf ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( pms->fMove && pms->anDice[ 0 ] && pms->anDice[ 1 ] ) { /* player 1 has rolled the dice */ sprintf ( sz, "b-midr-o%d%d", pms->anDice[ 0 ], pms->anDice[ 1 ] ); sprintf ( szAlt, "       %d %d       ", pms->anDice[ 0 ], pms->anDice[ 1 ] ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); } else if ( pms->fMove && pms->fDoubled ) { /* player 1 has doubled */ sprintf ( sz, "b-midr-c%d", 2 * pms->nCube ); sprintf ( szAlt, "       [%d]       ", 2 * pms->nCube ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); } else { /* player 1 on roll */ printImage ( pf, szImageDir, "b-midr", szExtension, "                 ", hecss, HTML_EXPORT_TYPE_GNU ); } fputs ( "", pf ); if ( ! fClockwise ) printImage ( pf, szImageDir, "b-midrb", szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); else printImage ( pf, szImageDir, fTurn ? "b-midrb-o" : "b-midrb-x", szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); if ( fClockwise ) /* Use roff as loff not generated (and probably not needed) */ sprintf ( sz, "b-roff-o%d", acOff[ 0 ] ); else strcpy ( sz, "b-loff-o0" ); printImage ( pf, szImageDir, sz, szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( fClockwise ) printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 23 - i ], anBoard[ 0 ][ i ], i % 2, FALSE, hecss ); else printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 12 + i ], anBoard[ 0 ][ 11 - i], i % 2, FALSE, hecss ); fputs ( "", pf ); sprintf ( sz, "b-bar-x%d", anBoard[ 0 ][ 24 ] ); if ( pms->fCubeOwner == 1 ) sprintf ( szAlt, "|%2d |", pms->nCube ); else strcpy ( szAlt, "|   |" ); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "", pf ); if ( fClockwise ) printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 17 - i ], anBoard[ 0 ][ i + 6 ], i % 2, FALSE, hecss ); else printPointGNU ( pf, szImageDir, szExtension, anBoard[ 1 ][ 18 + i ], anBoard[ 0 ][ 5 - i], i % 2, FALSE, hecss ); fputs ( "", pf ); if ( ! fClockwise ) sprintf ( sz, "b-roff-o%d", acOff[ 0 ] ); else strcpy ( sz, "b-roff-o0" ); printImage ( pf, szImageDir, sz, szExtension, "|", hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); if ( pms->fCubeOwner == 1 ) sprintf ( sz, "b-cb-%d", pms->nCube ); else strcpy ( sz, "b-cb" ); if ( anBoard[ 0 ][ 24 ] ) /* text for alt tag - bottom bar piece */ sprintf ( szAlt, "|                   " "| %1XO|" "                   |", anBoard[ 0 ][ 24 ] ); else strcpy(szAlt, ""); printImage ( pf, szImageDir, sz, szExtension, szAlt, hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
", pf ); sprintf ( sz, "b-%sbot%s", fTurn ? "lo" : "hi", fClockwise ? "" : "r"); printImage ( pf, szImageDir, sz, szExtension, fClockwise ? (fTurn ? "+--1--2--3--4--5--6-+---+--7--8--9-10-11-12-+" : "+-24-23-22-21-20-19-+---+-18-17-16-15-14-13-+") : (fTurn ? "+-12-11-10--9--8--7-+---+--6--5--4--3--2--1-+" : "+-13-14-15-16-17-18-+---+-19-20-21-22-23-24-+"), hecss, HTML_EXPORT_TYPE_GNU ); fputs ( "
\n\n", pf ); /* pip counts */ fputs ( "

", pf ); PipCount ( anBoard, anPips ); fprintf ( pf, _("Pip counts: %s %d, %s %d
\n"), ap[ 0 ].szName, anPips[ 1 ], ap[ 1 ].szName, anPips[ 0 ] ); /* position ID */ fprintf( pf, "", GetStyle ( CLASS_POSITIONID, hecss ) ); fprintf ( pf, _("Position ID: %s Match ID: %s
\n"), PositionID ( pms->anBoard ), MatchIDFromMatchState ( pms ) ); fprintf( pf, "
" ); fputs ( "

\n", pf ); } static void printHTMLBoard ( FILE *pf, matchstate *pms, int fTurn, const char *szImageDir, const char *szExtension, const htmlexporttype het, const htmlexportcss hecss ) { fputs ( "\n\n\n", pf ); switch ( het ) { case HTML_EXPORT_TYPE_FIBS2HTML: printHTMLBoardF2H ( pf, pms, fTurn, szImageDir, szExtension, hecss ); break; case HTML_EXPORT_TYPE_BBS: printHTMLBoardBBS ( pf, pms, fTurn, szImageDir, szExtension, hecss ); break; case HTML_EXPORT_TYPE_GNU: printHTMLBoardGNU ( pf, pms, fTurn, szImageDir, szExtension, hecss ); break; default: printf ( _("unknown board type\n") ); break; } fputs ( "\n\n\n", pf ); } /* * Print html header for board: move or cube decision * * Input: * pf: output file * ms: current match state * iMove: move no. * */ static void HTMLBoardHeader ( FILE *pf, const matchstate *pms, const htmlexporttype het, const htmlexportcss hecss, const int iGame, const int iMove, const int fHR ) { fputs ( "\n\n\n", pf ); if ( fHR ) fputs ( "
\n", pf ); fputs ( "

", pf ); if ( iMove >= 0 ) { fprintf ( pf, "" "", iGame + 1, iMove + 1 ); fprintf ( pf, _("Move number %d:"), iMove + 1 ); fputs ( "", pf ); } if ( pms->fResigned ) /* resignation */ fprintf ( pf, _(" %s resigns %d points"), ap[ pms->fTurn ].szName, pms->fResigned * pms->nCube ); else if ( pms->anDice[ 0 ] && pms->anDice[ 1 ] ) /* chequer play decision */ fprintf ( pf, _(" %s to play %d%d"), ap[ pms->fMove ].szName, pms->anDice[ 0 ], pms->anDice[ 1 ] ); else if ( pms->fDoubled ) /* take decision */ fprintf ( pf, _(" %s doubles to %d"), ap[ pms->fMove ].szName, pms->nCube * 2 ); else /* cube decision */ fprintf ( pf, _(" %s on roll, cube decision?"), ap[ pms->fMove ].szName ); fputs ( "

\n", pf ); fputs ( "\n\n\n", pf ); } /* * Print html header: dtd, head etc. * * Input: * pf: output file * ms: current match state * */ static void HTMLPrologue ( FILE *pf, const matchstate *pms, const int iGame, char *aszLinks[ 4 ], const htmlexporttype het, const htmlexportcss hecss ) { char szTitle[ 100 ]; int i; int fFirst; /* DTD */ sprintf( szTitle, pms->cGames == 1 ? _("The score (after %d game) is: %s %d, %s %d") : _("The score (after %d games) is: %s %d, %s %d"), pms->cGames, ap[ 0 ].szName, pms->anScore[ 0 ], ap[ 1 ].szName, pms->anScore[ 1 ] ); if ( pms->nMatchTo > 0 ) sprintf( strchr( szTitle, 0 ), pms->nMatchTo == 1 ? _(" (match to %d point%s)") : _(" (match to %d points%s)"), pms->nMatchTo, pms->fCrawford ? _(", Crawford game") : ( pms->fPostCrawford ? _(", post-Crawford play") : "")); fprintf ( pf, "\n" "\n" "\n" "\n" "\n" "\n" "nMatchTo ) ? _("match play") : _("money game") ); fprintf ( pf, _("%s (analysed by GNU Backgammon %s)"), szTitle, VERSION ); fprintf ( pf, "\" />\n" "%s\n", szTitle ); if ( hecss == HTML_EXPORT_CSS_HEAD ) WriteStyleSheet ( pf, hecss ); else if ( hecss == HTML_EXPORT_CSS_EXTERNAL ) fputs( "\n", pf ); fprintf ( pf, "\n" "\n" "\n" "

", GetStyle ( CLASS_FONT_FAMILY, hecss ) ); fprintf ( pf, _("Game number %d"), iGame + 1 ); fprintf ( pf, "

\n" "

%s

\n" , szTitle ); /* add links to other games */ fFirst = TRUE; for ( i = 0; i < 4; i++ ) if ( aszLinks && aszLinks[ i ] ) { if ( fFirst ) { fprintf ( pf, "
\n" ); fputs ( "

\n", pf ); fFirst = FALSE; } fprintf ( pf, "%s\n", aszLinks[ i ], gettext ( aszLinkText[ i ] ) ); } if ( ! fFirst ) fputs ( "

\n", pf ); } /* * Print html header: dtd, head etc. * * Input: * pf: output file * ms: current match state * */ static void HTMLEpilogue ( FILE *pf, const matchstate *pms, char *aszLinks[ 4 ], const htmlexportcss hecss ) { time_t t; int fFirst; int i; const char szVersion[] = "$Revision: 1.159 $"; int iMajor, iMinor; iMajor = atoi ( strchr ( szVersion, ' ' ) ); iMinor = atoi ( strchr ( szVersion, '.' ) + 1 ); fputs ( "\n\n\n", pf ); /* add links to other games */ fFirst = TRUE; for ( i = 0; i < 4; i++ ) if ( aszLinks && aszLinks[ i ] ) { if ( fFirst ) { fprintf ( pf, "
\n" ); fputs ( "

\n", pf ); fFirst = FALSE; } fprintf ( pf, "%s\n", aszLinks[ i ], aszLinkText[ i ] ); } if ( ! fFirst ) fputs ( "

\n", pf ); time ( &t ); fputs ( "
\n" "
", pf ); fprintf ( pf, _("Output generated %s by " "GNU Backgammon " "%s") , ctime ( &t ), VERSION ); fputs ( " ", pf ); fprintf ( pf, _("(HTML Export version %d.%d)"), iMajor, iMinor ); fprintf ( pf, "
\n" "

\n" "" "\n" "" "" "\n" "

\n" "\n" "\n", _("Valid XHTML 1.0!"), _("Valid CSS!") ); } /* * Print html header: dtd, head etc. * * Input: * pf: output file * ms: current match state * */ static void HTMLEpilogueComment ( FILE *pf ) { time_t t; const char szVersion[] = "$Revision: 1.159 $"; int iMajor, iMinor; char *pc; iMajor = atoi ( strchr ( szVersion, ' ' ) ); iMinor = atoi ( strchr ( szVersion, '.' ) + 1 ); time ( &t ); pc = ctime ( &t ); if ( ( pc = strchr ( pc, '\n' ) ) ) *pc = 0; fputs ( "\n\n\n", pf ); fprintf ( pf, _(""), iMajor, iMinor ); } /* * Print cube analysis * * Input: * pf: output file * arDouble: equitites for cube decisions * fPlayer: player who doubled * esDouble: eval setup * pci: cubeinfo * fDouble: double/no double * fTake: take/drop * */ static void HTMLPrintCubeAnalysisTable ( FILE *pf, float aarOutput[ 2 ][ NUM_ROLLOUT_OUTPUTS ], float aarStdDev[ 2 ][ NUM_ROLLOUT_OUTPUTS ], int fPlayer, evalsetup *pes, cubeinfo *pci, int fDouble, int fTake, skilltype stDouble, skilltype stTake, const htmlexportcss hecss ) { const char *aszCube[] = { NULL, N_("No double"), N_("Double, take"), N_("Double, pass") }; float arDouble[ 4 ]; int i; int ai[ 3 ]; float r; int fActual, fClose, fMissed; int fDisplay; int fAnno = FALSE; cubedecision cd; /* check if cube analysis should be printed */ if ( pes->et == EVAL_NONE ) return; /* no evaluation */ if ( ! GetDPEq ( NULL, NULL, pci ) ) return; /* cube not available */ cd = FindCubeDecision ( arDouble, GCCCONSTAHACK aarOutput, pci ); fActual = fDouble > 0; fClose = isCloseCubedecision ( arDouble ); fMissed = fDouble > -1 && isMissedDouble ( arDouble, GCCCONSTAHACK aarOutput, fDouble, pci ); fDisplay = ( fActual && exsExport.afCubeDisplay[ EXPORT_CUBE_ACTUAL ] ) || ( fClose && exsExport.afCubeDisplay[ EXPORT_CUBE_CLOSE ] ) || ( fMissed && exsExport.afCubeDisplay[ EXPORT_CUBE_MISSED ] ) || ( exsExport.afCubeDisplay[ stDouble ] ) || ( exsExport.afCubeDisplay[ stTake ] ); if ( ! fDisplay ) return; fputs ( "\n\n\n", pf ); /* print alerts */ if ( fMissed ) { fAnno = TRUE; /* missed double */ fprintf ( pf, "

%s (%s)!", GetStyle ( CLASS_BLUNDER, hecss ), _("Alert: missed double"), OutputEquityDiff ( arDouble[ OUTPUT_NODOUBLE ], ( arDouble[ OUTPUT_TAKE ] > arDouble[ OUTPUT_DROP ] ) ? arDouble[ OUTPUT_DROP ] : arDouble[ OUTPUT_TAKE ], pci ) ); if ( badSkill(stDouble) ) fprintf ( pf, " [%s]", gettext ( aszSkillType[ stDouble ] ) ); fprintf ( pf, "

\n" ); } r = arDouble[ OUTPUT_TAKE ] - arDouble[ OUTPUT_DROP ]; if ( fTake > 0 && r > 0.0f ) { fAnno = TRUE; /* wrong take */ fprintf ( pf, "

%s (%s)!", GetStyle ( CLASS_BLUNDER, hecss ), _("Alert: wrong take"), OutputEquityDiff ( arDouble[ OUTPUT_DROP ], arDouble[ OUTPUT_TAKE ], pci ) ); if ( badSkill(stTake) ) fprintf ( pf, " [%s]", gettext ( aszSkillType[ stTake ] ) ); fprintf ( pf, "

\n" ); } r = arDouble[ OUTPUT_DROP ] - arDouble[ OUTPUT_TAKE ]; if ( fDouble > 0 && ! fTake && r > 0.0f ) { fAnno = TRUE; /* wrong pass */ fprintf ( pf, "

%s (%s)!", GetStyle ( CLASS_BLUNDER, hecss ), _("Alert: wrong pass"), OutputEquityDiff ( arDouble[ OUTPUT_TAKE ], arDouble[ OUTPUT_DROP ], pci ) ); if ( badSkill(stTake) ) fprintf ( pf, " [%s]", gettext ( aszSkillType[ stTake ] ) ); fprintf ( pf, "

\n" ); } if ( arDouble[ OUTPUT_TAKE ] > arDouble[ OUTPUT_DROP ] ) r = arDouble[ OUTPUT_NODOUBLE ] - arDouble[ OUTPUT_DROP ]; else r = arDouble[ OUTPUT_NODOUBLE ] - arDouble[ OUTPUT_TAKE ]; if ( fDouble > 0 && r > 0.0f ) { fAnno = TRUE; /* wrong double */ fprintf ( pf, "

%s (%s)!", GetStyle ( CLASS_BLUNDER, hecss ), _("Alert: wrong double"), OutputEquityDiff ( ( arDouble[ OUTPUT_TAKE ] > arDouble[ OUTPUT_DROP ] ) ? arDouble[ OUTPUT_DROP ] : arDouble[ OUTPUT_TAKE ], arDouble[ OUTPUT_NODOUBLE ], pci ) ); if ( badSkill(stDouble) ) fprintf ( pf, " [%s]", gettext ( aszSkillType[ stDouble ] ) ); fprintf ( pf, "

\n" ); } if ( ( badSkill(stDouble) || badSkill(stTake) ) && ! fAnno ) { if ( badSkill(stDouble) ) { fprintf ( pf, "

", GetStyle ( CLASS_BLUNDER, hecss ) ); fprintf ( pf, _("Alert: double decision marked %s"), gettext ( aszSkillType[ stDouble ] ) ); fputs ( "

\n", pf ); } if ( badSkill(stTake) ) { fprintf ( pf, "

", GetStyle ( CLASS_BLUNDER, hecss ) ); fprintf ( pf, _("Alert: take decision marked %s"), gettext ( aszSkillType[ stTake ] ) ); fputs ( "

\n", pf ); } } /* print table */ fprintf ( pf, "\n", GetStyle ( CLASS_CUBEDECISION, hecss ) ); /* header */ fprintf ( pf, "\n", GetStyle ( CLASS_CUBEDECISIONHEADER, hecss ), _("Cube decision") ); /* ply & cubeless equity */ /* FIXME: about parameters if exsExport.afCubeParameters */ fprintf ( pf, "" ); /* ply */ fprintf ( pf, "" "" "\n", ( !pci->nMatchTo || ( pci->nMatchTo && ! fOutputMWC ) ) ? _("cubeless equity") : _("cubeless MWC"), GetStyle( CLASS_CUBE_EQUITY, hecss ), OutputEquity ( aarOutput[ 0 ][ OUTPUT_EQUITY ], pci, TRUE ), GetStyle( CLASS_CUBE_CUBELESS_TEXT, hecss ), _("Money"), GetStyle( CLASS_CUBE_EQUITY, hecss ), OutputMoneyEquity ( aarOutput[ 0 ], TRUE ) ); else fprintf ( pf, " cubeless equity\n", OutputMoneyEquity ( aarOutput[ 0 ], TRUE ) ); fprintf ( pf, "\n" ); /* percentages */ if ( exsExport.fCubeDetailProb && pes->et == EVAL_EVAL ) { fprintf( pf, "" "\n", pf ); } /* equities */ fprintf( pf, "\n", _("Cubeful equities:") ); /* evaluate parameters */ if ( pes->et == EVAL_EVAL && exsExport.afCubeParameters[ 0 ] ) { fputs ( "" "\n", pf ); } getCubeDecisionOrdering ( ai, arDouble, GCCCONSTAHACK aarOutput, pci ); for ( i = 0; i < 3; i++ ) { fprintf ( pf, "", i + 1, gettext ( aszCube[ ai[ i ] ] ) ); fprintf ( pf, "", GetStyle( CLASS_CUBE_EQUITY, hecss ), OutputEquity ( arDouble[ ai [ i ] ], pci, TRUE ) ); if ( i ) fprintf ( pf, "", OutputEquityDiff ( arDouble[ ai [ i ] ], arDouble[ OUTPUT_OPTIMAL ], pci ) ); else fputs ( "", pf ); fputs ( "\n", pf ); } /* cube decision */ fprintf ( pf, "" "\n" ); /* rollout details */ if ( pes->et == EVAL_ROLLOUT && ( exsExport.fCubeDetailProb || exsExport.afCubeParameters [ 1 ] ) ) { fprintf ( pf, "\n", _("Rollout details") ); } if ( pes->et == EVAL_ROLLOUT && exsExport.fCubeDetailProb ) { char asz[ 2 ][ 1024 ]; cubeinfo aci[ 2 ]; for ( i = 0; i < 2; i++ ) { memcpy ( &aci[ i ], pci, sizeof ( cubeinfo ) ); if ( i ) { aci[ i ].fCubeOwner = ! pci->fMove; aci[ i ].nCube *= 2; } FormatCubePosition ( asz[ i ], &aci[ i ] ); } fputs ( "" "\n", pf ); } if ( pes->et == EVAL_ROLLOUT && exsExport.afCubeParameters[ 1 ] ) { char *sz = strdup ( OutputRolloutContext ( NULL, pes ) ); char *pcS = sz, *pcE; while ( ( pcE = strstr ( pcS, "\n" ) ) ) { *pcE = 0; fprintf ( pf, "\n", pcS ); pcS = pcE + 1; } free ( sz ); } fprintf ( pf, "
%s
" "", GetStyle( CLASS_CUBE_PLY, hecss ) ); switch ( pes->et ) { case EVAL_NONE: fputs ( _("n/a"), pf ); break; case EVAL_EVAL: fprintf ( pf, _("%d-ply"), pes->ec.nPlies ); break; case EVAL_ROLLOUT: fputs ( _("Rollout"), pf ); break; } /* cubeless equity */ if ( pci->nMatchTo ) fprintf ( pf, " %s%s(%s: %s)%s 
 ", GetStyle( CLASS_CUBE_PROBABILITIES, hecss ) ); fputs ( OutputPercents ( aarOutput[ 0 ], TRUE ), pf ); fputs ( "
%s
 ", pf ); fputs ( OutputEvalContext( &pes->ec, FALSE ), pf ); fputs ( "
%d.%s%s%s 
%s%s", _("Proper cube action:"), GetStyle( CLASS_CUBE_ACTION, hecss ), GetCubeRecommendation ( cd ) ); if ( ( r = getPercent ( cd, arDouble ) ) >= 0.0 ) fprintf ( pf, " (%.1f%%)", 100.0f * r ); fprintf ( pf, "
%s
", pf ); printRolloutTable ( pf, asz, aarOutput, aarStdDev, aci, 2, pes->rc.fCubeful, TRUE, hecss ); fputs ( "
%s
\n" ); fputs ( "

 

\n", pf ); fputs ( "\n\n\n", pf ); } /* * Wrapper for print cube analysis * * Input: * pf: output file * pms: match state * pmr: current move record * szImageDir: URI to images * szExtension: extension of images * fTake: take/drop * */ static void HTMLPrintCubeAnalysis ( FILE *pf, matchstate *pms, moverecord *pmr, const char *szImageDir, const char *szExtension, const htmlexporttype het, const htmlexportcss hecss ) { cubeinfo ci; GetMatchStateCubeInfo ( &ci, pms ); switch ( pmr->mt ) { case MOVE_NORMAL: /* cube analysis from move */ HTMLPrintCubeAnalysisTable ( pf, pmr->n.aarOutput, pmr->n.aarStdDev, pmr->n.fPlayer, &pmr->n.esDouble, &ci, FALSE, -1, pmr->n.stCube, SKILL_NONE, hecss ); break; case MOVE_DOUBLE: HTMLPrintCubeAnalysisTable ( pf, pmr->d.CubeDecPtr->aarOutput, pmr->d.CubeDecPtr->aarStdDev, pmr->d.fPlayer, &pmr->d.CubeDecPtr->esDouble, &ci, TRUE, -1, pmr->d.st, SKILL_NONE, hecss ); break; case MOVE_TAKE: case MOVE_DROP: /* cube analysis from double, {take, drop, beaver} */ HTMLPrintCubeAnalysisTable ( pf, pmr->d.CubeDecPtr->aarOutput, pmr->d.CubeDecPtr->aarStdDev, pmr->d.fPlayer, &pmr->d.CubeDecPtr->esDouble, &ci, TRUE, pmr->mt == MOVE_TAKE, SKILL_NONE, /* FIXME: skill from prev. cube */ pmr->d.st, hecss ); break; default: assert ( FALSE ); } return; } /* * Print move analysis * * Input: * pf: output file * pms: match state * pmr: current move record * szImageDir: URI to images * szExtension: extension of images * */ static void HTMLPrintMoveAnalysis ( FILE *pf, matchstate *pms, moverecord *pmr, const char *szImageDir, const char *szExtension, const htmlexporttype het, const htmlexportcss hecss ) { char sz[ 64 ]; int i; float rEq, rEqTop; cubeinfo ci; GetMatchStateCubeInfo( &ci, pms ); /* check if move should be printed */ if ( ! exsExport.afMovesDisplay [ pmr->n.stMove ] ) return; fputs ( "\n\n\n", pf ); /* print alerts */ if ( badSkill(pmr->n.stMove) ) { /* blunder or error */ fprintf ( pf, "

", GetStyle ( CLASS_BLUNDER, hecss ) ); fprintf ( pf, _("Alert: %s move"), gettext ( aszSkillType[ pmr->n.stMove ] ) ); if ( !pms->nMatchTo || ( pms->nMatchTo && ! fOutputMWC ) ) fprintf ( pf, " (%+7.3f)

\n", pmr->n.ml.amMoves[ pmr->n.iMove ].rScore - pmr->n.ml.amMoves[ 0 ].rScore ); else fprintf ( pf, " (%+6.3f%%)

\n", 100.0f * eq2mwc ( pmr->n.ml.amMoves[ pmr->n.iMove ].rScore, &ci ) - 100.0f * eq2mwc ( pmr->n.ml.amMoves[ 0 ].rScore, &ci ) ); } if ( pmr->n.lt != LUCK_NONE ) { /* joker */ fprintf ( pf, "

", GetStyle ( CLASS_JOKER, hecss ) ); fprintf ( pf, _("Alert: %s roll!"), gettext ( aszLuckType[ pmr->n.lt ] ) ); if ( !pms->nMatchTo || ( pms->nMatchTo && ! fOutputMWC ) ) fprintf ( pf, " (%+7.3f)

\n", pmr->n.rLuck ); else fprintf ( pf, " (%+6.3f%%)

\n", 100.0f * eq2mwc ( pmr->n.rLuck, &ci ) - 100.0f * eq2mwc ( 0.0f, &ci ) ); } /* table header */ fprintf ( pf, "\n" "\n", GetStyle ( CLASS_MOVETABLE, hecss ) ); fprintf ( pf, "\n", GetStyleGeneral( hecss, CLASS_MOVEHEADER, CLASS_MOVENUMBER, -1 ), _("#") ); fprintf ( pf, "\n", GetStyleGeneral( hecss, CLASS_MOVEHEADER, CLASS_MOVEPLY, -1 ), _("Ply") ); fprintf ( pf, "\n", GetStyleGeneral( hecss, CLASS_MOVEHEADER, CLASS_MOVEMOVE, -1 ), _("Move") ); fprintf ( pf, "\n" "\n", GetStyleGeneral( hecss, CLASS_MOVEHEADER, CLASS_MOVEEQUITY, -1 ), ( !pms->nMatchTo || ( pms->nMatchTo && ! fOutputMWC ) ) ? _("Equity") : _("MWC") ); if ( pmr->n.ml.cMoves ) { for ( i = 0; i < pmr->n.ml.cMoves; i++ ) { if ( i >= exsExport.nMoves && i != pmr->n.iMove ) continue; if ( i == pmr->n.iMove ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ) ); else if ( i % 2 ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVEODD, hecss ) ); else fputs ( "\n", pf ); /* selected move or not */ fprintf ( pf, "\n", GetStyle ( CLASS_MOVENUMBER, hecss ), ( i == pmr->n.iMove ) ? bullet : " " ); /* move no */ if ( i != pmr->n.iMove || i != pmr->n.ml.cMoves - 1 || pmr->n.ml.cMoves == 1 ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVENUMBER, hecss ), i + 1 ); else fprintf ( pf, "\n", GetStyle ( CLASS_MOVENUMBER, hecss ) ); /* ply */ switch ( pmr->n.ml.amMoves[ i ].esMove.et ) { case EVAL_NONE: fprintf ( pf, "\n", GetStyle ( CLASS_MOVEPLY, hecss ) ); break; case EVAL_EVAL: fprintf ( pf, "\n", GetStyle ( CLASS_MOVEPLY, hecss ), pmr->n.ml.amMoves[ i ].esMove.ec.nPlies ); break; case EVAL_ROLLOUT: fprintf ( pf, "\n", GetStyle ( CLASS_MOVEPLY, hecss ) ); break; } /* move */ fprintf ( pf, "\n", GetStyle ( CLASS_MOVEMOVE, hecss ), FormatMove ( sz, pms->anBoard, pmr->n.ml.amMoves[ i ].anMove ) ); /* equity */ rEq = pmr->n.ml.amMoves[ i ].rScore; rEqTop = pmr->n.ml.amMoves[ 0 ].rScore; if ( i ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVEEQUITY, hecss ), OutputEquity ( rEq, &ci, TRUE ), OutputEquityDiff ( rEq, rEqTop, &ci ) ); else fprintf ( pf, "\n", GetStyle ( CLASS_MOVEEQUITY, hecss ), OutputEquity ( rEq, &ci, TRUE ) ); /* end row */ fprintf ( pf, "\n" ); /* * print row with detailed probabilities */ if ( exsExport.fMovesDetailProb ) { float *ar = pmr->n.ml.amMoves[ i ].arEvalMove; /* percentages */ if ( i == pmr->n.iMove ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ) ); else if ( i % 2 ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVEODD, hecss ) ); else fputs ( "\n", pf ); fputs ( "\n", pf ); fputs ( "\n", pf ); fputs( "\n", pf ); fputs ( "\n", pf ); } /* * Write row with move parameters */ if ( exsExport.afMovesParameters [ pmr->n.ml.amMoves[ i ].esMove.et - 1 ] ) { evalsetup *pes = &pmr->n.ml.amMoves[ i ].esMove; switch ( pes->et ) { case EVAL_EVAL: if ( i == pmr->n.iMove ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ) ); else if ( i % 2 ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVEODD, hecss ) ); else fputs ( "\n", pf ); fprintf ( pf, "\n" ); fputs ( "\n", pf ); fputs( "\n", pf ); fputs ( "\n", pf ); break; case EVAL_ROLLOUT: { char *sz = strdup ( OutputRolloutContext ( NULL, pes ) ); char *pcS = sz, *pcE; while ( ( pcE = strstr ( pcS, "\n" ) ) ) { *pcE = 0; if ( i == pmr->n.iMove ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ) ); else if ( i % 2 ) fprintf ( pf, "\n", GetStyle ( CLASS_MOVEODD, hecss ) ); else fputs ( "\n", pf ); fprintf ( pf, "\n" ); fputs ( "\n", pf ); fputs( "\n", pf ); fputs ( "\n", pf ); pcS = pcE + 1; } free ( sz ); break; } default: break; } } } } else { if ( pmr->n.anMove[ 0 ] >= 0 ) /* no movelist saved */ fprintf ( pf, "" "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ), FormatMove ( sz, pms->anBoard, pmr->n.anMove ) ); else /* no legal moves */ /* FIXME: output equity?? */ fprintf ( pf, "" "\n", GetStyle ( CLASS_MOVETHEMOVE, hecss ), _("Cannot move") ); } fprintf ( pf, "
%s%s%s%s
%s%d\?\?n/a%dR%s%s (%s)%s
 ", pf ); switch ( pmr->n.ml.amMoves[ i ].esMove.et ) { case EVAL_EVAL: fputs ( OutputPercents ( ar, TRUE ), pf ); break; case EVAL_ROLLOUT: printRolloutTable ( pf, NULL, ( float (*)[ NUM_ROLLOUT_OUTPUTS ] ) pmr->n.ml.amMoves[ i ].arEvalMove, ( float (*)[ NUM_ROLLOUT_OUTPUTS ] ) pmr->n.ml.amMoves[ i ].arEvalStdDev, &ci, 1, pmr->n.ml.amMoves[ i ].esMove.rc.fCubeful, FALSE, hecss ); break; default: break; } fputs ( " 
 ", pf ); fputs ( OutputEvalContext ( &pes->ec, TRUE ), pf ); fputs ( " 
 ", pf ); fputs ( pcS, pf ); fputs ( " 
   %s 
   %s 
\n" ); fputs ( "\n\n\n", pf ); return; } /* * Print cube analysis * * Input: * pf: output file * pms: match state * pmr: current move record * szImageDir: URI to images * szExtension: extension of images * */ static void HTMLAnalysis ( FILE *pf, matchstate *pms, moverecord *pmr, const char *szImageDir, const char *szExtension, const htmlexporttype het, const htmlexportcss hecss ) { char sz[ 1024 ]; switch ( pmr->mt ) { case MOVE_NORMAL: fprintf ( pf, "

" ); if ( het == HTML_EXPORT_TYPE_FIBS2HTML ) printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, het ); if ( pmr->n.anMove[ 0 ] >= 0 ) fprintf ( pf, _("%s%s moves %s"), bullet, ap[ pmr->n.fPlayer ].szName, FormatMove ( sz, pms->anBoard, pmr->n.anMove ) ); else if ( ! pmr->n.ml.cMoves ) fprintf ( pf, _("%s%s cannot move"), bullet, ap[ pmr->n.fPlayer ].szName ); fputs ( "

\n", pf ); /* HTMLRollAlert ( pf, pms, pmr, szImageDir, szExtension ); */ if ( exsExport.fIncludeAnalysis ) { HTMLPrintCubeAnalysis ( pf, pms, pmr, szImageDir, szExtension, het, hecss ); HTMLPrintMoveAnalysis ( pf, pms, pmr, szImageDir, szExtension, het, hecss ); } break; case MOVE_TAKE: case MOVE_DROP: case MOVE_DOUBLE: fprintf ( pf, "

" ); if ( het == HTML_EXPORT_TYPE_FIBS2HTML ) printImage ( pf, szImageDir, "b-indent", szExtension, "", hecss, het ); if ( pmr->mt == MOVE_DOUBLE ) fprintf ( pf, "%s%s doubles

\n", bullet, ap[ pmr->d.fPlayer ].szName ); else fprintf ( pf, "%s%s %s

\n", bullet, ap[ pmr->d.fPlayer ].szName, ( pmr->mt == MOVE_TAKE ) ? _("accepts") : _("rejects") ); if ( exsExport.fIncludeAnalysis ) HTMLPrintCubeAnalysis ( pf, pms, pmr, szImageDir, szExtension, het, hecss ); break; default: break; } } /* * Dump statcontext * * Input: * pf: output file * statcontext to dump * */ static void HTMLDumpStatcontext ( FILE *pf, const statcontext *psc, matchstate *pms, const int iGame, const htmlexportcss hecss ) { const int fIsMatch = iGame < 0; fprintf ( pf, "\n\n\n", ( iGame >= 0 ) ? "Game" : "Match" ); fprintf ( pf, "\n", GetStyle ( CLASS_STATTABLE, hecss ) ); if ( iGame >= 0 ) { printStatTableHeader ( pf, hecss, _("Game statistics for game %d"), iGame + 1); } else { if ( pms->nMatchTo ) printStatTableHeader ( pf, hecss, _( "Match statistics" ) ); else printStatTableHeader ( pf, hecss, _( "Session statistics" ) ); } fprintf ( pf, "\n" "\n" "\n", GetStyle ( CLASS_STATTABLEHEADER, hecss ), _("Player"), ap[ 0 ].szName, ap[ 1 ].szName ); /* checker play */ if( psc->fMoves ) { GList *list = formatGS( psc, pms, fIsMatch, FORMATGS_CHEQUER ); GList *pl; printStatTableHeader ( pf, hecss, _("Checker play statistics") ); for ( pl = g_list_first( list ); pl; pl = g_list_next( pl ) ) { char **aasz = pl->data; printStatTableRow( pf, aasz[ 0 ], "%s", aasz[ 1 ], aasz[ 2 ] ); } freeGS( list ); } /* dice stat */ if( psc->fDice ) { GList *list = formatGS( psc, pms, fIsMatch, FORMATGS_LUCK ); GList *pl; printStatTableHeader ( pf, hecss, _( "Luck statistics" ) ); for ( pl = g_list_first( list ); pl; pl = g_list_next( pl ) ) { char **aasz = pl->data; printStatTableRow( pf, aasz[ 0 ], "%s", aasz[ 1 ], aasz[ 2 ] ); } freeGS( list ); } /* cube statistics */ if( psc->fCube ) { GList *list = formatGS( psc, pms, fIsMatch, FORMATGS_CUBE ); GList *pl; printStatTableHeader ( pf, hecss, _( "Cube statistics" ) ); for ( pl = g_list_first( list ); pl; pl = g_list_next( pl ) ) { char **aasz = pl->data; printStatTableRow( pf, aasz[ 0 ], "%s", aasz[ 1 ], aasz[ 2 ] ); } freeGS( list ); } /* overall rating */ { GList *list = formatGS( psc, pms, fIsMatch, FORMATGS_OVERALL ); GList *pl; printStatTableHeader ( pf, hecss, _( "Overall statistics" ) ); for ( pl = g_list_first( list ); pl; pl = g_list_next( pl ) ) { char **aasz = pl->data; printStatTableRow( pf, aasz[ 0 ], "%s", aasz[ 1 ], aasz[ 2 ] ); } freeGS( list ); } fprintf ( pf, "
%s%s%s
\n" ); fprintf ( pf, "\n\n\n", ( iGame >= 0 ) ? "Game" : "Match" ); } static void HTMLPrintComment ( FILE *pf, const moverecord *pmr, const htmlexportcss hecss ) { char *sz = NULL; switch ( pmr->mt ) { case MOVE_GAMEINFO: sz = pmr->g.sz; break; case MOVE_DOUBLE: case MOVE_TAKE: case MOVE_DROP: sz = pmr->d.sz; break; case MOVE_NORMAL: sz = pmr->n.sz; break; case MOVE_RESIGN: sz = pmr->r.sz; break; case MOVE_SETBOARD: sz = pmr->sb.sz; break; case MOVE_SETDICE: sz = pmr->sd.sz; break; case MOVE_SETCUBEVAL: sz = pmr->scv.sz; break; case MOVE_SETCUBEPOS: sz = pmr->scp.sz; break; case MOVE_TIME: /* ignore */ break; } if ( sz ) { fputs ( "\n\n", pf ); fprintf ( pf, "
\n" "
", GetStyle ( CLASS_COMMENTHEADER, hecss ) ); fputs ( _("Annotation"), pf ); fputs ( "
\n", pf ); fprintf ( pf, "
", GetStyle ( CLASS_COMMENT, hecss ) ); while ( *sz ) { if ( *sz == '\n' ) fputs ( "
\n", pf ); else fputc ( *sz, pf ); sz++; } fputs ( "
\n\n", pf ); fputs ( "\n\n", pf ); } } static void HTMLPrintMI( FILE *pf, const char *szTitle, const char *sz ) { gchar **ppch; gchar *pchToken; int i; if ( ! sz || ! *sz ) return; fprintf( pf, "" "%s", szTitle ); ppch = g_strsplit( sz, "\n", -1 ); for ( i = 0; (pchToken = ppch[ i ]) ; ++i ) { if ( i ) fputs( "
\n", pf ); fputs( pchToken, pf ); } g_strfreev( ppch ); fputs( "\n", pf ); } static void HTMLMatchInfo ( FILE *pf, const matchinfo *pmi, const htmlexportcss hecss ) { int i; char sz[ 80 ]; struct tm tmx; if ( ! pmi->nYear && ! pmi->pchRating[ 0 ] && ! pmi->pchRating[ 1 ] && ! pmi->pchEvent && ! pmi->pchRound && ! pmi->pchPlace && ! pmi->pchAnnotator && ! pmi->pchComment ) /* no match information -- don't print anything */ return; fputs ( "\n\n\n", pf ); fputs ( "
", pf ); fprintf ( pf, "

%s

\n", _("Match Information") ); fputs ( "\n", pf ); /* ratings */ for ( i = 0; i < 2; ++i ) if ( pmi->pchRating[ i ] ) { gchar *pch = g_strdup_printf( _("%s's rating"), ap[ i ].szName ); HTMLPrintMI( pf, pch, pmi->pchRating[ i ] ? pmi->pchRating[ i ] : _("n/a") ); g_free( pch ); } /* date */ if ( pmi->nYear ) { tmx.tm_year = pmi->nYear - 1900; tmx.tm_mon = pmi->nMonth - 1; tmx.tm_mday = pmi->nDay; strftime ( sz, sizeof ( sz ), _("%B %d, %Y"), &tmx ); HTMLPrintMI( pf, _("Date"), sz ); } /* event, round, place and annotator */ HTMLPrintMI( pf, _("Event"), pmi->pchEvent ); HTMLPrintMI( pf, _("Round"), pmi->pchRound ); HTMLPrintMI( pf, _("Place"), pmi->pchPlace ); HTMLPrintMI( pf, _("Annotator"), pmi->pchAnnotator ); HTMLPrintMI( pf, _("Comment"), pmi->pchComment ); fputs ( "
\n", pf ); fputs ( "\n\n\n", pf ); } static void HTMLDumpPlayerRecords ( FILE *pf, const htmlexportcss hecss ) { /* dump the player records from file */ playerrecord apr[ 2 ]; playerrecord *pr; int i; int f = FALSE; int af[ 2 ] = { FALSE, FALSE }; for ( i = 0; i < 2; ++i ) if ( ( pr = GetPlayerRecord ( ap[ i ].szName ) ) ) { f = TRUE; af[ i ] = TRUE; memcpy ( &apr[ i ], pr, sizeof ( playerrecord ) ); } else memset ( &apr[ i ], 0, sizeof ( playerrecord ) ); if ( ! f ) return; fputs ( "\n\n\n", pf ); fprintf ( pf, "\n", GetStyle ( CLASS_STATTABLE, hecss ) ); printStatTableHeader ( pf, hecss, _("Recorded player statistics") ); fprintf ( pf, "\n" "\n" "\n", GetStyle ( CLASS_STATTABLEHEADER, hecss ), _("Player"), ap[ 0 ].szName, ap[ 1 ].szName ); printStatTableRow ( pf, _("Chequer (Long-term error rate)"), "%5.3f", -apr[ 0 ].arErrorChequerplay[ EXPAVG_100 ], -apr[ 1 ].arErrorChequerplay[ EXPAVG_100 ] ); printStatTableRow ( pf, _("Cube (Long-term error rate)"), "%5.3f", -apr[ 0 ].arErrorCube[ EXPAVG_100 ], -apr[ 1 ].arErrorCube[ EXPAVG_100 ] ); printStatTableRow ( pf, _("Chequer (Short-term error rate)"), "%5.3f", -apr[ 0 ].arErrorChequerplay[ EXPAVG_20 ], -apr[ 1 ].arErrorChequerplay[ EXPAVG_20 ] ); printStatTableRow ( pf, _("Cube (Short-term error rate)"), "%5.3f", -apr[ 0 ].arErrorCube[ EXPAVG_20 ], -apr[ 1 ].arErrorCube[ EXPAVG_20 ] ); printStatTableRow ( pf, _("Chequer (total)"), "%5.3f", -apr[ 0 ].arErrorChequerplay[ TOTAL ], -apr[ 1 ].arErrorChequerplay[ TOTAL ] ); printStatTableRow ( pf, _("Cube (total)"), "%5.3f", -apr[ 0 ].arErrorCube[ TOTAL ], -apr[ 1 ].arErrorCube[ TOTAL ] ); printStatTableRow ( pf, _("Luck (total)"), "%5.3f", apr[ 0 ].arLuck[ TOTAL ], apr[ 1 ].arLuck[ TOTAL ] ); printStatTableRow ( pf, _("Games (total)"), "%d", apr[ 0 ].cGames, apr[ 1 ].cGames ); fprintf ( pf, "
%s%s%s
\n" ); fprintf ( pf, "\n\n\n" ); } /* * Export a game in HTML * * Input: * pf: output file * plGame: list of moverecords for the current game * */ static void ExportGameHTML ( FILE *pf, list *plGame, const char *szImageDir, const char *szExtension, const htmlexporttype het, const htmlexportcss hecss, const int iGame, const int fLastGame, char *aszLinks[ 4 ] ) { list *pl; moverecord *pmr; matchstate msExport; matchstate msOrig; int iMove = 0; statcontext *psc = NULL; static statcontext scTotal; movegameinfo *pmgi = NULL; if ( ! iGame ) IniStatcontext ( &scTotal ); updateStatisticsGame ( plGame ); for( pl = plGame->plNext; pl != plGame; pl = pl->plNext ) { pmr = pl->p; FixMatchState ( &msExport, pmr ); switch( pmr->mt ) { case MOVE_GAMEINFO: ApplyMoveRecord ( &msExport, plGame, pmr ); HTMLPrologue( pf, &msExport, iGame, aszLinks, het, hecss ); if ( exsExport.fIncludeMatchInfo ) HTMLMatchInfo ( pf, &mi, hecss ); msOrig = msExport; pmgi = &pmr->g; psc = &pmr->g.sc; AddStatcontext ( psc, &scTotal ); /* FIXME: game introduction */ break; case MOVE_NORMAL: if( pmr->n.fPlayer != msExport.fMove ) { SwapSides( msExport.anBoard ); msExport.fMove = pmr->n.fPlayer; } msExport.fTurn = msExport.fMove = pmr->n.fPlayer; msExport.anDice[ 0 ] = pmr->n.anRoll[ 0 ]; msExport.anDice[ 1 ] = pmr->n.anRoll[ 1 ]; HTMLBoardHeader ( pf, &msExport, het, hecss, iGame, iMove, TRUE ); printHTMLBoard( pf, &msExport, msExport.fTurn, szImageDir, szExtension, het, hecss ); HTMLAnalysis ( pf, &msExport, pmr, szImageDir, szExtension, het, hecss ); iMove++; break; case MOVE_TAKE: case MOVE_DROP: HTMLBoardHeader ( pf,&msExport, het, hecss, iGame, iMove, TRUE ); printHTMLBoard( pf, &msExport, msExport.fTurn, szImageDir, szExtension, het, hecss ); HTMLAnalysis ( pf, &msExport, pmr, szImageDir, szExtension, het, hecss ); iMove++; break; default: break; } if ( exsExport.fIncludeAnnotation ) HTMLPrintComment ( pf, pmr, hecss ); ApplyMoveRecord ( &msExport, plGame, pmr ); } if( pmgi && pmgi->fWinner != -1 ) { /* print game result */ fprintf ( pf, ( pmgi->nPoints == 1 ) ? _("

%s wins %d point

\n") : _("

%s wins %d points

\n"), GetStyle ( CLASS_RESULT, hecss ), ap[ pmgi->fWinner ].szName, pmgi->nPoints ); } if ( psc ) { HTMLDumpStatcontext ( pf, psc, &msOrig, iGame, hecss ); HTMLDumpPlayerRecords ( pf, hecss ); } if ( fLastGame ) { /* match statistics */ fprintf ( pf, "
\n" ); HTMLDumpStatcontext ( pf, &scTotal, &msOrig, -1, hecss ); /* legend */ if ( exsExport.fIncludeLegend ) HTMLPrintLegend( pf, hecss ); } HTMLEpilogue( pf, &msExport, aszLinks, hecss ); } /* * get name number * * Input * plGame: the game for which the game number is requested * * Returns: * the game number * */ extern int getGameNumber ( const list *plGame ) { list *pl; int iGame; for( pl = lMatch.plNext, iGame = 0; pl != &lMatch; pl = pl->plNext, iGame++ ) if ( pl->p == plGame ) return iGame; return -1; } /* * get move number * * Input * plGame: the game * p: the move * * Returns: * the move number * */ extern int getMoveNumber ( const list *plGame, const void *p ) { list *pl; int iMove; for( pl = plGame->plNext, iMove = 0; pl != plGame; pl = pl->plNext, iMove++ ) if ( p == pl->p ) return iMove; return -1; } /* * Open file gnubg.css with same path as requested html file * * If the gnubg.css file already exists NULL is returned * (and gnubg.css is NOT overwritten) * */ static FILE * OpenCSS( const char *sz ) { char *pch = strdup( sz ); char *pchBase = dirname( pch ); char *pchCSS; FILE *pf; sprintf( pchCSS = (char *) malloc( strlen( pchBase ) + 20 ), "%s%c%s", pchBase, DIR_SEPARATOR, "gnubg.css" ); if ( !access( pchCSS, R_OK ) ) { /* file exists */ outputf( _("gnubg.css is not written since it already exist in \"%s\"\n"), pchBase ); pf = NULL; } else if ( ! ( pf = fopen( pchCSS, "w" ) ) ) { outputerr( pchCSS ); } free( pch ); free( pchBase ); free( pchCSS ); return pf; } extern void CommandExportGameHtml( char *sz ) { FILE *pf; sz = NextToken( &sz ); if( !plGame ) { outputl( _("No game in progress (type `new game' to start one).") ); return; } if( !sz || !*sz ) { outputl( _("You must specify a file to export to (see `help export " "game html').") ); return; } if ( ! confirmOverwrite ( sz, fConfirmSave ) ) return; if( !strcmp( sz, "-" ) ) pf = stdout; else if( !( pf = fopen( sz, "w" ) ) ) { outputerr( sz ); return; } ExportGameHTML( pf, plGame, exsExport.szHTMLPictureURL, exsExport.szHTMLExtension, exsExport.het, exsExport.hecss, getGameNumber ( plGame ), FALSE, NULL ); if( pf != stdout ) fclose( pf ); setDefaultFileName ( sz, PATH_HTML ); /* external stylesheet */ if ( exsExport.hecss == HTML_EXPORT_CSS_EXTERNAL ) if ( ( pf = OpenCSS( sz ) ) ) WriteStyleSheet ( pf, exsExport.hecss ); } /* * Get filename for html file: * * Number 0 gets the value of szBase. * Assume szBase is "blah.html", then number 1 will be * "blah_001.html", and so forth. * * Input: * szBase: base filename * iGame: game number * * Garbage collect: * Caller must free returned pointer if not NULL * */ extern char * HTMLFilename ( const char *szBase, const int iGame ) { if ( ! iGame ) return strdup ( szBase ); else { char *sz = malloc ( strlen ( szBase ) + 5 ); char *szExtension = strrchr ( szBase, '.' ); char *pc; if ( ! szExtension ) { sprintf ( sz, "%s_%03d", szBase, iGame + 1 ); return sz; } else { strcpy ( sz, szBase ); pc = strrchr ( sz, '.' ); sprintf ( pc, "_%03d%s", iGame + 1, szExtension ); return sz; } } } extern void CommandExportMatchHtml( char *sz ) { FILE *pf; list *pl; int nGames; char *aszLinks[ 4 ], *filenames[4]; char *szCurrent; int i, j; sz = NextToken( &sz ); if( !sz || !*sz ) { outputl( _("You must specify a file to export to (see `help export " "match html').") ); return; } /* Find number of games in match */ for( pl = lMatch.plNext, nGames = 0; pl != &lMatch; pl = pl->plNext, nGames++ ) ; for( pl = lMatch.plNext, i = 0; pl != &lMatch; pl = pl->plNext, i++ ) { szCurrent = HTMLFilename ( sz, i ); filenames[0] = HTMLFilename ( sz, 0 ); aszLinks[ 0 ] = basename ( filenames[ 0 ] ); filenames[ 1 ] = aszLinks[ 1 ] = NULL; if (i > 0) { filenames[ 1 ] = HTMLFilename ( sz, i - 1 ); aszLinks[ 1 ] = basename ( filenames[ 1 ] ); } filenames[ 2 ] = aszLinks[ 2 ] = NULL; if (i < nGames - 1) { filenames[ 2 ] = HTMLFilename ( sz, i + 1 ); aszLinks[ 2 ] = basename ( filenames[ 2 ] ); } filenames[ 3 ] = HTMLFilename ( sz, nGames - 1 ); aszLinks[ 3 ] = basename ( filenames[ 3 ] ); if ( !i ) { if ( ! confirmOverwrite ( sz, fConfirmSave ) ) { for ( j = 0; j < 4; j++ ) free (filenames [ j ] ); free ( szCurrent ); return; } setDefaultFileName ( sz, PATH_HTML ); } if( !strcmp( szCurrent, "-" ) ) pf = stdout; else if( !( pf = fopen( szCurrent, "w" ) ) ) { outputerr( szCurrent ); for ( j = 0; j < 4; j++ ) free (filenames [ j ] ); free ( szCurrent ); return; } ExportGameHTML ( pf, pl->p, exsExport.szHTMLPictureURL, exsExport.szHTMLExtension, exsExport.het, exsExport.hecss, i, i == nGames - 1, aszLinks ); for ( j = 0; j < 4; j++ ) free (filenames [ j ] ); free ( szCurrent ); if( pf != stdout ) fclose( pf ); } /* external stylesheet */ if ( exsExport.hecss == HTML_EXPORT_CSS_EXTERNAL ) if ( ( pf = OpenCSS( sz ) ) ) WriteStyleSheet ( pf, exsExport.hecss ); } extern void CommandExportPositionHtml( char *sz ) { FILE *pf; int fHistory; moverecord *pmr = getCurrentMoveRecord ( &fHistory ); int iMove; sz = NextToken( &sz ); if( ms.gs == GAME_NONE ) { outputl( _("No game in progress (type `new game' to start one).") ); return; } if( !sz || !*sz ) { outputl( _("You must specify a file to export to (see `help export " "position html').") ); return; } if ( ! confirmOverwrite ( sz, fConfirmSave ) ) return; if( !strcmp( sz, "-" ) ) pf = stdout; else if( !( pf = fopen( sz, "w" ) ) ) { outputerr( sz ); return; } HTMLPrologue ( pf, &ms, getGameNumber ( plGame ), NULL, exsExport.het, exsExport.hecss ); if ( exsExport.fIncludeMatchInfo ) HTMLMatchInfo ( pf, &mi, exsExport.hecss ); if ( fHistory ) iMove = getMoveNumber ( plGame, pmr ) - 1; else if ( plLastMove ) iMove = getMoveNumber ( plGame, plLastMove->p ); else iMove = -1; HTMLBoardHeader ( pf, &ms, exsExport.het, exsExport.hecss, getGameNumber ( plGame ), iMove, TRUE ); printHTMLBoard( pf, &ms, ms.fTurn, exsExport.szHTMLPictureURL, exsExport.szHTMLExtension, exsExport.het, exsExport.hecss ); if( pmr ) { HTMLAnalysis ( pf, &ms, pmr, exsExport.szHTMLPictureURL, exsExport.szHTMLExtension, exsExport.het, exsExport.hecss ); if ( exsExport.fIncludeAnnotation ) HTMLPrintComment ( pf, pmr, exsExport.hecss ); } HTMLEpilogue ( pf, &ms, NULL, exsExport.hecss ); if( pf != stdout ) fclose( pf ); setDefaultFileName ( sz, PATH_HTML ); /* external stylesheet */ if ( exsExport.hecss == HTML_EXPORT_CSS_EXTERNAL ) if ( ( pf = OpenCSS( sz ) ) ) WriteStyleSheet ( pf, exsExport.hecss ); } static void ExportPositionGammOnLine( FILE *pf ) { int fHistory; moverecord *pmr = getCurrentMoveRecord ( &fHistory ); int iMove; fputs ( "\n\n\n", pf ); fputs( "", pf ); fprintf( pf, ms.cGames == 1 ? _("The score (after %d game) is: %s %d, %s %d") : _("The score (after %d games) is: %s %d, %s %d"), ms.cGames, ap[ 0 ].szName, ms.anScore[ 0 ], ap[ 1 ].szName, ms.anScore[ 1 ] ); if ( ms.nMatchTo > 0 ) fprintf( pf, ms.nMatchTo == 1 ? _(" (match to %d point%s)") : _(" (match to %d points%s)"), ms.nMatchTo, ms.fCrawford ? _(", Crawford game") : ( ms.fPostCrawford ? _(", post-Crawford play") : "")); fputs( "\n", pf ); fputs ( "\n\n\n", pf ); if ( fHistory ) iMove = getMoveNumber ( plGame, pmr ) - 1; else if ( plLastMove ) iMove = getMoveNumber ( plGame, plLastMove->p ); else iMove = -1; HTMLBoardHeader ( pf, &ms, HTML_EXPORT_TYPE_BBS, HTML_EXPORT_CSS_INLINE, getGameNumber ( plGame ), iMove, FALSE ); printHTMLBoard( pf, &ms, ms.fTurn, #ifdef GAMMONLINE_TEST "http://www.gammonline.com/demo/Images/", #else "../Images/", #endif "gif", HTML_EXPORT_TYPE_BBS, HTML_EXPORT_CSS_INLINE ); if( pmr ) { HTMLAnalysis ( pf, &ms, pmr, "../Images/", "gif", HTML_EXPORT_TYPE_BBS, HTML_EXPORT_CSS_INLINE ); HTMLPrintComment ( pf, pmr, HTML_EXPORT_CSS_INLINE ); } HTMLEpilogueComment ( pf ); } extern void CommandExportPositionGammOnLine ( char *sz ) { FILE *pf; sz = NextToken( &sz ); if( ms.gs == GAME_NONE ) { outputl( _("No game in progress (type `new game' to start one).") ); return; } if( !sz || !*sz ) { outputl( _("You must specify a file to export to (see `help export " "position html').") ); return; } if ( ! confirmOverwrite ( sz, fConfirmSave ) ) return; if( !strcmp( sz, "-" ) ) pf = stdout; else if( !( pf = fopen( sz, "w" ) ) ) { outputerr( sz ); return; } ExportPositionGammOnLine( pf ); if( pf != stdout ) fclose( pf ); } extern void CommandExportPositionGOL2Clipboard( char *sz ) { char *szClipboard; long l; FILE *pf; if( ms.gs == GAME_NONE ) { outputl( _("No game in progress (type `new game' to start one).") ); return; } /* get tmp file name */ if ( ! ( pf = tmpfile() ) ) { outputerr("temporary file"); return; } /* generate file */ ExportPositionGammOnLine( pf ); /* find size of file */ if ( fseek( pf, 0L, SEEK_END ) ) { outputerr( "temporary file" ); return; } l = ftell( pf ); if ( fseek( pf, 0L, SEEK_SET ) ) { outputerr( "temporary file" ); return; } /* copy file to clipboard */ szClipboard = (char *) malloc ( l + 1 ); fread( szClipboard, 1, l + 1, pf ); szClipboard[ l ] = 0; TextToClipboard( szClipboard ); free( szClipboard ); fclose( pf ); }