If you don't have a version already, you can install GNU
libiconv (http://www.gnu.org/software/libiconv/).
-The following package is required to enable PSPP's graphing features.
-If you cannot arrange to install it, you must run `configure' with
---without-libplot.
+The following packages are required to enable PSPP's graphing
+features. If you cannot arrange to install them, you must run
+`configure' with --without-cairo.
- * libplot, from GNU plotutils
- (http://www.gnu.org/software/plotutils/).
+ * Cairo (http://cairographics.org/), version 1.5 or later.
+
+ * Pango (http://www.pango.org/), version 1.22 or later.
The following packages are required to enable PSPPIRE, the graphical
user interface for PSPP. If you cannot install them or do not wish to
Optional Features
=================
-`--without-libplot'
- Don't compile in support for charts (using libplot). This is
- useful if your system doesn't have the libplot library.
+`--without-cairo'
+ Don't compile in support for charts (using Cairo and Pango). This
+ is useful if your system lacks these libraries.
`--without-gui'
Don't build the PSPPIRE gui. Use this option if you only want to
build the command line version of PSPP.
+ Cairo and Pango required to build the GUI, so --without-cairo
+ implies --without-gui.
+
`--with-gui-tools'
Build the gui developer tools. There is no reason to use this
option unless you're involved with the development of PSPP
PSPP NEWS -- history of user-visible changes.
-Time-stamp: <2009-10-06 20:46:21 blp>
+Time-stamp: <2009-12-05 20:39:07 blp>
Copyright (C) 1996-9, 2000, 2008, 2009 Free Software Foundation, Inc.
See the end for copying conditions.
Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
+Changes from 0.7.2 to 0.7.3:
+
+ * Charts are now produced with Cairo and Pango, instead of libplot.
+ Without them, the new graphing features will not work. If you do
+ not have Cairo and Pango installed, you must run `configure' with
+ --without-cairo.
+
+ * The PostScript driver has been removed.
+
Changes from 0.7.1 to 0.7.2:
* Updated Perl module interface.
* François Pinard for advice on proceeding with development.
* Jim Van Zandt for Debian packaging and suggestions.
-
- * The authors of libplot and libgsl for providing those libraries.
AC_SUBST([VERSION_FOR_PERL])
])
-dnl Check that libplot is available.
-AC_DEFUN([PSPP_LIBPLOT],
-[
- AC_ARG_WITH(
- libplot,
- [AS_HELP_STRING([--without-libplot],
- [don't compile in support of charts (using libplot)])])
-
- if test x"$with_libplot" != x"no" ; then
- # Check whether we can link against libplot without any extra libraries.
- AC_CHECK_LIB(plot, pl_newpl_r, [LIBPLOT_LIBS="-lplot"])
-
- # Check whether we can link against libplot if we also link X.
- if test x"$LIBPLOT_LIBS" = x""; then
- AC_PATH_XTRA
- extra_libs="-lXaw -lXmu -lXt $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS -lm"
- AC_CHECK_LIB(plot, pl_newpl_r,
- [LIBPLOT_LIBS="-lplot $extra_libs"
- LDFLAGS="$LDFLAGS $X_LIBS"],,
- [$extra_libs])
- fi
-
- # Still can't link?
- if test x"$LIBPLOT_LIBS" = x""; then
- PSPP_REQUIRED_PREREQ([libplot (or use --without-libplot)])
- fi
-
- # Set up to make everything work.
- LIBS="$LIBPLOT_LIBS $LIBS"
- AC_DEFINE(HAVE_LIBPLOT, 1,
- [Define to 1 if you have the `libplot' library (-lplot).])
- fi
-])
-
dnl PSPP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED])
dnl Check whether the given C compiler OPTION is accepted.
dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED.
dist_pkgsysconf_DATA = \
config/devices
-psfontsdir = $(pkgsysconfdir)/psfonts
-dist_psfonts_DATA = \
- config/psfonts/Helvetica-Bold.afm \
- config/psfonts/Times-Bold.afm \
- config/psfonts/Courier-Bold.afm \
- config/psfonts/Helvetica-BoldOblique.afm \
- config/psfonts/Times-BoldItalic.afm \
- config/psfonts/Courier-BoldOblique.afm \
- config/psfonts/Helvetica-Oblique.afm \
- config/psfonts/Times-Italic.afm \
- config/psfonts/Courier-Oblique.afm \
- config/psfonts/Helvetica.afm \
- config/psfonts/Times-Roman.afm \
- config/psfonts/Courier.afm
-
EXTRA_DIST += config/OChangeLog
# PostScript device.
list-ps:postscript::
+# Cairo devices.
+pdf:cairo:listing:
+svg:cairo:listing:output-type=svg output-file="pspp.svg"
+ps-cairo:cairo:listing:output-type=ps output-file="pspp-cairo.ps"
+
+odt:odf:listing:debug=off output-file="pspp.odt"
+
# Devices that support the IBM PC line-drawing characters.
define ibmpc-graphics \
box[0000]='\x20' box[0001]='\xb3' box[0002]='\xba' \
list-ibmpc:ascii:listing:length=66 width=79 output-file=${list-output-file} \
${ibmpc-graphics}
+# Devices that support Unicode line-drawing characters in UTF-8 encoding.
+# PSPP doesn't support a \u escape but if it did then this is how these
+# would appear:
+#
+# define utf8-graphics \
+# box[0000]='\u0020' box[1000]='\u2576' box[2000]='\u2550' \
+# box[0100]='\u2577' box[1100]='\u256D' box[2100]='\u2552' \
+# box[0200]='\u2551' box[1200]='\u2553' box[2200]='\u2554' \
+# box[0010]='\u2574' box[1010]='\u2500' box[2010]='\u2550' \
+# box[0110]='\u256E' box[1110]='\u252C' box[2110]='\u2564' \
+# box[0210]='\u2556' box[1210]='\u2565' box[2210]='\u2566' \
+# box[0020]='\u2550' box[1020]='\u2550' box[2020]='\u2550' \
+# box[0120]='\u2555' box[1120]='\u2564' box[2120]='\u2564' \
+# box[0220]='\u2557' box[1220]='\u2566' box[2220]='\u2566' \
+# box[0001]='\u2575' box[1001]='\u2570' box[2001]='\u2558' \
+# box[0101]='\u2502' box[1101]='\u251C' box[2101]='\u255E' \
+# box[0201]='\u2551' box[1201]='\u255F' box[2201]='\u2560' \
+# box[0011]='\u256F' box[1011]='\u2534' box[2011]='\u2567' \
+# box[0111]='\u2524' box[1111]='\u253C' box[2111]='\u256A' \
+# box[0211]='\u2562' box[1211]='\u256B' box[2211]='\u256C' \
+# box[0021]='\u255B' box[1021]='\u2567' box[2021]='\u2567' \
+# box[0121]='\u2561' box[1121]='\u256A' box[2121]='\u256A' \
+# box[0221]='\u2563' box[1221]='\u256C' box[2221]='\u256C' \
+# box[0002]='\u2551' box[1002]='\u2559' box[2002]='\u255A' \
+# box[0102]='\u2551' box[1102]='\u255F' box[2102]='\u2560' \
+# box[0202]='\u2551' box[1202]='\u255F' box[2202]='\u2560' \
+# box[0012]='\u255C' box[1012]='\u2568' box[2012]='\u2569' \
+# box[0112]='\u2562' box[1112]='\u256A' box[2112]='\u256C' \
+# box[0212]='\u2562' box[1212]='\u256B' box[2212]='\u256C' \
+# box[0022]='\u255D' box[1022]='\u2569' box[2022]='\u2569' \
+# box[0122]='\u2563' box[1122]='\u256C' box[2122]='\u256C' \
+# box[0222]='\u2563' box[1222]='\u256C' box[2222]='\u256C'
+#
+# Instead, we encode them in UTF-8 by hand below.
+#
+# Here is a little Perl program that I used to do this translation:
+#
+# sub utf8_encode {
+# my $val = hex($_[0]);
+# my $d0 = 0xe0 | ($val >> 12);
+# my $d1 = 0x80 | (($val >> 6) & 0x3f);
+# my $d2 = 0x80 | ($val & 0x3f);
+# return sprintf('\x%02x\x%02x\x%02x', $d0, $d1, $d2);
+# }
+# while (<>) {
+# s/\\u(....)/utf8_encode($1)/ge;
+# print $_;
+# }
+#
+define utf8-graphics \
+ box[0000]='\xe0\x80\xa0' box[1000]='\xe2\x95\xb6' box[2000]='\xe2\x95\x90' \
+ box[0100]='\xe2\x95\xb7' box[1100]='\xe2\x95\xad' box[2100]='\xe2\x95\x92' \
+ box[0200]='\xe2\x95\x91' box[1200]='\xe2\x95\x93' box[2200]='\xe2\x95\x94' \
+ box[0010]='\xe2\x95\xb4' box[1010]='\xe2\x94\x80' box[2010]='\xe2\x95\x90' \
+ box[0110]='\xe2\x95\xae' box[1110]='\xe2\x94\xac' box[2110]='\xe2\x95\xa4' \
+ box[0210]='\xe2\x95\x96' box[1210]='\xe2\x95\xa5' box[2210]='\xe2\x95\xa6' \
+ box[0020]='\xe2\x95\x90' box[1020]='\xe2\x95\x90' box[2020]='\xe2\x95\x90' \
+ box[0120]='\xe2\x95\x95' box[1120]='\xe2\x95\xa4' box[2120]='\xe2\x95\xa4' \
+ box[0220]='\xe2\x95\x97' box[1220]='\xe2\x95\xa6' box[2220]='\xe2\x95\xa6' \
+ box[0001]='\xe2\x95\xb5' box[1001]='\xe2\x95\xb0' box[2001]='\xe2\x95\x98' \
+ box[0101]='\xe2\x94\x82' box[1101]='\xe2\x94\x9c' box[2101]='\xe2\x95\x9e' \
+ box[0201]='\xe2\x95\x91' box[1201]='\xe2\x95\x9f' box[2201]='\xe2\x95\xa0' \
+ box[0011]='\xe2\x95\xaf' box[1011]='\xe2\x94\xb4' box[2011]='\xe2\x95\xa7' \
+ box[0111]='\xe2\x94\xa4' box[1111]='\xe2\x94\xbc' box[2111]='\xe2\x95\xaa' \
+ box[0211]='\xe2\x95\xa2' box[1211]='\xe2\x95\xab' box[2211]='\xe2\x95\xac' \
+ box[0021]='\xe2\x95\x9b' box[1021]='\xe2\x95\xa7' box[2021]='\xe2\x95\xa7' \
+ box[0121]='\xe2\x95\xa1' box[1121]='\xe2\x95\xaa' box[2121]='\xe2\x95\xaa' \
+ box[0221]='\xe2\x95\xa3' box[1221]='\xe2\x95\xac' box[2221]='\xe2\x95\xac' \
+ box[0002]='\xe2\x95\x91' box[1002]='\xe2\x95\x99' box[2002]='\xe2\x95\x9a' \
+ box[0102]='\xe2\x95\x91' box[1102]='\xe2\x95\x9f' box[2102]='\xe2\x95\xa0' \
+ box[0202]='\xe2\x95\x91' box[1202]='\xe2\x95\x9f' box[2202]='\xe2\x95\xa0' \
+ box[0012]='\xe2\x95\x9c' box[1012]='\xe2\x95\xa8' box[2012]='\xe2\x95\xa9' \
+ box[0112]='\xe2\x95\xa2' box[1112]='\xe2\x95\xaa' box[2112]='\xe2\x95\xac' \
+ box[0212]='\xe2\x95\xa2' box[1212]='\xe2\x95\xab' box[2212]='\xe2\x95\xac' \
+ box[0022]='\xe2\x95\x9d' box[1022]='\xe2\x95\xa9' box[2022]='\xe2\x95\xa9' \
+ box[0122]='\xe2\x95\xa3' box[1122]='\xe2\x95\xac' box[2122]='\xe2\x95\xac' \
+ box[0222]='\xe2\x95\xa3' box[1222]='\xe2\x95\xac' box[2222]='\xe2\x95\xac'
+
+tty-utf8:ascii:screen:length=$viewlength width=$viewwidth ${utf8-graphics} \
+ output-file=${tty-output-file} emphasis=none
+list-utf8:ascii:listing:length=66 width=79 output-file=${list-output-file} \
+ ${utf8-graphics} emphasis=none
+
# Local Variables:
# fill-prefix: "# "
# End:
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 16:13:14 1990
-Comment UniqueID 27058
-Comment VMusage 28444 40812
-FontName Courier-Bold
-FullName Courier Bold
-FamilyName Courier
-Weight Bold
-ItalicAngle 0
-IsFixedPitch true
-FontBBox -40 -206 786 801
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 439
-Ascender 626
-Descender -142
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 212 -15 388 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 145 297 455 562 ;
-C 35 ; WX 600 ; N numbersign ; B 66 -45 534 651 ;
-C 36 ; WX 600 ; N dollar ; B 92 -126 509 666 ;
-C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
-C 38 ; WX 600 ; N ampersand ; B 46 -15 536 543 ;
-C 39 ; WX 600 ; N quoteright ; B 188 297 412 562 ;
-C 40 ; WX 600 ; N parenleft ; B 229 -102 451 616 ;
-C 41 ; WX 600 ; N parenright ; B 149 -102 371 616 ;
-C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
-C 43 ; WX 600 ; N plus ; B 81 0 519 439 ;
-C 44 ; WX 600 ; N comma ; B 140 -101 374 164 ;
-C 45 ; WX 600 ; N hyphen ; B 110 213 490 303 ;
-C 46 ; WX 600 ; N period ; B 206 -15 394 151 ;
-C 47 ; WX 600 ; N slash ; B 105 -77 496 626 ;
-C 48 ; WX 600 ; N zero ; B 97 -15 503 616 ;
-C 49 ; WX 600 ; N one ; B 91 0 529 616 ;
-C 50 ; WX 600 ; N two ; B 71 0 489 616 ;
-C 51 ; WX 600 ; N three ; B 73 -15 491 616 ;
-C 52 ; WX 600 ; N four ; B 63 0 497 616 ;
-C 53 ; WX 600 ; N five ; B 80 -15 511 601 ;
-C 54 ; WX 600 ; N six ; B 100 -15 511 616 ;
-C 55 ; WX 600 ; N seven ; B 65 0 484 601 ;
-C 56 ; WX 600 ; N eight ; B 93 -15 507 616 ;
-C 57 ; WX 600 ; N nine ; B 89 -15 500 616 ;
-C 58 ; WX 600 ; N colon ; B 206 -15 394 405 ;
-C 59 ; WX 600 ; N semicolon ; B 140 -101 394 405 ;
-C 60 ; WX 600 ; N less ; B 66 -15 503 453 ;
-C 61 ; WX 600 ; N equal ; B 81 89 519 349 ;
-C 62 ; WX 600 ; N greater ; B 97 -15 534 453 ;
-C 63 ; WX 600 ; N question ; B 108 -15 491 580 ;
-C 64 ; WX 600 ; N at ; B 26 -15 574 616 ;
-C 65 ; WX 600 ; N A ; B 1 0 599 562 ;
-C 66 ; WX 600 ; N B ; B 40 0 563 562 ;
-C 67 ; WX 600 ; N C ; B 32 -18 554 580 ;
-C 68 ; WX 600 ; N D ; B 40 0 584 562 ;
-C 69 ; WX 600 ; N E ; B 40 0 545 562 ;
-C 70 ; WX 600 ; N F ; B 54 0 555 562 ;
-C 71 ; WX 600 ; N G ; B 32 -18 584 580 ;
-C 72 ; WX 600 ; N H ; B 30 0 570 562 ;
-C 73 ; WX 600 ; N I ; B 87 0 513 562 ;
-C 74 ; WX 600 ; N J ; B 47 -18 591 562 ;
-C 75 ; WX 600 ; N K ; B 36 0 584 562 ;
-C 76 ; WX 600 ; N L ; B 49 0 568 562 ;
-C 77 ; WX 600 ; N M ; B 3 0 597 562 ;
-C 78 ; WX 600 ; N N ; B 18 -12 600 562 ;
-C 79 ; WX 600 ; N O ; B 32 -18 568 580 ;
-C 80 ; WX 600 ; N P ; B 58 0 549 562 ;
-C 81 ; WX 600 ; N Q ; B 32 -123 568 580 ;
-C 82 ; WX 600 ; N R ; B 34 0 589 562 ;
-C 83 ; WX 600 ; N S ; B 57 -22 543 582 ;
-C 84 ; WX 600 ; N T ; B 31 0 569 562 ;
-C 85 ; WX 600 ; N U ; B 14 -18 586 562 ;
-C 86 ; WX 600 ; N V ; B -3 0 603 562 ;
-C 87 ; WX 600 ; N W ; B -8 0 608 562 ;
-C 88 ; WX 600 ; N X ; B 22 0 578 562 ;
-C 89 ; WX 600 ; N Y ; B 22 0 579 562 ;
-C 90 ; WX 600 ; N Z ; B 72 0 529 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 255 -102 465 616 ;
-C 92 ; WX 600 ; N backslash ; B 105 -77 496 626 ;
-C 93 ; WX 600 ; N bracketright ; B 135 -102 345 616 ;
-C 94 ; WX 600 ; N asciicircum ; B 108 249 492 616 ;
-C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 188 297 412 562 ;
-C 97 ; WX 600 ; N a ; B 45 -15 560 454 ;
-C 98 ; WX 600 ; N b ; B 10 -15 574 626 ;
-C 99 ; WX 600 ; N c ; B 50 -15 539 459 ;
-C 100 ; WX 600 ; N d ; B 30 -15 581 626 ;
-C 101 ; WX 600 ; N e ; B 50 -15 553 454 ;
-C 102 ; WX 600 ; N f ; B 93 0 537 626 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 40 -146 570 454 ;
-C 104 ; WX 600 ; N h ; B 15 0 582 626 ;
-C 105 ; WX 600 ; N i ; B 87 0 513 648 ;
-C 106 ; WX 600 ; N j ; B 73 -146 430 648 ;
-C 107 ; WX 600 ; N k ; B 30 0 575 626 ;
-C 108 ; WX 600 ; N l ; B 87 0 513 626 ;
-C 109 ; WX 600 ; N m ; B -12 0 616 454 ;
-C 110 ; WX 600 ; N n ; B 28 0 582 454 ;
-C 111 ; WX 600 ; N o ; B 40 -15 560 454 ;
-C 112 ; WX 600 ; N p ; B 9 -142 560 454 ;
-C 113 ; WX 600 ; N q ; B 30 -142 581 454 ;
-C 114 ; WX 600 ; N r ; B 57 0 570 454 ;
-C 115 ; WX 600 ; N s ; B 78 -17 525 459 ;
-C 116 ; WX 600 ; N t ; B 57 -15 522 562 ;
-C 117 ; WX 600 ; N u ; B 9 -15 559 439 ;
-C 118 ; WX 600 ; N v ; B 9 0 591 439 ;
-C 119 ; WX 600 ; N w ; B -8 0 608 439 ;
-C 120 ; WX 600 ; N x ; B 16 0 584 439 ;
-C 121 ; WX 600 ; N y ; B 6 -142 591 439 ;
-C 122 ; WX 600 ; N z ; B 91 0 510 439 ;
-C 123 ; WX 600 ; N braceleft ; B 170 -102 454 616 ;
-C 124 ; WX 600 ; N bar ; B 255 -77 345 626 ;
-C 125 ; WX 600 ; N braceright ; B 146 -102 430 616 ;
-C 126 ; WX 600 ; N asciitilde ; B 81 124 520 307 ;
-C 161 ; WX 600 ; N exclamdown ; B 212 -146 388 449 ;
-C 162 ; WX 600 ; N cent ; B 76 -49 508 614 ;
-C 163 ; WX 600 ; N sterling ; B 82 -28 548 611 ;
-C 164 ; WX 600 ; N fraction ; B 30 -60 571 661 ;
-C 165 ; WX 600 ; N yen ; B 20 0 580 591 ;
-C 166 ; WX 600 ; N florin ; B -20 -131 562 616 ;
-C 167 ; WX 600 ; N section ; B 103 -70 497 580 ;
-C 168 ; WX 600 ; N currency ; B 54 49 546 517 ;
-C 169 ; WX 600 ; N quotesingle ; B 237 297 363 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 81 297 519 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
-C 174 ; WX 600 ; N fi ; B 22 0 583 626 ;
-C 175 ; WX 600 ; N fl ; B 22 0 583 626 ;
-C 177 ; WX 600 ; N endash ; B 75 213 525 303 ;
-C 178 ; WX 600 ; N dagger ; B 116 -70 484 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 116 -70 484 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 206 136 394 302 ;
-C 182 ; WX 600 ; N paragraph ; B 16 -70 566 580 ;
-C 183 ; WX 600 ; N bullet ; B 150 142 450 420 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 188 -140 412 125 ;
-C 185 ; WX 600 ; N quotedblbase ; B 81 -140 519 125 ;
-C 186 ; WX 600 ; N quotedblright ; B 81 297 519 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 36 -15 564 96 ;
-C 189 ; WX 600 ; N perthousand ; B -40 -15 786 616 ;
-C 191 ; WX 600 ; N questiondown ; B 109 -146 492 449 ;
-C 193 ; WX 600 ; N grave ; B 132 508 395 661 ;
-C 194 ; WX 600 ; N acute ; B 205 508 468 661 ;
-C 195 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
-C 196 ; WX 600 ; N tilde ; B 89 493 512 636 ;
-C 197 ; WX 600 ; N macron ; B 88 505 512 585 ;
-C 198 ; WX 600 ; N breve ; B 83 468 517 631 ;
-C 199 ; WX 600 ; N dotaccent ; B 240 505 360 625 ;
-C 200 ; WX 600 ; N dieresis ; B 148 505 452 625 ;
-C 202 ; WX 600 ; N ring ; B 198 481 402 678 ;
-C 203 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 95 508 578 661 ;
-C 206 ; WX 600 ; N ogonek ; B 169 -199 367 0 ;
-C 207 ; WX 600 ; N caron ; B 103 493 497 667 ;
-C 208 ; WX 600 ; N emdash ; B 0 213 600 303 ;
-C 225 ; WX 600 ; N AE ; B -29 0 562 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
-C 232 ; WX 600 ; N Lslash ; B 49 0 568 562 ;
-C 233 ; WX 600 ; N Oslash ; B 32 -22 568 584 ;
-C 234 ; WX 600 ; N OE ; B 0 0 570 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
-C 241 ; WX 600 ; N ae ; B 6 -15 591 454 ;
-C 245 ; WX 600 ; N dotlessi ; B 87 0 513 439 ;
-C 248 ; WX 600 ; N lslash ; B 87 0 513 626 ;
-C 249 ; WX 600 ; N oslash ; B 40 -24 560 463 ;
-C 250 ; WX 600 ; N oe ; B -8 -15 601 454 ;
-C 251 ; WX 600 ; N germandbls ; B 32 -15 586 626 ;
-C -1 ; WX 600 ; N scedilla ; B 78 -206 525 459 ;
-C -1 ; WX 600 ; N notegraphic ; B 87 -15 513 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 32 -18 568 780 ;
-C -1 ; WX 600 ; N ll ; B -2 0 590 626 ;
-C -1 ; WX 600 ; N otilde ; B 40 -15 560 636 ;
-C -1 ; WX 600 ; N scaron ; B 78 -17 525 667 ;
-C -1 ; WX 600 ; N divide ; B 81 -15 519 453 ;
-C -1 ; WX 600 ; N Thorn ; B 58 0 547 562 ;
-C -1 ; WX 600 ; N format ; B 5 -146 95 598 ;
-C -1 ; WX 600 ; N largebullet ; B 258 239 342 323 ;
-C -1 ; WX 600 ; N Eth ; B 40 0 584 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 32 -18 568 748 ;
-C -1 ; WX 600 ; N onesuperior ; B 158 230 442 616 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 582 290 ;
-C -1 ; WX 600 ; N Ydieresis ; B 22 0 579 748 ;
-C -1 ; WX 600 ; N merge ; B 144 -15 456 487 ;
-C -1 ; WX 600 ; N IJ ; B 2 -18 612 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 50 -206 539 459 ;
-C -1 ; WX 600 ; N multiply ; B 81 0 520 439 ;
-C -1 ; WX 600 ; N degree ; B 86 243 474 616 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 589 562 ;
-C -1 ; WX 600 ; N indent ; B 70 52 530 364 ;
-C -1 ; WX 600 ; N Otilde ; B 32 -18 568 759 ;
-C -1 ; WX 600 ; N thorn ; B -4 -142 560 626 ;
-C -1 ; WX 600 ; N mu ; B 9 -142 559 439 ;
-C -1 ; WX 600 ; N Yacute ; B 22 0 579 784 ;
-C -1 ; WX 600 ; N threesuperior ; B 148 222 423 616 ;
-C -1 ; WX 600 ; N logicalnot ; B 81 59 519 349 ;
-C -1 ; WX 600 ; N Ugrave ; B 14 -18 586 784 ;
-C -1 ; WX 600 ; N eth ; B 68 -27 533 626 ;
-C -1 ; WX 600 ; N left ; B 70 52 530 364 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 40 0 545 780 ;
-C -1 ; WX 600 ; N edieresis ; B 50 -15 553 625 ;
-C -1 ; WX 600 ; N Ograve ; B 32 -18 568 784 ;
-C -1 ; WX 600 ; N down ; B 144 -15 456 422 ;
-C -1 ; WX 600 ; N Agrave ; B 1 0 599 784 ;
-C -1 ; WX 600 ; N atilde ; B 45 -15 560 636 ;
-C -1 ; WX 600 ; N up ; B 144 0 456 437 ;
-C -1 ; WX 600 ; N eacute ; B 50 -15 553 661 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 525 599 ;
-C -1 ; WX 600 ; N lira ; B 82 -28 548 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 87 0 513 780 ;
-C -1 ; WX 600 ; N Adieresis ; B 1 0 599 748 ;
-C -1 ; WX 600 ; N yacute ; B 6 -142 591 661 ;
-C -1 ; WX 600 ; N icircumflex ; B 63 0 513 657 ;
-C -1 ; WX 600 ; N adieresis ; B 45 -15 560 625 ;
-C -1 ; WX 600 ; N zcaron ; B 91 0 510 667 ;
-C -1 ; WX 600 ; N Scaron ; B 57 -22 543 790 ;
-C -1 ; WX 600 ; N minus ; B 81 174 519 264 ;
-C -1 ; WX 600 ; N Aring ; B 1 0 599 801 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 14 -18 586 780 ;
-C -1 ; WX 600 ; N plusminus ; B 81 0 519 461 ;
-C -1 ; WX 600 ; N ograve ; B 40 -15 560 661 ;
-C -1 ; WX 600 ; N Edieresis ; B 40 0 545 748 ;
-C -1 ; WX 600 ; N brokenbar ; B 255 -77 345 626 ;
-C -1 ; WX 600 ; N Idieresis ; B 87 0 513 748 ;
-C -1 ; WX 600 ; N acircumflex ; B 45 -15 560 657 ;
-C -1 ; WX 600 ; N ydieresis ; B 6 -142 591 625 ;
-C -1 ; WX 600 ; N Oacute ; B 32 -18 568 784 ;
-C -1 ; WX 600 ; N Egrave ; B 40 0 545 784 ;
-C -1 ; WX 600 ; N center ; B 40 14 560 580 ;
-C -1 ; WX 600 ; N threequarters ; B -20 -60 675 661 ;
-C -1 ; WX 600 ; N tab ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 50 -15 553 657 ;
-C -1 ; WX 600 ; N Eacute ; B 40 0 545 784 ;
-C -1 ; WX 600 ; N trademark ; B -9 230 749 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N onehalf ; B -20 -60 675 661 ;
-C -1 ; WX 600 ; N onequarter ; B -20 -60 692 661 ;
-C -1 ; WX 600 ; N Uacute ; B 14 -18 586 784 ;
-C -1 ; WX 600 ; N Atilde ; B 1 0 599 759 ;
-C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N Igrave ; B 87 0 513 784 ;
-C -1 ; WX 600 ; N Iacute ; B 87 0 513 784 ;
-C -1 ; WX 600 ; N Acircumflex ; B 1 0 599 780 ;
-C -1 ; WX 600 ; N Udieresis ; B 14 -18 586 748 ;
-C -1 ; WX 600 ; N Gcaron ; B 32 -18 584 790 ;
-C -1 ; WX 600 ; N Aacute ; B 1 0 599 784 ;
-C -1 ; WX 600 ; N LL ; B -35 0 635 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 153 230 426 616 ;
-C -1 ; WX 600 ; N Scedilla ; B 57 -206 543 582 ;
-C -1 ; WX 600 ; N arrowboth ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N udieresis ; B 9 -15 559 625 ;
-C -1 ; WX 600 ; N odieresis ; B 40 -15 560 625 ;
-C -1 ; WX 600 ; N aring ; B 45 -15 560 678 ;
-C -1 ; WX 600 ; N ij ; B 16 -146 564 648 ;
-C -1 ; WX 600 ; N arrowdown ; B 144 -15 456 608 ;
-C -1 ; WX 600 ; N igrave ; B 87 0 513 661 ;
-C -1 ; WX 600 ; N aacute ; B 45 -15 560 661 ;
-C -1 ; WX 600 ; N stop ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 40 -15 560 657 ;
-C -1 ; WX 600 ; N gcaron ; B 40 -146 570 667 ;
-C -1 ; WX 600 ; N iacute ; B 87 0 513 661 ;
-C -1 ; WX 600 ; N Ntilde ; B 18 -12 600 759 ;
-C -1 ; WX 600 ; N idieresis ; B 87 0 513 625 ;
-C -1 ; WX 600 ; N Ccedilla ; B 32 -206 554 580 ;
-C -1 ; WX 600 ; N arrowright ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N ucircumflex ; B 9 -15 559 657 ;
-C -1 ; WX 600 ; N Idot ; B 87 0 513 748 ;
-C -1 ; WX 600 ; N agrave ; B 45 -15 560 661 ;
-C -1 ; WX 600 ; N ntilde ; B 28 0 582 636 ;
-C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N return ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 72 0 529 790 ;
-C -1 ; WX 600 ; N uacute ; B 9 -15 559 661 ;
-C -1 ; WX 600 ; N overscore ; B 0 579 600 629 ;
-C -1 ; WX 600 ; N egrave ; B 50 -15 553 661 ;
-C -1 ; WX 600 ; N ugrave ; B 9 -15 559 661 ;
-C -1 ; WX 600 ; N oacute ; B 40 -15 560 661 ;
-C -1 ; WX 600 ; N arrowleft ; B -24 143 624 455 ;
-C -1 ; WX 600 ; N arrowup ; B 144 0 456 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 30 123 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -30 123 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -20 123 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -50 123 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring -10 123 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde -30 123 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 30 123 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 0 123 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 0 123 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 0 123 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 10 123 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 123 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 123 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 123 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 123 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 0 123 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 0 123 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 0 123 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 0 123 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 0 123 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 0 123 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 0 123 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 20 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 30 123 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 0 123 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 0 123 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -30 123 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 30 123 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 0 123 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 0 123 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex -20 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis -10 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave -30 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -40 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -40 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -40 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave 0 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 0 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -20 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis -20 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 30 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 0 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 17:20:38 1990
-Comment UniqueID 27068
-Comment VMusage 6910 48006
-FontName Courier-BoldOblique
-FullName Courier Bold Oblique
-FamilyName Courier
-Weight Bold
-ItalicAngle -12
-IsFixedPitch true
-FontBBox -46 -206 868 801
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 439
-Ascender 626
-Descender -142
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 224 -15 484 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 226 297 574 562 ;
-C 35 ; WX 600 ; N numbersign ; B 100 -45 628 651 ;
-C 36 ; WX 600 ; N dollar ; B 97 -126 619 666 ;
-C 37 ; WX 600 ; N percent ; B 103 -15 624 616 ;
-C 38 ; WX 600 ; N ampersand ; B 72 -15 582 543 ;
-C 39 ; WX 600 ; N quoteright ; B 251 297 531 562 ;
-C 40 ; WX 600 ; N parenleft ; B 276 -102 582 616 ;
-C 41 ; WX 600 ; N parenright ; B 127 -102 434 616 ;
-C 42 ; WX 600 ; N asterisk ; B 179 219 597 601 ;
-C 43 ; WX 600 ; N plus ; B 118 0 575 439 ;
-C 44 ; WX 600 ; N comma ; B 119 -101 409 164 ;
-C 45 ; WX 600 ; N hyphen ; B 155 213 554 303 ;
-C 46 ; WX 600 ; N period ; B 219 -15 410 151 ;
-C 47 ; WX 600 ; N slash ; B 96 -77 622 626 ;
-C 48 ; WX 600 ; N zero ; B 146 -15 583 616 ;
-C 49 ; WX 600 ; N one ; B 103 0 547 616 ;
-C 50 ; WX 600 ; N two ; B 71 0 583 616 ;
-C 51 ; WX 600 ; N three ; B 82 -15 561 616 ;
-C 52 ; WX 600 ; N four ; B 92 0 544 616 ;
-C 53 ; WX 600 ; N five ; B 87 -15 611 601 ;
-C 54 ; WX 600 ; N six ; B 146 -15 642 616 ;
-C 55 ; WX 600 ; N seven ; B 157 0 612 601 ;
-C 56 ; WX 600 ; N eight ; B 125 -15 594 616 ;
-C 57 ; WX 600 ; N nine ; B 86 -15 582 616 ;
-C 58 ; WX 600 ; N colon ; B 219 -15 464 405 ;
-C 59 ; WX 600 ; N semicolon ; B 119 -101 464 405 ;
-C 60 ; WX 600 ; N less ; B 113 -15 584 453 ;
-C 61 ; WX 600 ; N equal ; B 100 89 593 349 ;
-C 62 ; WX 600 ; N greater ; B 109 -15 581 453 ;
-C 63 ; WX 600 ; N question ; B 193 -15 581 580 ;
-C 64 ; WX 600 ; N at ; B 76 -15 627 616 ;
-C 65 ; WX 600 ; N A ; B 1 0 617 562 ;
-C 66 ; WX 600 ; N B ; B 40 0 619 562 ;
-C 67 ; WX 600 ; N C ; B 85 -18 664 580 ;
-C 68 ; WX 600 ; N D ; B 40 0 654 562 ;
-C 69 ; WX 600 ; N E ; B 40 0 654 562 ;
-C 70 ; WX 600 ; N F ; B 54 0 668 562 ;
-C 71 ; WX 600 ; N G ; B 85 -18 664 580 ;
-C 72 ; WX 600 ; N H ; B 30 0 689 562 ;
-C 73 ; WX 600 ; N I ; B 87 0 632 562 ;
-C 74 ; WX 600 ; N J ; B 69 -18 710 562 ;
-C 75 ; WX 600 ; N K ; B 36 0 676 562 ;
-C 76 ; WX 600 ; N L ; B 49 0 625 562 ;
-C 77 ; WX 600 ; N M ; B 3 0 716 562 ;
-C 78 ; WX 600 ; N N ; B 18 -12 719 562 ;
-C 79 ; WX 600 ; N O ; B 84 -18 636 580 ;
-C 80 ; WX 600 ; N P ; B 58 0 634 562 ;
-C 81 ; WX 600 ; N Q ; B 84 -123 636 580 ;
-C 82 ; WX 600 ; N R ; B 34 0 607 562 ;
-C 83 ; WX 600 ; N S ; B 64 -22 662 582 ;
-C 84 ; WX 600 ; N T ; B 96 0 668 562 ;
-C 85 ; WX 600 ; N U ; B 116 -18 705 562 ;
-C 86 ; WX 600 ; N V ; B 99 0 722 562 ;
-C 87 ; WX 600 ; N W ; B 94 0 727 562 ;
-C 88 ; WX 600 ; N X ; B 22 0 679 562 ;
-C 89 ; WX 600 ; N Y ; B 124 0 698 562 ;
-C 90 ; WX 600 ; N Z ; B 72 0 626 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 233 -102 596 616 ;
-C 92 ; WX 600 ; N backslash ; B 231 -77 487 626 ;
-C 93 ; WX 600 ; N bracketright ; B 113 -102 476 616 ;
-C 94 ; WX 600 ; N asciicircum ; B 171 249 555 616 ;
-C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 251 297 531 562 ;
-C 97 ; WX 600 ; N a ; B 72 -15 578 454 ;
-C 98 ; WX 600 ; N b ; B 23 -15 626 626 ;
-C 99 ; WX 600 ; N c ; B 91 -15 621 459 ;
-C 100 ; WX 600 ; N d ; B 71 -15 634 626 ;
-C 101 ; WX 600 ; N e ; B 91 -15 594 454 ;
-C 102 ; WX 600 ; N f ; B 93 0 667 626 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 51 -146 663 454 ;
-C 104 ; WX 600 ; N h ; B 28 0 600 626 ;
-C 105 ; WX 600 ; N i ; B 87 0 531 648 ;
-C 106 ; WX 600 ; N j ; B 47 -146 568 648 ;
-C 107 ; WX 600 ; N k ; B 43 0 632 626 ;
-C 108 ; WX 600 ; N l ; B 87 0 531 626 ;
-C 109 ; WX 600 ; N m ; B -12 0 634 454 ;
-C 110 ; WX 600 ; N n ; B 28 0 600 454 ;
-C 111 ; WX 600 ; N o ; B 81 -15 612 454 ;
-C 112 ; WX 600 ; N p ; B -21 -142 612 454 ;
-C 113 ; WX 600 ; N q ; B 71 -142 674 454 ;
-C 114 ; WX 600 ; N r ; B 57 0 644 454 ;
-C 115 ; WX 600 ; N s ; B 77 -17 597 459 ;
-C 116 ; WX 600 ; N t ; B 132 -15 556 562 ;
-C 117 ; WX 600 ; N u ; B 84 -15 577 439 ;
-C 118 ; WX 600 ; N v ; B 84 0 684 439 ;
-C 119 ; WX 600 ; N w ; B 67 0 701 439 ;
-C 120 ; WX 600 ; N x ; B 16 0 660 439 ;
-C 121 ; WX 600 ; N y ; B -10 -142 684 439 ;
-C 122 ; WX 600 ; N z ; B 91 0 603 439 ;
-C 123 ; WX 600 ; N braceleft ; B 216 -102 585 616 ;
-C 124 ; WX 600 ; N bar ; B 239 -77 478 626 ;
-C 125 ; WX 600 ; N braceright ; B 124 -102 494 616 ;
-C 126 ; WX 600 ; N asciitilde ; B 120 124 573 307 ;
-C 161 ; WX 600 ; N exclamdown ; B 207 -146 468 449 ;
-C 162 ; WX 600 ; N cent ; B 131 -49 594 614 ;
-C 163 ; WX 600 ; N sterling ; B 117 -28 640 611 ;
-C 164 ; WX 600 ; N fraction ; B 27 -60 702 661 ;
-C 165 ; WX 600 ; N yen ; B 110 0 706 591 ;
-C 166 ; WX 600 ; N florin ; B -46 -131 691 616 ;
-C 167 ; WX 600 ; N section ; B 94 -70 599 580 ;
-C 168 ; WX 600 ; N currency ; B 77 49 643 517 ;
-C 169 ; WX 600 ; N quotesingle ; B 318 297 482 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 144 297 638 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 63 70 638 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 196 70 544 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 166 70 514 446 ;
-C 174 ; WX 600 ; N fi ; B 22 0 633 626 ;
-C 175 ; WX 600 ; N fl ; B 22 0 633 626 ;
-C 177 ; WX 600 ; N endash ; B 120 213 589 303 ;
-C 178 ; WX 600 ; N dagger ; B 188 -70 573 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 134 -70 574 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 251 136 442 302 ;
-C 182 ; WX 600 ; N paragraph ; B 71 -70 689 580 ;
-C 183 ; WX 600 ; N bullet ; B 207 142 513 420 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 158 -140 439 125 ;
-C 185 ; WX 600 ; N quotedblbase ; B 51 -140 546 125 ;
-C 186 ; WX 600 ; N quotedblright ; B 144 297 638 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 72 70 647 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 43 -15 574 96 ;
-C 189 ; WX 600 ; N perthousand ; B 24 -15 815 616 ;
-C 191 ; WX 600 ; N questiondown ; B 111 -146 499 449 ;
-C 193 ; WX 600 ; N grave ; B 272 508 503 661 ;
-C 194 ; WX 600 ; N acute ; B 313 508 608 661 ;
-C 195 ; WX 600 ; N circumflex ; B 212 483 606 657 ;
-C 196 ; WX 600 ; N tilde ; B 200 493 642 636 ;
-C 197 ; WX 600 ; N macron ; B 195 505 636 585 ;
-C 198 ; WX 600 ; N breve ; B 217 468 651 631 ;
-C 199 ; WX 600 ; N dotaccent ; B 359 505 482 625 ;
-C 200 ; WX 600 ; N dieresis ; B 267 505 574 625 ;
-C 202 ; WX 600 ; N ring ; B 319 481 528 678 ;
-C 203 ; WX 600 ; N cedilla ; B 169 -206 367 0 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 203 508 718 661 ;
-C 206 ; WX 600 ; N ogonek ; B 144 -199 350 0 ;
-C 207 ; WX 600 ; N caron ; B 238 493 632 667 ;
-C 208 ; WX 600 ; N emdash ; B 45 213 664 303 ;
-C 225 ; WX 600 ; N AE ; B -29 0 667 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 189 196 526 580 ;
-C 232 ; WX 600 ; N Lslash ; B 49 0 625 562 ;
-C 233 ; WX 600 ; N Oslash ; B 48 -22 672 584 ;
-C 234 ; WX 600 ; N OE ; B 51 0 675 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 189 196 542 580 ;
-C 241 ; WX 600 ; N ae ; B 30 -15 641 454 ;
-C 245 ; WX 600 ; N dotlessi ; B 87 0 531 439 ;
-C 248 ; WX 600 ; N lslash ; B 87 0 574 626 ;
-C 249 ; WX 600 ; N oslash ; B 54 -24 637 463 ;
-C 250 ; WX 600 ; N oe ; B 29 -15 651 454 ;
-C 251 ; WX 600 ; N germandbls ; B 32 -15 618 626 ;
-C -1 ; WX 600 ; N scedilla ; B 77 -206 597 459 ;
-C -1 ; WX 600 ; N notegraphic ; B 99 -15 609 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 84 -18 636 780 ;
-C -1 ; WX 600 ; N ll ; B 11 0 643 626 ;
-C -1 ; WX 600 ; N otilde ; B 81 -15 642 636 ;
-C -1 ; WX 600 ; N scaron ; B 77 -17 632 667 ;
-C -1 ; WX 600 ; N divide ; B 118 -15 575 453 ;
-C -1 ; WX 600 ; N Thorn ; B 58 0 613 562 ;
-C -1 ; WX 600 ; N format ; B -26 -146 222 598 ;
-C -1 ; WX 600 ; N largebullet ; B 317 239 403 323 ;
-C -1 ; WX 600 ; N Eth ; B 40 0 654 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 84 -18 636 748 ;
-C -1 ; WX 600 ; N onesuperior ; B 218 230 506 616 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 601 290 ;
-C -1 ; WX 600 ; N Ydieresis ; B 124 0 698 748 ;
-C -1 ; WX 600 ; N merge ; B 174 -15 526 487 ;
-C -1 ; WX 600 ; N IJ ; B 2 -18 731 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 91 -206 621 459 ;
-C -1 ; WX 600 ; N multiply ; B 94 0 600 439 ;
-C -1 ; WX 600 ; N degree ; B 173 243 569 616 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 632 562 ;
-C -1 ; WX 600 ; N indent ; B 106 52 574 364 ;
-C -1 ; WX 600 ; N Otilde ; B 84 -18 668 759 ;
-C -1 ; WX 600 ; N thorn ; B -21 -142 612 626 ;
-C -1 ; WX 600 ; N mu ; B 60 -142 577 439 ;
-C -1 ; WX 600 ; N Yacute ; B 124 0 698 784 ;
-C -1 ; WX 600 ; N threesuperior ; B 203 222 515 616 ;
-C -1 ; WX 600 ; N logicalnot ; B 136 59 593 349 ;
-C -1 ; WX 600 ; N Ugrave ; B 116 -18 705 784 ;
-C -1 ; WX 600 ; N eth ; B 103 -27 651 626 ;
-C -1 ; WX 600 ; N left ; B 114 52 582 364 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 40 0 654 780 ;
-C -1 ; WX 600 ; N edieresis ; B 91 -15 594 625 ;
-C -1 ; WX 600 ; N Ograve ; B 84 -18 636 784 ;
-C -1 ; WX 600 ; N down ; B 174 -15 486 422 ;
-C -1 ; WX 600 ; N Agrave ; B 1 0 617 784 ;
-C -1 ; WX 600 ; N atilde ; B 72 -15 642 636 ;
-C -1 ; WX 600 ; N up ; B 204 0 516 437 ;
-C -1 ; WX 600 ; N eacute ; B 91 -15 608 661 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 652 599 ;
-C -1 ; WX 600 ; N lira ; B 117 -28 640 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 87 0 632 780 ;
-C -1 ; WX 600 ; N Adieresis ; B 1 0 617 748 ;
-C -1 ; WX 600 ; N yacute ; B -10 -142 684 661 ;
-C -1 ; WX 600 ; N icircumflex ; B 87 0 566 657 ;
-C -1 ; WX 600 ; N adieresis ; B 72 -15 578 625 ;
-C -1 ; WX 600 ; N zcaron ; B 91 0 632 667 ;
-C -1 ; WX 600 ; N Scaron ; B 64 -22 662 790 ;
-C -1 ; WX 600 ; N minus ; B 118 174 575 264 ;
-C -1 ; WX 600 ; N Aring ; B 1 0 617 801 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 116 -18 705 780 ;
-C -1 ; WX 600 ; N plusminus ; B 81 0 592 461 ;
-C -1 ; WX 600 ; N ograve ; B 81 -15 612 661 ;
-C -1 ; WX 600 ; N Edieresis ; B 40 0 654 748 ;
-C -1 ; WX 600 ; N brokenbar ; B 239 -77 478 626 ;
-C -1 ; WX 600 ; N Idieresis ; B 87 0 632 748 ;
-C -1 ; WX 600 ; N acircumflex ; B 72 -15 586 657 ;
-C -1 ; WX 600 ; N ydieresis ; B -10 -142 684 625 ;
-C -1 ; WX 600 ; N Oacute ; B 84 -18 636 784 ;
-C -1 ; WX 600 ; N Egrave ; B 40 0 654 784 ;
-C -1 ; WX 600 ; N center ; B 103 14 623 580 ;
-C -1 ; WX 600 ; N threequarters ; B 35 -60 725 661 ;
-C -1 ; WX 600 ; N tab ; B 19 0 641 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 91 -15 606 657 ;
-C -1 ; WX 600 ; N Eacute ; B 40 0 665 784 ;
-C -1 ; WX 600 ; N trademark ; B 86 230 868 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N onehalf ; B 50 -60 742 661 ;
-C -1 ; WX 600 ; N onequarter ; B 50 -60 742 661 ;
-C -1 ; WX 600 ; N Uacute ; B 116 -18 705 784 ;
-C -1 ; WX 600 ; N Atilde ; B 1 0 638 759 ;
-C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N Igrave ; B 87 0 632 784 ;
-C -1 ; WX 600 ; N Iacute ; B 87 0 635 784 ;
-C -1 ; WX 600 ; N Acircumflex ; B 1 0 617 780 ;
-C -1 ; WX 600 ; N Udieresis ; B 116 -18 705 748 ;
-C -1 ; WX 600 ; N Gcaron ; B 85 -18 669 790 ;
-C -1 ; WX 600 ; N Aacute ; B 1 0 665 784 ;
-C -1 ; WX 600 ; N LL ; B -35 0 684 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 202 230 531 616 ;
-C -1 ; WX 600 ; N Scedilla ; B 64 -206 662 582 ;
-C -1 ; WX 600 ; N arrowboth ; B 40 143 688 455 ;
-C -1 ; WX 600 ; N udieresis ; B 84 -15 577 625 ;
-C -1 ; WX 600 ; N odieresis ; B 81 -15 612 625 ;
-C -1 ; WX 600 ; N aring ; B 72 -15 578 678 ;
-C -1 ; WX 600 ; N ij ; B 16 -146 702 648 ;
-C -1 ; WX 600 ; N arrowdown ; B 174 -15 486 608 ;
-C -1 ; WX 600 ; N igrave ; B 87 0 531 661 ;
-C -1 ; WX 600 ; N aacute ; B 72 -15 608 661 ;
-C -1 ; WX 600 ; N stop ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 81 -15 612 657 ;
-C -1 ; WX 600 ; N gcaron ; B 51 -146 663 667 ;
-C -1 ; WX 600 ; N iacute ; B 87 0 608 661 ;
-C -1 ; WX 600 ; N Ntilde ; B 18 -12 719 759 ;
-C -1 ; WX 600 ; N idieresis ; B 87 0 534 625 ;
-C -1 ; WX 600 ; N Ccedilla ; B 85 -206 664 580 ;
-C -1 ; WX 600 ; N arrowright ; B 32 143 688 455 ;
-C -1 ; WX 600 ; N ucircumflex ; B 84 -15 586 657 ;
-C -1 ; WX 600 ; N Idot ; B 87 0 632 748 ;
-C -1 ; WX 600 ; N agrave ; B 72 -15 578 661 ;
-C -1 ; WX 600 ; N ntilde ; B 28 0 642 636 ;
-C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N return ; B 79 0 700 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 72 0 659 790 ;
-C -1 ; WX 600 ; N uacute ; B 84 -15 608 661 ;
-C -1 ; WX 600 ; N overscore ; B 123 579 734 629 ;
-C -1 ; WX 600 ; N egrave ; B 91 -15 594 661 ;
-C -1 ; WX 600 ; N ugrave ; B 84 -15 577 661 ;
-C -1 ; WX 600 ; N oacute ; B 81 -15 612 661 ;
-C -1 ; WX 600 ; N arrowleft ; B 40 143 695 455 ;
-C -1 ; WX 600 ; N arrowup ; B 243 0 555 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 56 123 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -4 123 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 6 123 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -24 123 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 16 123 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde -4 123 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 56 123 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 26 123 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 26 123 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 26 123 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 36 123 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 26 123 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 26 123 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 26 123 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 26 123 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 26 123 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 26 123 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 26 123 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 26 123 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 26 123 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 26 123 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 26 123 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 20 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 56 123 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 26 123 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 26 123 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -4 123 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 56 123 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 26 123 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 26 123 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex -20 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis -10 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave -30 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -40 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -40 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -40 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave 0 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 0 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -20 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis -20 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 30 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 0 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 18:32:01 1990
-Comment UniqueID 27082
-Comment VMusage 6415 46660
-FontName Courier-Oblique
-FullName Courier Oblique
-FamilyName Courier
-Weight Medium
-ItalicAngle -12
-IsFixedPitch true
-FontBBox -30 -157 734 805
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 426
-Ascender 629
-Descender -157
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 243 -15 457 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
-C 35 ; WX 600 ; N numbersign ; B 142 -32 587 639 ;
-C 36 ; WX 600 ; N dollar ; B 115 -126 589 662 ;
-C 37 ; WX 600 ; N percent ; B 147 -15 596 622 ;
-C 38 ; WX 600 ; N ampersand ; B 94 -15 572 543 ;
-C 39 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
-C 40 ; WX 600 ; N parenleft ; B 320 -108 565 622 ;
-C 41 ; WX 600 ; N parenright ; B 144 -108 389 622 ;
-C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
-C 43 ; WX 600 ; N plus ; B 128 0 562 426 ;
-C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
-C 45 ; WX 600 ; N hyphen ; B 161 238 549 278 ;
-C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
-C 47 ; WX 600 ; N slash ; B 111 -80 606 629 ;
-C 48 ; WX 600 ; N zero ; B 161 -15 568 622 ;
-C 49 ; WX 600 ; N one ; B 105 0 505 622 ;
-C 50 ; WX 600 ; N two ; B 77 0 561 622 ;
-C 51 ; WX 600 ; N three ; B 89 -15 531 622 ;
-C 52 ; WX 600 ; N four ; B 120 0 532 622 ;
-C 53 ; WX 600 ; N five ; B 105 -15 589 607 ;
-C 54 ; WX 600 ; N six ; B 162 -15 629 622 ;
-C 55 ; WX 600 ; N seven ; B 191 0 605 607 ;
-C 56 ; WX 600 ; N eight ; B 139 -15 581 622 ;
-C 57 ; WX 600 ; N nine ; B 100 -15 567 622 ;
-C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
-C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
-C 60 ; WX 600 ; N less ; B 86 -2 603 428 ;
-C 61 ; WX 600 ; N equal ; B 108 101 582 325 ;
-C 62 ; WX 600 ; N greater ; B 87 -2 604 428 ;
-C 63 ; WX 600 ; N question ; B 224 -15 576 572 ;
-C 64 ; WX 600 ; N at ; B 134 -15 575 622 ;
-C 65 ; WX 600 ; N A ; B 10 0 597 562 ;
-C 66 ; WX 600 ; N B ; B 50 0 609 562 ;
-C 67 ; WX 600 ; N C ; B 100 -18 651 580 ;
-C 68 ; WX 600 ; N D ; B 50 0 638 562 ;
-C 69 ; WX 600 ; N E ; B 60 0 653 562 ;
-C 70 ; WX 600 ; N F ; B 60 0 653 562 ;
-C 71 ; WX 600 ; N G ; B 90 -18 641 580 ;
-C 72 ; WX 600 ; N H ; B 39 0 680 562 ;
-C 73 ; WX 600 ; N I ; B 103 0 616 562 ;
-C 74 ; WX 600 ; N J ; B 59 -18 678 562 ;
-C 75 ; WX 600 ; N K ; B 45 0 664 562 ;
-C 76 ; WX 600 ; N L ; B 54 0 598 562 ;
-C 77 ; WX 600 ; N M ; B 11 0 708 562 ;
-C 78 ; WX 600 ; N N ; B 14 -13 705 562 ;
-C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
-C 80 ; WX 600 ; N P ; B 86 0 637 562 ;
-C 81 ; WX 600 ; N Q ; B 95 -129 625 580 ;
-C 82 ; WX 600 ; N R ; B 45 0 590 562 ;
-C 83 ; WX 600 ; N S ; B 83 -20 643 580 ;
-C 84 ; WX 600 ; N T ; B 116 0 658 562 ;
-C 85 ; WX 600 ; N U ; B 132 -18 695 562 ;
-C 86 ; WX 600 ; N V ; B 115 -13 716 562 ;
-C 87 ; WX 600 ; N W ; B 115 -13 716 562 ;
-C 88 ; WX 600 ; N X ; B 30 0 668 562 ;
-C 89 ; WX 600 ; N Y ; B 143 0 688 562 ;
-C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 253 -108 574 622 ;
-C 92 ; WX 600 ; N backslash ; B 256 -80 461 629 ;
-C 93 ; WX 600 ; N bracketright ; B 135 -108 456 622 ;
-C 94 ; WX 600 ; N asciicircum ; B 175 359 587 622 ;
-C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 294 328 506 562 ;
-C 97 ; WX 600 ; N a ; B 83 -15 559 441 ;
-C 98 ; WX 600 ; N b ; B 36 -15 618 629 ;
-C 99 ; WX 600 ; N c ; B 113 -15 607 441 ;
-C 100 ; WX 600 ; N d ; B 92 -15 633 629 ;
-C 101 ; WX 600 ; N e ; B 113 -15 591 441 ;
-C 102 ; WX 600 ; N f ; B 121 0 655 629 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 68 -157 650 441 ;
-C 104 ; WX 600 ; N h ; B 40 0 582 629 ;
-C 105 ; WX 600 ; N i ; B 102 0 505 657 ;
-C 106 ; WX 600 ; N j ; B 59 -157 543 657 ;
-C 107 ; WX 600 ; N k ; B 65 0 626 629 ;
-C 108 ; WX 600 ; N l ; B 102 0 505 629 ;
-C 109 ; WX 600 ; N m ; B 2 0 606 441 ;
-C 110 ; WX 600 ; N n ; B 33 0 575 441 ;
-C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
-C 112 ; WX 600 ; N p ; B -17 -157 598 441 ;
-C 113 ; WX 600 ; N q ; B 92 -157 675 441 ;
-C 114 ; WX 600 ; N r ; B 67 0 631 441 ;
-C 115 ; WX 600 ; N s ; B 92 -15 570 441 ;
-C 116 ; WX 600 ; N t ; B 157 -15 534 561 ;
-C 117 ; WX 600 ; N u ; B 111 -15 562 426 ;
-C 118 ; WX 600 ; N v ; B 100 -10 674 426 ;
-C 119 ; WX 600 ; N w ; B 82 -10 692 426 ;
-C 120 ; WX 600 ; N x ; B 27 0 648 426 ;
-C 121 ; WX 600 ; N y ; B -30 -157 643 426 ;
-C 122 ; WX 600 ; N z ; B 106 0 586 426 ;
-C 123 ; WX 600 ; N braceleft ; B 240 -108 562 622 ;
-C 124 ; WX 600 ; N bar ; B 265 -80 453 629 ;
-C 125 ; WX 600 ; N braceright ; B 147 -108 470 622 ;
-C 126 ; WX 600 ; N asciitilde ; B 110 160 585 269 ;
-C 161 ; WX 600 ; N exclamdown ; B 232 -157 445 430 ;
-C 162 ; WX 600 ; N cent ; B 158 -49 581 614 ;
-C 163 ; WX 600 ; N sterling ; B 131 -21 614 611 ;
-C 164 ; WX 600 ; N fraction ; B 23 -57 706 665 ;
-C 165 ; WX 600 ; N yen ; B 135 0 693 594 ;
-C 166 ; WX 600 ; N florin ; B -19 -143 664 622 ;
-C 167 ; WX 600 ; N section ; B 111 -78 583 580 ;
-C 168 ; WX 600 ; N currency ; B 99 65 621 499 ;
-C 169 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 213 328 576 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
-C 174 ; WX 600 ; N fi ; B 10 0 612 629 ;
-C 175 ; WX 600 ; N fl ; B 10 0 612 629 ;
-C 177 ; WX 600 ; N endash ; B 126 238 584 278 ;
-C 178 ; WX 600 ; N dagger ; B 226 -78 537 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 171 -78 537 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 273 152 418 276 ;
-C 182 ; WX 600 ; N paragraph ; B 107 -78 623 562 ;
-C 183 ; WX 600 ; N bullet ; B 231 137 478 376 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
-C 185 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
-C 186 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 51 -15 566 97 ;
-C 189 ; WX 600 ; N perthousand ; B 57 -15 627 622 ;
-C 191 ; WX 600 ; N questiondown ; B 112 -157 464 430 ;
-C 193 ; WX 600 ; N grave ; B 294 497 484 672 ;
-C 194 ; WX 600 ; N acute ; B 348 497 612 672 ;
-C 195 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
-C 196 ; WX 600 ; N tilde ; B 219 503 617 606 ;
-C 197 ; WX 600 ; N macron ; B 232 525 600 565 ;
-C 198 ; WX 600 ; N breve ; B 279 501 576 609 ;
-C 199 ; WX 600 ; N dotaccent ; B 379 508 452 580 ;
-C 200 ; WX 600 ; N dieresis ; B 313 508 519 580 ;
-C 202 ; WX 600 ; N ring ; B 344 483 492 627 ;
-C 203 ; WX 600 ; N cedilla ; B 221 -151 340 10 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
-C 206 ; WX 600 ; N ogonek ; B 207 -151 348 0 ;
-C 207 ; WX 600 ; N caron ; B 262 492 614 669 ;
-C 208 ; WX 600 ; N emdash ; B 51 238 659 278 ;
-C 225 ; WX 600 ; N AE ; B 10 0 648 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 216 259 504 580 ;
-C 232 ; WX 600 ; N Lslash ; B 54 0 598 562 ;
-C 233 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
-C 234 ; WX 600 ; N OE ; B 66 0 665 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 217 259 530 580 ;
-C 241 ; WX 600 ; N ae ; B 47 -15 620 441 ;
-C 245 ; WX 600 ; N dotlessi ; B 102 0 505 426 ;
-C 248 ; WX 600 ; N lslash ; B 102 0 559 629 ;
-C 249 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
-C 250 ; WX 600 ; N oe ; B 61 -15 609 441 ;
-C 251 ; WX 600 ; N germandbls ; B 55 -15 610 629 ;
-C -1 ; WX 600 ; N scedilla ; B 92 -151 570 441 ;
-C -1 ; WX 600 ; N notegraphic ; B 143 -15 557 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 94 -18 625 775 ;
-C -1 ; WX 600 ; N ll ; B 40 0 609 629 ;
-C -1 ; WX 600 ; N otilde ; B 102 -15 617 606 ;
-C -1 ; WX 600 ; N scaron ; B 92 -15 614 669 ;
-C -1 ; WX 600 ; N divide ; B 128 1 562 426 ;
-C -1 ; WX 600 ; N Thorn ; B 86 0 599 562 ;
-C -1 ; WX 600 ; N format ; B -28 -157 169 598 ;
-C -1 ; WX 600 ; N largebullet ; B 322 227 388 290 ;
-C -1 ; WX 600 ; N Eth ; B 50 0 638 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 94 -18 625 716 ;
-C -1 ; WX 600 ; N onesuperior ; B 238 249 481 622 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 590 227 ;
-C -1 ; WX 600 ; N Ydieresis ; B 143 0 688 716 ;
-C -1 ; WX 600 ; N merge ; B 192 -15 497 436 ;
-C -1 ; WX 600 ; N IJ ; B 39 -18 681 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 113 -151 607 441 ;
-C -1 ; WX 600 ; N multiply ; B 93 -1 599 426 ;
-C -1 ; WX 600 ; N degree ; B 214 269 576 622 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 610 562 ;
-C -1 ; WX 600 ; N indent ; B 110 75 574 341 ;
-C -1 ; WX 600 ; N Otilde ; B 94 -18 644 732 ;
-C -1 ; WX 600 ; N thorn ; B -17 -157 598 629 ;
-C -1 ; WX 600 ; N mu ; B 79 -157 562 426 ;
-C -1 ; WX 600 ; N Yacute ; B 143 0 688 793 ;
-C -1 ; WX 600 ; N threesuperior ; B 220 240 494 622 ;
-C -1 ; WX 600 ; N logicalnot ; B 148 64 582 325 ;
-C -1 ; WX 600 ; N Ugrave ; B 132 -18 695 793 ;
-C -1 ; WX 600 ; N eth ; B 102 -15 629 629 ;
-C -1 ; WX 600 ; N left ; B 114 75 578 341 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 60 0 653 775 ;
-C -1 ; WX 600 ; N edieresis ; B 113 -15 591 580 ;
-C -1 ; WX 600 ; N Ograve ; B 94 -18 625 793 ;
-C -1 ; WX 600 ; N down ; B 192 -15 458 422 ;
-C -1 ; WX 600 ; N Agrave ; B 10 0 597 793 ;
-C -1 ; WX 600 ; N atilde ; B 83 -15 617 606 ;
-C -1 ; WX 600 ; N up ; B 232 0 498 437 ;
-C -1 ; WX 600 ; N eacute ; B 113 -15 612 672 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 652 599 ;
-C -1 ; WX 600 ; N lira ; B 125 -21 614 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 103 0 616 775 ;
-C -1 ; WX 600 ; N Adieresis ; B 10 0 597 716 ;
-C -1 ; WX 600 ; N yacute ; B -30 -157 643 672 ;
-C -1 ; WX 600 ; N icircumflex ; B 102 0 551 654 ;
-C -1 ; WX 600 ; N adieresis ; B 83 -15 559 580 ;
-C -1 ; WX 600 ; N zcaron ; B 106 0 624 669 ;
-C -1 ; WX 600 ; N Scaron ; B 83 -20 673 805 ;
-C -1 ; WX 600 ; N minus ; B 128 195 562 232 ;
-C -1 ; WX 600 ; N Aring ; B 10 0 597 753 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 132 -18 695 775 ;
-C -1 ; WX 600 ; N plusminus ; B 87 0 583 514 ;
-C -1 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
-C -1 ; WX 600 ; N Edieresis ; B 60 0 653 716 ;
-C -1 ; WX 600 ; N brokenbar ; B 265 -80 453 629 ;
-C -1 ; WX 600 ; N Idieresis ; B 103 0 616 716 ;
-C -1 ; WX 600 ; N acircumflex ; B 83 -15 581 654 ;
-C -1 ; WX 600 ; N ydieresis ; B -30 -157 643 580 ;
-C -1 ; WX 600 ; N Oacute ; B 94 -18 638 793 ;
-C -1 ; WX 600 ; N Egrave ; B 60 0 653 793 ;
-C -1 ; WX 600 ; N center ; B 103 14 623 580 ;
-C -1 ; WX 600 ; N threequarters ; B 28 -57 711 665 ;
-C -1 ; WX 600 ; N tab ; B 19 0 641 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 113 -15 591 654 ;
-C -1 ; WX 600 ; N Eacute ; B 60 0 668 793 ;
-C -1 ; WX 600 ; N trademark ; B 108 263 710 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N onehalf ; B 42 -57 725 665 ;
-C -1 ; WX 600 ; N onequarter ; B 48 -57 731 665 ;
-C -1 ; WX 600 ; N Uacute ; B 132 -18 695 793 ;
-C -1 ; WX 600 ; N Atilde ; B 10 0 644 732 ;
-C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N Igrave ; B 103 0 616 793 ;
-C -1 ; WX 600 ; N Iacute ; B 103 0 638 793 ;
-C -1 ; WX 600 ; N Acircumflex ; B 10 0 597 775 ;
-C -1 ; WX 600 ; N Udieresis ; B 132 -18 695 716 ;
-C -1 ; WX 600 ; N Gcaron ; B 90 -18 643 805 ;
-C -1 ; WX 600 ; N Aacute ; B 10 0 658 793 ;
-C -1 ; WX 600 ; N LL ; B 15 0 640 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 237 249 528 622 ;
-C -1 ; WX 600 ; N Scedilla ; B 83 -151 643 580 ;
-C -1 ; WX 600 ; N arrowboth ; B 36 122 692 476 ;
-C -1 ; WX 600 ; N udieresis ; B 111 -15 562 580 ;
-C -1 ; WX 600 ; N odieresis ; B 102 -15 588 580 ;
-C -1 ; WX 600 ; N aring ; B 83 -15 559 627 ;
-C -1 ; WX 600 ; N ij ; B 44 -157 623 657 ;
-C -1 ; WX 600 ; N arrowdown ; B 157 -15 511 608 ;
-C -1 ; WX 600 ; N igrave ; B 102 0 505 672 ;
-C -1 ; WX 600 ; N aacute ; B 83 -15 612 672 ;
-C -1 ; WX 600 ; N stop ; B 19 0 700 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
-C -1 ; WX 600 ; N gcaron ; B 68 -157 650 669 ;
-C -1 ; WX 600 ; N iacute ; B 102 0 612 672 ;
-C -1 ; WX 600 ; N Ntilde ; B 14 -13 705 732 ;
-C -1 ; WX 600 ; N idieresis ; B 102 0 505 580 ;
-C -1 ; WX 600 ; N Ccedilla ; B 100 -151 651 580 ;
-C -1 ; WX 600 ; N arrowright ; B 35 122 688 476 ;
-C -1 ; WX 600 ; N ucircumflex ; B 111 -15 571 654 ;
-C -1 ; WX 600 ; N Idot ; B 103 0 616 716 ;
-C -1 ; WX 600 ; N agrave ; B 83 -15 559 672 ;
-C -1 ; WX 600 ; N ntilde ; B 33 0 617 606 ;
-C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ;
-C -1 ; WX 600 ; N return ; B 79 0 700 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 86 0 643 805 ;
-C -1 ; WX 600 ; N uacute ; B 111 -15 602 672 ;
-C -1 ; WX 600 ; N overscore ; B 123 579 734 629 ;
-C -1 ; WX 600 ; N egrave ; B 113 -15 591 672 ;
-C -1 ; WX 600 ; N ugrave ; B 111 -15 562 672 ;
-C -1 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
-C -1 ; WX 600 ; N arrowleft ; B 40 122 692 476 ;
-C -1 ; WX 600 ; N arrowup ; B 218 0 572 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 46 121 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -4 121 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -1 136 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -4 121 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 12 126 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 27 126 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 56 121 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 26 121 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 29 136 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 26 121 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 29 136 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 26 121 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 26 121 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 29 136 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 26 121 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 27 126 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 26 121 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 26 121 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 29 136 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 26 121 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 27 126 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 59 136 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 0 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 56 121 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 26 121 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 29 136 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -4 121 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 56 121 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 29 136 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 29 136 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 0 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 0 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 0 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -30 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -30 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -30 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -30 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute -10 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -10 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 0 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute -20 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis -10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 10 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Jan 18 17:48:17 1990
-Comment UniqueID 27077
-Comment VMusage 27874 40242
-FontName Courier
-FullName Courier
-FamilyName Courier
-Weight Medium
-ItalicAngle 0
-IsFixedPitch true
-FontBBox -28 -157 628 805
-UnderlinePosition -100
-UnderlineThickness 50
-Version 002.003
-Notice Copyright (c) 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-EncodingScheme AdobeStandardEncoding
-CapHeight 562
-XHeight 426
-Ascender 629
-Descender -157
-StartCharMetrics 260
-C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
-C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
-C 35 ; WX 600 ; N numbersign ; B 100 -32 500 639 ;
-C 36 ; WX 600 ; N dollar ; B 112 -126 489 662 ;
-C 37 ; WX 600 ; N percent ; B 97 -15 515 622 ;
-C 38 ; WX 600 ; N ampersand ; B 70 -15 531 543 ;
-C 39 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
-C 40 ; WX 600 ; N parenleft ; B 276 -108 433 622 ;
-C 41 ; WX 600 ; N parenright ; B 167 -108 324 622 ;
-C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
-C 43 ; WX 600 ; N plus ; B 87 0 513 426 ;
-C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
-C 45 ; WX 600 ; N hyphen ; B 110 238 490 278 ;
-C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
-C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
-C 48 ; WX 600 ; N zero ; B 113 -15 487 622 ;
-C 49 ; WX 600 ; N one ; B 102 0 498 622 ;
-C 50 ; WX 600 ; N two ; B 77 0 464 622 ;
-C 51 ; WX 600 ; N three ; B 82 -15 459 622 ;
-C 52 ; WX 600 ; N four ; B 88 0 493 622 ;
-C 53 ; WX 600 ; N five ; B 99 -15 490 607 ;
-C 54 ; WX 600 ; N six ; B 118 -15 497 622 ;
-C 55 ; WX 600 ; N seven ; B 89 0 476 607 ;
-C 56 ; WX 600 ; N eight ; B 109 -15 491 622 ;
-C 57 ; WX 600 ; N nine ; B 103 -15 482 622 ;
-C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
-C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
-C 60 ; WX 600 ; N less ; B 41 -2 519 428 ;
-C 61 ; WX 600 ; N equal ; B 87 101 513 325 ;
-C 62 ; WX 600 ; N greater ; B 81 -2 559 428 ;
-C 63 ; WX 600 ; N question ; B 136 -15 485 572 ;
-C 64 ; WX 600 ; N at ; B 84 -15 526 622 ;
-C 65 ; WX 600 ; N A ; B 10 0 590 562 ;
-C 66 ; WX 600 ; N B ; B 50 0 552 562 ;
-C 67 ; WX 600 ; N C ; B 48 -18 533 580 ;
-C 68 ; WX 600 ; N D ; B 50 0 567 562 ;
-C 69 ; WX 600 ; N E ; B 60 0 543 562 ;
-C 70 ; WX 600 ; N F ; B 60 0 538 562 ;
-C 71 ; WX 600 ; N G ; B 38 -18 568 580 ;
-C 72 ; WX 600 ; N H ; B 39 0 561 562 ;
-C 73 ; WX 600 ; N I ; B 103 0 497 562 ;
-C 74 ; WX 600 ; N J ; B 41 -18 559 562 ;
-C 75 ; WX 600 ; N K ; B 45 0 575 562 ;
-C 76 ; WX 600 ; N L ; B 54 0 547 562 ;
-C 77 ; WX 600 ; N M ; B 11 0 589 562 ;
-C 78 ; WX 600 ; N N ; B 14 -13 586 562 ;
-C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
-C 80 ; WX 600 ; N P ; B 86 0 551 562 ;
-C 81 ; WX 600 ; N Q ; B 43 -129 557 580 ;
-C 82 ; WX 600 ; N R ; B 45 0 581 562 ;
-C 83 ; WX 600 ; N S ; B 79 -20 522 580 ;
-C 84 ; WX 600 ; N T ; B 45 0 556 562 ;
-C 85 ; WX 600 ; N U ; B 24 -18 576 562 ;
-C 86 ; WX 600 ; N V ; B 3 -13 597 562 ;
-C 87 ; WX 600 ; N W ; B 3 -13 597 562 ;
-C 88 ; WX 600 ; N X ; B 30 0 570 562 ;
-C 89 ; WX 600 ; N Y ; B 31 0 569 562 ;
-C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
-C 91 ; WX 600 ; N bracketleft ; B 276 -108 442 622 ;
-C 92 ; WX 600 ; N backslash ; B 125 -80 475 629 ;
-C 93 ; WX 600 ; N bracketright ; B 158 -108 324 622 ;
-C 94 ; WX 600 ; N asciicircum ; B 94 359 506 622 ;
-C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
-C 96 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
-C 97 ; WX 600 ; N a ; B 60 -15 552 441 ;
-C 98 ; WX 600 ; N b ; B 21 -15 568 629 ;
-C 99 ; WX 600 ; N c ; B 73 -15 522 441 ;
-C 100 ; WX 600 ; N d ; B 52 -15 584 629 ;
-C 101 ; WX 600 ; N e ; B 73 -15 541 441 ;
-C 102 ; WX 600 ; N f ; B 121 0 524 629 ; L i fi ; L l fl ;
-C 103 ; WX 600 ; N g ; B 52 -157 559 441 ;
-C 104 ; WX 600 ; N h ; B 25 0 575 629 ;
-C 105 ; WX 600 ; N i ; B 102 0 498 657 ;
-C 106 ; WX 600 ; N j ; B 89 -157 403 657 ;
-C 107 ; WX 600 ; N k ; B 50 0 573 629 ;
-C 108 ; WX 600 ; N l ; B 102 0 498 629 ;
-C 109 ; WX 600 ; N m ; B 2 0 598 441 ;
-C 110 ; WX 600 ; N n ; B 33 0 568 441 ;
-C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
-C 112 ; WX 600 ; N p ; B 16 -157 548 441 ;
-C 113 ; WX 600 ; N q ; B 52 -157 584 441 ;
-C 114 ; WX 600 ; N r ; B 67 0 552 441 ;
-C 115 ; WX 600 ; N s ; B 94 -15 506 441 ;
-C 116 ; WX 600 ; N t ; B 74 -15 503 561 ;
-C 117 ; WX 600 ; N u ; B 28 -15 555 426 ;
-C 118 ; WX 600 ; N v ; B 17 -10 583 426 ;
-C 119 ; WX 600 ; N w ; B -1 -10 601 426 ;
-C 120 ; WX 600 ; N x ; B 27 0 573 426 ;
-C 121 ; WX 600 ; N y ; B -12 -157 552 426 ;
-C 122 ; WX 600 ; N z ; B 106 0 495 426 ;
-C 123 ; WX 600 ; N braceleft ; B 189 -108 430 622 ;
-C 124 ; WX 600 ; N bar ; B 282 -80 319 629 ;
-C 125 ; WX 600 ; N braceright ; B 170 -108 411 622 ;
-C 126 ; WX 600 ; N asciitilde ; B 67 160 534 269 ;
-C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
-C 162 ; WX 600 ; N cent ; B 103 -49 493 614 ;
-C 163 ; WX 600 ; N sterling ; B 91 -21 518 611 ;
-C 164 ; WX 600 ; N fraction ; B 31 -57 569 665 ;
-C 165 ; WX 600 ; N yen ; B 33 0 567 594 ;
-C 166 ; WX 600 ; N florin ; B 11 -143 532 622 ;
-C 167 ; WX 600 ; N section ; B 120 -78 481 580 ;
-C 168 ; WX 600 ; N currency ; B 80 65 520 499 ;
-C 169 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
-C 170 ; WX 600 ; N quotedblleft ; B 143 328 457 562 ;
-C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
-C 172 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
-C 173 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
-C 174 ; WX 600 ; N fi ; B 10 0 590 629 ;
-C 175 ; WX 600 ; N fl ; B 10 0 590 629 ;
-C 177 ; WX 600 ; N endash ; B 75 238 525 278 ;
-C 178 ; WX 600 ; N dagger ; B 148 -78 452 580 ;
-C 179 ; WX 600 ; N daggerdbl ; B 148 -78 452 580 ;
-C 180 ; WX 600 ; N periodcentered ; B 229 152 371 276 ;
-C 182 ; WX 600 ; N paragraph ; B 57 -78 504 562 ;
-C 183 ; WX 600 ; N bullet ; B 179 137 421 376 ;
-C 184 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
-C 185 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
-C 186 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
-C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
-C 188 ; WX 600 ; N ellipsis ; B 44 -15 556 97 ;
-C 189 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
-C 191 ; WX 600 ; N questiondown ; B 115 -157 464 430 ;
-C 193 ; WX 600 ; N grave ; B 151 497 378 672 ;
-C 194 ; WX 600 ; N acute ; B 242 497 469 672 ;
-C 195 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
-C 196 ; WX 600 ; N tilde ; B 109 503 491 606 ;
-C 197 ; WX 600 ; N macron ; B 120 525 480 565 ;
-C 198 ; WX 600 ; N breve ; B 153 501 447 609 ;
-C 199 ; WX 600 ; N dotaccent ; B 264 508 336 580 ;
-C 200 ; WX 600 ; N dieresis ; B 198 508 402 580 ;
-C 202 ; WX 600 ; N ring ; B 228 483 372 627 ;
-C 203 ; WX 600 ; N cedilla ; B 249 -151 358 10 ;
-C 205 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
-C 206 ; WX 600 ; N ogonek ; B 227 -151 370 0 ;
-C 207 ; WX 600 ; N caron ; B 124 492 476 669 ;
-C 208 ; WX 600 ; N emdash ; B 0 238 600 278 ;
-C 225 ; WX 600 ; N AE ; B 10 0 543 562 ;
-C 227 ; WX 600 ; N ordfeminine ; B 161 259 437 580 ;
-C 232 ; WX 600 ; N Lslash ; B 54 0 547 562 ;
-C 233 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
-C 234 ; WX 600 ; N OE ; B 14 0 560 562 ;
-C 235 ; WX 600 ; N ordmasculine ; B 162 259 438 580 ;
-C 241 ; WX 600 ; N ae ; B 26 -15 563 441 ;
-C 245 ; WX 600 ; N dotlessi ; B 102 0 498 426 ;
-C 248 ; WX 600 ; N lslash ; B 102 0 498 629 ;
-C 249 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
-C 250 ; WX 600 ; N oe ; B 26 -15 552 441 ;
-C 251 ; WX 600 ; N germandbls ; B 55 -15 581 629 ;
-C -1 ; WX 600 ; N scedilla ; B 94 -151 506 441 ;
-C -1 ; WX 600 ; N notegraphic ; B 136 -15 464 572 ;
-C -1 ; WX 600 ; N Ocircumflex ; B 43 -18 557 775 ;
-C -1 ; WX 600 ; N ll ; B 25 0 560 629 ;
-C -1 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
-C -1 ; WX 600 ; N scaron ; B 94 -15 506 669 ;
-C -1 ; WX 600 ; N divide ; B 87 1 513 426 ;
-C -1 ; WX 600 ; N Thorn ; B 86 0 531 562 ;
-C -1 ; WX 600 ; N format ; B 5 -157 42 598 ;
-C -1 ; WX 600 ; N largebullet ; B 268 227 332 290 ;
-C -1 ; WX 600 ; N Eth ; B 30 0 567 562 ;
-C -1 ; WX 600 ; N Odieresis ; B 43 -18 557 716 ;
-C -1 ; WX 600 ; N onesuperior ; B 179 249 421 622 ;
-C -1 ; WX 600 ; N dectab ; B 18 0 582 227 ;
-C -1 ; WX 600 ; N Ydieresis ; B 31 0 569 716 ;
-C -1 ; WX 600 ; N merge ; B 167 -15 433 436 ;
-C -1 ; WX 600 ; N IJ ; B 39 -18 562 562 ;
-C -1 ; WX 600 ; N ccedilla ; B 73 -151 522 441 ;
-C -1 ; WX 600 ; N multiply ; B 87 -1 514 426 ;
-C -1 ; WX 600 ; N degree ; B 123 269 477 622 ;
-C -1 ; WX 600 ; N prescription ; B 34 -15 570 562 ;
-C -1 ; WX 600 ; N indent ; B 70 75 530 341 ;
-C -1 ; WX 600 ; N Otilde ; B 43 -18 557 732 ;
-C -1 ; WX 600 ; N thorn ; B 1 -157 548 629 ;
-C -1 ; WX 600 ; N mu ; B 28 -157 555 426 ;
-C -1 ; WX 600 ; N Yacute ; B 31 0 569 793 ;
-C -1 ; WX 600 ; N threesuperior ; B 162 240 399 622 ;
-C -1 ; WX 600 ; N logicalnot ; B 87 64 513 325 ;
-C -1 ; WX 600 ; N Ugrave ; B 24 -18 576 793 ;
-C -1 ; WX 600 ; N eth ; B 62 -15 538 629 ;
-C -1 ; WX 600 ; N left ; B 70 75 530 341 ;
-C -1 ; WX 600 ; N Ecircumflex ; B 60 0 543 775 ;
-C -1 ; WX 600 ; N edieresis ; B 73 -15 541 580 ;
-C -1 ; WX 600 ; N Ograve ; B 43 -18 557 793 ;
-C -1 ; WX 600 ; N down ; B 167 -15 433 422 ;
-C -1 ; WX 600 ; N Agrave ; B 10 0 590 793 ;
-C -1 ; WX 600 ; N atilde ; B 60 -15 552 606 ;
-C -1 ; WX 600 ; N up ; B 167 0 433 437 ;
-C -1 ; WX 600 ; N eacute ; B 73 -15 541 672 ;
-C -1 ; WX 600 ; N graybox ; B 76 0 525 599 ;
-C -1 ; WX 600 ; N lira ; B 80 -21 518 611 ;
-C -1 ; WX 600 ; N Icircumflex ; B 103 0 497 775 ;
-C -1 ; WX 600 ; N Adieresis ; B 10 0 590 716 ;
-C -1 ; WX 600 ; N yacute ; B -12 -157 552 672 ;
-C -1 ; WX 600 ; N icircumflex ; B 94 0 498 654 ;
-C -1 ; WX 600 ; N adieresis ; B 60 -15 552 580 ;
-C -1 ; WX 600 ; N zcaron ; B 106 0 495 669 ;
-C -1 ; WX 600 ; N Scaron ; B 79 -20 522 805 ;
-C -1 ; WX 600 ; N minus ; B 87 195 513 232 ;
-C -1 ; WX 600 ; N Aring ; B 10 0 590 753 ;
-C -1 ; WX 600 ; N Ucircumflex ; B 24 -18 576 775 ;
-C -1 ; WX 600 ; N plusminus ; B 87 0 513 514 ;
-C -1 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
-C -1 ; WX 600 ; N Edieresis ; B 60 0 543 716 ;
-C -1 ; WX 600 ; N brokenbar ; B 282 -80 319 629 ;
-C -1 ; WX 600 ; N Idieresis ; B 103 0 497 716 ;
-C -1 ; WX 600 ; N acircumflex ; B 60 -15 552 654 ;
-C -1 ; WX 600 ; N ydieresis ; B -12 -157 552 580 ;
-C -1 ; WX 600 ; N Oacute ; B 43 -18 557 793 ;
-C -1 ; WX 600 ; N Egrave ; B 60 0 543 793 ;
-C -1 ; WX 600 ; N center ; B 40 14 560 580 ;
-C -1 ; WX 600 ; N threequarters ; B 22 -57 574 665 ;
-C -1 ; WX 600 ; N tab ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ecircumflex ; B 73 -15 541 654 ;
-C -1 ; WX 600 ; N Eacute ; B 60 0 543 793 ;
-C -1 ; WX 600 ; N trademark ; B 10 263 591 562 ;
-C -1 ; WX 600 ; N square ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
-C -1 ; WX 600 ; N onequarter ; B 6 -57 594 665 ;
-C -1 ; WX 600 ; N Uacute ; B 24 -18 576 793 ;
-C -1 ; WX 600 ; N Atilde ; B 10 0 590 732 ;
-C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N Igrave ; B 103 0 497 793 ;
-C -1 ; WX 600 ; N Iacute ; B 103 0 497 793 ;
-C -1 ; WX 600 ; N Acircumflex ; B 10 0 590 775 ;
-C -1 ; WX 600 ; N Udieresis ; B 24 -18 576 716 ;
-C -1 ; WX 600 ; N Gcaron ; B 38 -18 568 805 ;
-C -1 ; WX 600 ; N Aacute ; B 10 0 590 793 ;
-C -1 ; WX 600 ; N LL ; B 15 0 585 562 ;
-C -1 ; WX 600 ; N twosuperior ; B 184 249 417 622 ;
-C -1 ; WX 600 ; N Scedilla ; B 79 -151 522 580 ;
-C -1 ; WX 600 ; N arrowboth ; B -28 122 628 476 ;
-C -1 ; WX 600 ; N udieresis ; B 28 -15 555 580 ;
-C -1 ; WX 600 ; N odieresis ; B 62 -15 538 580 ;
-C -1 ; WX 600 ; N aring ; B 60 -15 552 627 ;
-C -1 ; WX 600 ; N ij ; B 44 -157 483 657 ;
-C -1 ; WX 600 ; N arrowdown ; B 123 -15 477 608 ;
-C -1 ; WX 600 ; N igrave ; B 102 0 498 672 ;
-C -1 ; WX 600 ; N aacute ; B 60 -15 552 672 ;
-C -1 ; WX 600 ; N stop ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
-C -1 ; WX 600 ; N gcaron ; B 52 -157 559 669 ;
-C -1 ; WX 600 ; N iacute ; B 102 0 498 672 ;
-C -1 ; WX 600 ; N Ntilde ; B 14 -13 586 732 ;
-C -1 ; WX 600 ; N idieresis ; B 102 0 498 580 ;
-C -1 ; WX 600 ; N Ccedilla ; B 48 -151 533 580 ;
-C -1 ; WX 600 ; N arrowright ; B -24 122 624 476 ;
-C -1 ; WX 600 ; N ucircumflex ; B 28 -15 555 654 ;
-C -1 ; WX 600 ; N Idot ; B 103 0 497 716 ;
-C -1 ; WX 600 ; N agrave ; B 60 -15 552 672 ;
-C -1 ; WX 600 ; N ntilde ; B 33 0 568 606 ;
-C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ;
-C -1 ; WX 600 ; N return ; B 19 0 581 562 ;
-C -1 ; WX 600 ; N Zcaron ; B 86 0 514 805 ;
-C -1 ; WX 600 ; N uacute ; B 28 -15 555 672 ;
-C -1 ; WX 600 ; N overscore ; B 0 579 600 629 ;
-C -1 ; WX 600 ; N egrave ; B 73 -15 541 672 ;
-C -1 ; WX 600 ; N ugrave ; B 28 -15 555 672 ;
-C -1 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
-C -1 ; WX 600 ; N arrowleft ; B -24 122 624 476 ;
-C -1 ; WX 600 ; N arrowup ; B 123 0 477 623 ;
-EndCharMetrics
-StartComposites 62
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 20 121 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex -30 121 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis -30 136 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave -30 121 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring -15 126 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 0 126 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 0 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 30 121 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 0 121 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 0 136 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 0 121 ;
-CC Gcaron 2 ; PCC G 0 0 ; PCC caron 0 136 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 121 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 121 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 136 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 121 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 0 126 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 0 121 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 0 121 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 0 136 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 0 121 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 0 126 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 30 136 ;
-CC Scedilla 2 ; PCC S 0 0 ; PCC cedilla 0 0 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 30 121 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 0 121 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 0 136 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave -30 121 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 30 121 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 0 136 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 0 136 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 0 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 0 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 0 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 0 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 0 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 0 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 0 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 0 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 0 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 0 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 0 0 ;
-CC gcaron 2 ; PCC g 0 0 ; PCC caron -30 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute 0 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -30 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -30 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -30 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 0 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 0 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 0 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 0 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 0 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 0 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 0 0 ;
-CC scedilla 2 ; PCC s 0 0 ; PCC cedilla 0 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute -10 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex -10 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 0 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave -30 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute -20 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis -10 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 10 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Thu Mar 15 09:43:00 1990
-Comment UniqueID 28357
-Comment VMusage 26878 33770
-FontName Helvetica-Bold
-FullName Helvetica Bold
-FamilyName Helvetica
-Weight Bold
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -170 -228 1003 962
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 90 0 244 718 ;
-C 34 ; WX 474 ; N quotedbl ; B 98 447 376 718 ;
-C 35 ; WX 556 ; N numbersign ; B 18 0 538 698 ;
-C 36 ; WX 556 ; N dollar ; B 30 -115 523 775 ;
-C 37 ; WX 889 ; N percent ; B 28 -19 861 710 ;
-C 38 ; WX 722 ; N ampersand ; B 54 -19 701 718 ;
-C 39 ; WX 278 ; N quoteright ; B 69 445 209 718 ;
-C 40 ; WX 333 ; N parenleft ; B 35 -208 314 734 ;
-C 41 ; WX 333 ; N parenright ; B 19 -208 298 734 ;
-C 42 ; WX 389 ; N asterisk ; B 27 387 362 718 ;
-C 43 ; WX 584 ; N plus ; B 40 0 544 506 ;
-C 44 ; WX 278 ; N comma ; B 64 -168 214 146 ;
-C 45 ; WX 333 ; N hyphen ; B 27 215 306 345 ;
-C 46 ; WX 278 ; N period ; B 64 0 214 146 ;
-C 47 ; WX 278 ; N slash ; B -33 -19 311 737 ;
-C 48 ; WX 556 ; N zero ; B 32 -19 524 710 ;
-C 49 ; WX 556 ; N one ; B 69 0 378 710 ;
-C 50 ; WX 556 ; N two ; B 26 0 511 710 ;
-C 51 ; WX 556 ; N three ; B 27 -19 516 710 ;
-C 52 ; WX 556 ; N four ; B 27 0 526 710 ;
-C 53 ; WX 556 ; N five ; B 27 -19 516 698 ;
-C 54 ; WX 556 ; N six ; B 31 -19 520 710 ;
-C 55 ; WX 556 ; N seven ; B 25 0 528 698 ;
-C 56 ; WX 556 ; N eight ; B 32 -19 524 710 ;
-C 57 ; WX 556 ; N nine ; B 30 -19 522 710 ;
-C 58 ; WX 333 ; N colon ; B 92 0 242 512 ;
-C 59 ; WX 333 ; N semicolon ; B 92 -168 242 512 ;
-C 60 ; WX 584 ; N less ; B 38 -8 546 514 ;
-C 61 ; WX 584 ; N equal ; B 40 87 544 419 ;
-C 62 ; WX 584 ; N greater ; B 38 -8 546 514 ;
-C 63 ; WX 611 ; N question ; B 60 0 556 727 ;
-C 64 ; WX 975 ; N at ; B 118 -19 856 737 ;
-C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
-C 66 ; WX 722 ; N B ; B 76 0 669 718 ;
-C 67 ; WX 722 ; N C ; B 44 -19 684 737 ;
-C 68 ; WX 722 ; N D ; B 76 0 685 718 ;
-C 69 ; WX 667 ; N E ; B 76 0 621 718 ;
-C 70 ; WX 611 ; N F ; B 76 0 587 718 ;
-C 71 ; WX 778 ; N G ; B 44 -19 713 737 ;
-C 72 ; WX 722 ; N H ; B 71 0 651 718 ;
-C 73 ; WX 278 ; N I ; B 64 0 214 718 ;
-C 74 ; WX 556 ; N J ; B 22 -18 484 718 ;
-C 75 ; WX 722 ; N K ; B 87 0 722 718 ;
-C 76 ; WX 611 ; N L ; B 76 0 583 718 ;
-C 77 ; WX 833 ; N M ; B 69 0 765 718 ;
-C 78 ; WX 722 ; N N ; B 69 0 654 718 ;
-C 79 ; WX 778 ; N O ; B 44 -19 734 737 ;
-C 80 ; WX 667 ; N P ; B 76 0 627 718 ;
-C 81 ; WX 778 ; N Q ; B 44 -52 737 737 ;
-C 82 ; WX 722 ; N R ; B 76 0 677 718 ;
-C 83 ; WX 667 ; N S ; B 39 -19 629 737 ;
-C 84 ; WX 611 ; N T ; B 14 0 598 718 ;
-C 85 ; WX 722 ; N U ; B 72 -19 651 718 ;
-C 86 ; WX 667 ; N V ; B 19 0 648 718 ;
-C 87 ; WX 944 ; N W ; B 16 0 929 718 ;
-C 88 ; WX 667 ; N X ; B 14 0 653 718 ;
-C 89 ; WX 667 ; N Y ; B 15 0 653 718 ;
-C 90 ; WX 611 ; N Z ; B 25 0 586 718 ;
-C 91 ; WX 333 ; N bracketleft ; B 63 -196 309 722 ;
-C 92 ; WX 278 ; N backslash ; B -33 -19 311 737 ;
-C 93 ; WX 333 ; N bracketright ; B 24 -196 270 722 ;
-C 94 ; WX 584 ; N asciicircum ; B 62 323 522 698 ;
-C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
-C 96 ; WX 278 ; N quoteleft ; B 69 454 209 727 ;
-C 97 ; WX 556 ; N a ; B 29 -14 527 546 ;
-C 98 ; WX 611 ; N b ; B 61 -14 578 718 ;
-C 99 ; WX 556 ; N c ; B 34 -14 524 546 ;
-C 100 ; WX 611 ; N d ; B 34 -14 551 718 ;
-C 101 ; WX 556 ; N e ; B 23 -14 528 546 ;
-C 102 ; WX 333 ; N f ; B 10 0 318 727 ; L i fi ; L l fl ;
-C 103 ; WX 611 ; N g ; B 40 -217 553 546 ;
-C 104 ; WX 611 ; N h ; B 65 0 546 718 ;
-C 105 ; WX 278 ; N i ; B 69 0 209 725 ;
-C 106 ; WX 278 ; N j ; B 3 -214 209 725 ;
-C 107 ; WX 556 ; N k ; B 69 0 562 718 ;
-C 108 ; WX 278 ; N l ; B 69 0 209 718 ;
-C 109 ; WX 889 ; N m ; B 64 0 826 546 ;
-C 110 ; WX 611 ; N n ; B 65 0 546 546 ;
-C 111 ; WX 611 ; N o ; B 34 -14 578 546 ;
-C 112 ; WX 611 ; N p ; B 62 -207 578 546 ;
-C 113 ; WX 611 ; N q ; B 34 -207 552 546 ;
-C 114 ; WX 389 ; N r ; B 64 0 373 546 ;
-C 115 ; WX 556 ; N s ; B 30 -14 519 546 ;
-C 116 ; WX 333 ; N t ; B 10 -6 309 676 ;
-C 117 ; WX 611 ; N u ; B 66 -14 545 532 ;
-C 118 ; WX 556 ; N v ; B 13 0 543 532 ;
-C 119 ; WX 778 ; N w ; B 10 0 769 532 ;
-C 120 ; WX 556 ; N x ; B 15 0 541 532 ;
-C 121 ; WX 556 ; N y ; B 10 -214 539 532 ;
-C 122 ; WX 500 ; N z ; B 20 0 480 532 ;
-C 123 ; WX 389 ; N braceleft ; B 48 -196 365 722 ;
-C 124 ; WX 280 ; N bar ; B 84 -19 196 737 ;
-C 125 ; WX 389 ; N braceright ; B 24 -196 341 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 61 163 523 343 ;
-C 161 ; WX 333 ; N exclamdown ; B 90 -186 244 532 ;
-C 162 ; WX 556 ; N cent ; B 34 -118 524 628 ;
-C 163 ; WX 556 ; N sterling ; B 28 -16 541 718 ;
-C 164 ; WX 167 ; N fraction ; B -170 -19 336 710 ;
-C 165 ; WX 556 ; N yen ; B -9 0 565 698 ;
-C 166 ; WX 556 ; N florin ; B -10 -210 516 737 ;
-C 167 ; WX 556 ; N section ; B 34 -184 522 727 ;
-C 168 ; WX 556 ; N currency ; B -3 76 559 636 ;
-C 169 ; WX 238 ; N quotesingle ; B 70 447 168 718 ;
-C 170 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ;
-C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ;
-C 173 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ;
-C 174 ; WX 611 ; N fi ; B 10 0 542 727 ;
-C 175 ; WX 611 ; N fl ; B 10 0 542 727 ;
-C 177 ; WX 556 ; N endash ; B 0 227 556 333 ;
-C 178 ; WX 556 ; N dagger ; B 36 -171 520 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 36 -171 520 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 58 172 220 334 ;
-C 182 ; WX 556 ; N paragraph ; B -8 -191 539 700 ;
-C 183 ; WX 350 ; N bullet ; B 10 194 340 524 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 69 -146 209 127 ;
-C 185 ; WX 500 ; N quotedblbase ; B 64 -146 436 127 ;
-C 186 ; WX 500 ; N quotedblright ; B 64 445 436 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 88 76 468 484 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ;
-C 189 ; WX 1000 ; N perthousand ; B -3 -19 1003 710 ;
-C 191 ; WX 611 ; N questiondown ; B 55 -195 551 532 ;
-C 193 ; WX 333 ; N grave ; B -23 604 225 750 ;
-C 194 ; WX 333 ; N acute ; B 108 604 356 750 ;
-C 195 ; WX 333 ; N circumflex ; B -10 604 343 750 ;
-C 196 ; WX 333 ; N tilde ; B -17 610 350 737 ;
-C 197 ; WX 333 ; N macron ; B -6 604 339 678 ;
-C 198 ; WX 333 ; N breve ; B -2 604 335 750 ;
-C 199 ; WX 333 ; N dotaccent ; B 104 614 230 729 ;
-C 200 ; WX 333 ; N dieresis ; B 6 614 327 729 ;
-C 202 ; WX 333 ; N ring ; B 59 568 275 776 ;
-C 203 ; WX 333 ; N cedilla ; B 6 -228 245 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 9 604 486 750 ;
-C 206 ; WX 333 ; N ogonek ; B 71 -228 304 0 ;
-C 207 ; WX 333 ; N caron ; B -10 604 343 750 ;
-C 208 ; WX 1000 ; N emdash ; B 0 227 1000 333 ;
-C 225 ; WX 1000 ; N AE ; B 5 0 954 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 22 276 347 737 ;
-C 232 ; WX 611 ; N Lslash ; B -20 0 583 718 ;
-C 233 ; WX 778 ; N Oslash ; B 33 -27 744 745 ;
-C 234 ; WX 1000 ; N OE ; B 37 -19 961 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 6 276 360 737 ;
-C 241 ; WX 889 ; N ae ; B 29 -14 858 546 ;
-C 245 ; WX 278 ; N dotlessi ; B 69 0 209 532 ;
-C 248 ; WX 278 ; N lslash ; B -18 0 296 718 ;
-C 249 ; WX 611 ; N oslash ; B 22 -29 589 560 ;
-C 250 ; WX 944 ; N oe ; B 34 -14 912 546 ;
-C 251 ; WX 611 ; N germandbls ; B 69 -14 579 731 ;
-C -1 ; WX 611 ; N Zcaron ; B 25 0 586 936 ;
-C -1 ; WX 556 ; N ccedilla ; B 34 -228 524 546 ;
-C -1 ; WX 556 ; N ydieresis ; B 10 -214 539 729 ;
-C -1 ; WX 556 ; N atilde ; B 29 -14 527 737 ;
-C -1 ; WX 278 ; N icircumflex ; B -37 0 316 750 ;
-C -1 ; WX 333 ; N threesuperior ; B 8 271 326 710 ;
-C -1 ; WX 556 ; N ecircumflex ; B 23 -14 528 750 ;
-C -1 ; WX 611 ; N thorn ; B 62 -208 578 718 ;
-C -1 ; WX 556 ; N egrave ; B 23 -14 528 750 ;
-C -1 ; WX 333 ; N twosuperior ; B 9 283 324 710 ;
-C -1 ; WX 556 ; N eacute ; B 23 -14 528 750 ;
-C -1 ; WX 611 ; N otilde ; B 34 -14 578 737 ;
-C -1 ; WX 722 ; N Aacute ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N ocircumflex ; B 34 -14 578 750 ;
-C -1 ; WX 556 ; N yacute ; B 10 -214 539 750 ;
-C -1 ; WX 611 ; N udieresis ; B 66 -14 545 729 ;
-C -1 ; WX 834 ; N threequarters ; B 16 -19 799 710 ;
-C -1 ; WX 556 ; N acircumflex ; B 29 -14 527 750 ;
-C -1 ; WX 722 ; N Eth ; B -5 0 685 718 ;
-C -1 ; WX 556 ; N edieresis ; B 23 -14 528 729 ;
-C -1 ; WX 611 ; N ugrave ; B 66 -14 545 750 ;
-C -1 ; WX 1000 ; N trademark ; B 44 306 956 718 ;
-C -1 ; WX 611 ; N ograve ; B 34 -14 578 750 ;
-C -1 ; WX 556 ; N scaron ; B 30 -14 519 750 ;
-C -1 ; WX 278 ; N Idieresis ; B -21 0 300 915 ;
-C -1 ; WX 611 ; N uacute ; B 66 -14 545 750 ;
-C -1 ; WX 556 ; N agrave ; B 29 -14 527 750 ;
-C -1 ; WX 611 ; N ntilde ; B 65 0 546 737 ;
-C -1 ; WX 556 ; N aring ; B 29 -14 527 776 ;
-C -1 ; WX 500 ; N zcaron ; B 20 0 480 750 ;
-C -1 ; WX 278 ; N Icircumflex ; B -37 0 316 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 69 0 654 923 ;
-C -1 ; WX 611 ; N ucircumflex ; B 66 -14 545 750 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 76 0 621 936 ;
-C -1 ; WX 278 ; N Iacute ; B 64 0 329 936 ;
-C -1 ; WX 722 ; N Ccedilla ; B 44 -228 684 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 44 -19 734 915 ;
-C -1 ; WX 667 ; N Scaron ; B 39 -19 629 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 76 0 621 915 ;
-C -1 ; WX 278 ; N Igrave ; B -50 0 214 936 ;
-C -1 ; WX 556 ; N adieresis ; B 29 -14 527 729 ;
-C -1 ; WX 778 ; N Ograve ; B 44 -19 734 936 ;
-C -1 ; WX 667 ; N Egrave ; B 76 0 621 936 ;
-C -1 ; WX 667 ; N Ydieresis ; B 15 0 653 915 ;
-C -1 ; WX 737 ; N registered ; B -11 -19 748 737 ;
-C -1 ; WX 778 ; N Otilde ; B 44 -19 734 923 ;
-C -1 ; WX 834 ; N onequarter ; B 26 -19 766 710 ;
-C -1 ; WX 722 ; N Ugrave ; B 72 -19 651 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 72 -19 651 936 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 627 718 ;
-C -1 ; WX 584 ; N divide ; B 40 -42 544 548 ;
-C -1 ; WX 722 ; N Atilde ; B 20 0 702 923 ;
-C -1 ; WX 722 ; N Uacute ; B 72 -19 651 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 44 -19 734 936 ;
-C -1 ; WX 584 ; N logicalnot ; B 40 108 544 419 ;
-C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
-C -1 ; WX 278 ; N idieresis ; B -21 0 300 729 ;
-C -1 ; WX 278 ; N iacute ; B 69 0 329 750 ;
-C -1 ; WX 556 ; N aacute ; B 29 -14 527 750 ;
-C -1 ; WX 584 ; N plusminus ; B 40 0 544 506 ;
-C -1 ; WX 584 ; N multiply ; B 40 1 545 505 ;
-C -1 ; WX 722 ; N Udieresis ; B 72 -19 651 915 ;
-C -1 ; WX 584 ; N minus ; B 40 197 544 309 ;
-C -1 ; WX 333 ; N onesuperior ; B 26 283 237 710 ;
-C -1 ; WX 667 ; N Eacute ; B 76 0 621 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 20 0 702 936 ;
-C -1 ; WX 737 ; N copyright ; B -11 -19 749 737 ;
-C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N odieresis ; B 34 -14 578 729 ;
-C -1 ; WX 611 ; N oacute ; B 34 -14 578 750 ;
-C -1 ; WX 400 ; N degree ; B 57 426 343 712 ;
-C -1 ; WX 278 ; N igrave ; B -50 0 209 750 ;
-C -1 ; WX 611 ; N mu ; B 66 -207 545 532 ;
-C -1 ; WX 778 ; N Oacute ; B 44 -19 734 936 ;
-C -1 ; WX 611 ; N eth ; B 34 -14 578 737 ;
-C -1 ; WX 722 ; N Adieresis ; B 20 0 702 915 ;
-C -1 ; WX 667 ; N Yacute ; B 15 0 653 936 ;
-C -1 ; WX 280 ; N brokenbar ; B 84 -19 196 737 ;
-C -1 ; WX 834 ; N onehalf ; B 26 -19 794 710 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 209
-
-KPX A y -30
-KPX A w -30
-KPX A v -40
-KPX A u -30
-KPX A Y -110
-KPX A W -60
-KPX A V -80
-KPX A U -50
-KPX A T -90
-KPX A Q -40
-KPX A O -40
-KPX A G -50
-KPX A C -40
-
-KPX B U -10
-KPX B A -30
-
-KPX D period -30
-KPX D comma -30
-KPX D Y -70
-KPX D W -40
-KPX D V -40
-KPX D A -40
-
-KPX F period -100
-KPX F comma -100
-KPX F a -20
-KPX F A -80
-
-KPX J u -20
-KPX J period -20
-KPX J comma -20
-KPX J A -20
-
-KPX K y -40
-KPX K u -30
-KPX K o -35
-KPX K e -15
-KPX K O -30
-
-KPX L y -30
-KPX L quoteright -140
-KPX L quotedblright -140
-KPX L Y -120
-KPX L W -80
-KPX L V -110
-KPX L T -90
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -50
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -50
-
-KPX P period -120
-KPX P o -40
-KPX P e -30
-KPX P comma -120
-KPX P a -30
-KPX P A -100
-
-KPX Q period 20
-KPX Q comma 20
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -40
-KPX R V -50
-KPX R U -20
-KPX R T -20
-KPX R O -20
-
-KPX T y -60
-KPX T w -60
-KPX T u -90
-KPX T semicolon -40
-KPX T r -80
-KPX T period -80
-KPX T o -80
-KPX T hyphen -120
-KPX T e -60
-KPX T comma -80
-KPX T colon -40
-KPX T a -80
-KPX T O -40
-KPX T A -90
-
-KPX U period -30
-KPX U comma -30
-KPX U A -50
-
-KPX V u -60
-KPX V semicolon -40
-KPX V period -120
-KPX V o -90
-KPX V hyphen -80
-KPX V e -50
-KPX V comma -120
-KPX V colon -40
-KPX V a -60
-KPX V O -50
-KPX V G -50
-KPX V A -80
-
-KPX W y -20
-KPX W u -45
-KPX W semicolon -10
-KPX W period -80
-KPX W o -60
-KPX W hyphen -40
-KPX W e -35
-KPX W comma -80
-KPX W colon -10
-KPX W a -40
-KPX W O -20
-KPX W A -60
-
-KPX Y u -100
-KPX Y semicolon -50
-KPX Y period -100
-KPX Y o -100
-KPX Y e -80
-KPX Y comma -100
-KPX Y colon -50
-KPX Y a -90
-KPX Y O -70
-KPX Y A -110
-
-KPX a y -20
-KPX a w -15
-KPX a v -15
-KPX a g -10
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b l -10
-
-KPX c y -10
-KPX c l -20
-KPX c k -20
-KPX c h -10
-
-KPX colon space -40
-
-KPX comma space -40
-KPX comma quoteright -120
-KPX comma quotedblright -120
-
-KPX d y -15
-KPX d w -15
-KPX d v -15
-KPX d d -10
-
-KPX e y -15
-KPX e x -15
-KPX e w -15
-KPX e v -15
-KPX e period 20
-KPX e comma 10
-
-KPX f quoteright 30
-KPX f quotedblright 30
-KPX f period -10
-KPX f o -20
-KPX f e -10
-KPX f comma -10
-
-KPX g g -10
-KPX g e 10
-
-KPX h y -20
-
-KPX k o -15
-
-KPX l y -15
-KPX l w -15
-
-KPX m y -30
-KPX m u -20
-
-KPX n y -20
-KPX n v -40
-KPX n u -10
-
-KPX o y -20
-KPX o x -30
-KPX o w -15
-KPX o v -20
-
-KPX p y -15
-
-KPX period space -40
-KPX period quoteright -120
-KPX period quotedblright -120
-
-KPX quotedblright space -80
-
-KPX quoteleft quoteleft -46
-
-KPX quoteright v -20
-KPX quoteright space -80
-KPX quoteright s -60
-KPX quoteright r -40
-KPX quoteright quoteright -46
-KPX quoteright l -20
-KPX quoteright d -80
-
-KPX r y 10
-KPX r v 10
-KPX r t 20
-KPX r s -15
-KPX r q -20
-KPX r period -60
-KPX r o -20
-KPX r hyphen -20
-KPX r g -15
-KPX r d -20
-KPX r comma -60
-KPX r c -20
-
-KPX s w -15
-
-KPX semicolon space -40
-
-KPX space quoteleft -60
-KPX space quotedblleft -80
-KPX space Y -120
-KPX space W -80
-KPX space V -80
-KPX space T -100
-
-KPX v period -80
-KPX v o -30
-KPX v comma -80
-KPX v a -20
-
-KPX w period -40
-KPX w o -20
-KPX w comma -40
-
-KPX x e -10
-
-KPX y period -80
-KPX y o -25
-KPX y e -10
-KPX y comma -80
-KPX y a -30
-
-KPX z e 10
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 195 186 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 195 186 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 195 186 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 195 186 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 195 186 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 195 186 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 215 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 167 186 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 167 186 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 167 186 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 167 186 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute -27 186 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex -27 186 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis -27 186 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave -27 186 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 186 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 186 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 186 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 186 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 186 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 186 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 167 186 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 186 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 186 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 186 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 186 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 167 186 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 167 186 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 186 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 112 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 132 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 139 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 139 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 139 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 139 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 139 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 139 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 112 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 139 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 139 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 139 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 139 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 112 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 112 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Thu Mar 15 10:44:33 1990
-Comment UniqueID 28371
-Comment VMusage 7614 43068
-FontName Helvetica-BoldOblique
-FullName Helvetica Bold Oblique
-FamilyName Helvetica
-Weight Bold
-ItalicAngle -12
-IsFixedPitch false
-FontBBox -174 -228 1114 962
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 532
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 94 0 397 718 ;
-C 34 ; WX 474 ; N quotedbl ; B 193 447 529 718 ;
-C 35 ; WX 556 ; N numbersign ; B 60 0 644 698 ;
-C 36 ; WX 556 ; N dollar ; B 67 -115 622 775 ;
-C 37 ; WX 889 ; N percent ; B 136 -19 901 710 ;
-C 38 ; WX 722 ; N ampersand ; B 89 -19 732 718 ;
-C 39 ; WX 278 ; N quoteright ; B 167 445 362 718 ;
-C 40 ; WX 333 ; N parenleft ; B 76 -208 470 734 ;
-C 41 ; WX 333 ; N parenright ; B -25 -208 369 734 ;
-C 42 ; WX 389 ; N asterisk ; B 146 387 481 718 ;
-C 43 ; WX 584 ; N plus ; B 82 0 610 506 ;
-C 44 ; WX 278 ; N comma ; B 28 -168 245 146 ;
-C 45 ; WX 333 ; N hyphen ; B 73 215 379 345 ;
-C 46 ; WX 278 ; N period ; B 64 0 245 146 ;
-C 47 ; WX 278 ; N slash ; B -37 -19 468 737 ;
-C 48 ; WX 556 ; N zero ; B 86 -19 617 710 ;
-C 49 ; WX 556 ; N one ; B 173 0 529 710 ;
-C 50 ; WX 556 ; N two ; B 26 0 619 710 ;
-C 51 ; WX 556 ; N three ; B 65 -19 608 710 ;
-C 52 ; WX 556 ; N four ; B 60 0 598 710 ;
-C 53 ; WX 556 ; N five ; B 64 -19 636 698 ;
-C 54 ; WX 556 ; N six ; B 85 -19 619 710 ;
-C 55 ; WX 556 ; N seven ; B 125 0 676 698 ;
-C 56 ; WX 556 ; N eight ; B 69 -19 616 710 ;
-C 57 ; WX 556 ; N nine ; B 78 -19 615 710 ;
-C 58 ; WX 333 ; N colon ; B 92 0 351 512 ;
-C 59 ; WX 333 ; N semicolon ; B 56 -168 351 512 ;
-C 60 ; WX 584 ; N less ; B 82 -8 655 514 ;
-C 61 ; WX 584 ; N equal ; B 58 87 633 419 ;
-C 62 ; WX 584 ; N greater ; B 36 -8 609 514 ;
-C 63 ; WX 611 ; N question ; B 165 0 671 727 ;
-C 64 ; WX 975 ; N at ; B 186 -19 954 737 ;
-C 65 ; WX 722 ; N A ; B 20 0 702 718 ;
-C 66 ; WX 722 ; N B ; B 76 0 764 718 ;
-C 67 ; WX 722 ; N C ; B 107 -19 789 737 ;
-C 68 ; WX 722 ; N D ; B 76 0 777 718 ;
-C 69 ; WX 667 ; N E ; B 76 0 757 718 ;
-C 70 ; WX 611 ; N F ; B 76 0 740 718 ;
-C 71 ; WX 778 ; N G ; B 108 -19 817 737 ;
-C 72 ; WX 722 ; N H ; B 71 0 804 718 ;
-C 73 ; WX 278 ; N I ; B 64 0 367 718 ;
-C 74 ; WX 556 ; N J ; B 60 -18 637 718 ;
-C 75 ; WX 722 ; N K ; B 87 0 858 718 ;
-C 76 ; WX 611 ; N L ; B 76 0 611 718 ;
-C 77 ; WX 833 ; N M ; B 69 0 918 718 ;
-C 78 ; WX 722 ; N N ; B 69 0 807 718 ;
-C 79 ; WX 778 ; N O ; B 107 -19 823 737 ;
-C 80 ; WX 667 ; N P ; B 76 0 738 718 ;
-C 81 ; WX 778 ; N Q ; B 107 -52 823 737 ;
-C 82 ; WX 722 ; N R ; B 76 0 778 718 ;
-C 83 ; WX 667 ; N S ; B 81 -19 718 737 ;
-C 84 ; WX 611 ; N T ; B 140 0 751 718 ;
-C 85 ; WX 722 ; N U ; B 116 -19 804 718 ;
-C 86 ; WX 667 ; N V ; B 172 0 801 718 ;
-C 87 ; WX 944 ; N W ; B 169 0 1082 718 ;
-C 88 ; WX 667 ; N X ; B 14 0 791 718 ;
-C 89 ; WX 667 ; N Y ; B 168 0 806 718 ;
-C 90 ; WX 611 ; N Z ; B 25 0 737 718 ;
-C 91 ; WX 333 ; N bracketleft ; B 21 -196 462 722 ;
-C 92 ; WX 278 ; N backslash ; B 124 -19 307 737 ;
-C 93 ; WX 333 ; N bracketright ; B -18 -196 423 722 ;
-C 94 ; WX 584 ; N asciicircum ; B 131 323 591 698 ;
-C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
-C 96 ; WX 278 ; N quoteleft ; B 165 454 361 727 ;
-C 97 ; WX 556 ; N a ; B 55 -14 583 546 ;
-C 98 ; WX 611 ; N b ; B 61 -14 645 718 ;
-C 99 ; WX 556 ; N c ; B 79 -14 599 546 ;
-C 100 ; WX 611 ; N d ; B 82 -14 704 718 ;
-C 101 ; WX 556 ; N e ; B 70 -14 593 546 ;
-C 102 ; WX 333 ; N f ; B 87 0 469 727 ; L i fi ; L l fl ;
-C 103 ; WX 611 ; N g ; B 38 -217 666 546 ;
-C 104 ; WX 611 ; N h ; B 65 0 629 718 ;
-C 105 ; WX 278 ; N i ; B 69 0 363 725 ;
-C 106 ; WX 278 ; N j ; B -42 -214 363 725 ;
-C 107 ; WX 556 ; N k ; B 69 0 670 718 ;
-C 108 ; WX 278 ; N l ; B 69 0 362 718 ;
-C 109 ; WX 889 ; N m ; B 64 0 909 546 ;
-C 110 ; WX 611 ; N n ; B 65 0 629 546 ;
-C 111 ; WX 611 ; N o ; B 82 -14 643 546 ;
-C 112 ; WX 611 ; N p ; B 18 -207 645 546 ;
-C 113 ; WX 611 ; N q ; B 80 -207 665 546 ;
-C 114 ; WX 389 ; N r ; B 64 0 489 546 ;
-C 115 ; WX 556 ; N s ; B 63 -14 584 546 ;
-C 116 ; WX 333 ; N t ; B 100 -6 422 676 ;
-C 117 ; WX 611 ; N u ; B 98 -14 658 532 ;
-C 118 ; WX 556 ; N v ; B 126 0 656 532 ;
-C 119 ; WX 778 ; N w ; B 123 0 882 532 ;
-C 120 ; WX 556 ; N x ; B 15 0 648 532 ;
-C 121 ; WX 556 ; N y ; B 42 -214 652 532 ;
-C 122 ; WX 500 ; N z ; B 20 0 583 532 ;
-C 123 ; WX 389 ; N braceleft ; B 94 -196 518 722 ;
-C 124 ; WX 280 ; N bar ; B 80 -19 353 737 ;
-C 125 ; WX 389 ; N braceright ; B -18 -196 407 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 115 163 577 343 ;
-C 161 ; WX 333 ; N exclamdown ; B 50 -186 353 532 ;
-C 162 ; WX 556 ; N cent ; B 79 -118 599 628 ;
-C 163 ; WX 556 ; N sterling ; B 50 -16 635 718 ;
-C 164 ; WX 167 ; N fraction ; B -174 -19 487 710 ;
-C 165 ; WX 556 ; N yen ; B 60 0 713 698 ;
-C 166 ; WX 556 ; N florin ; B -50 -210 669 737 ;
-C 167 ; WX 556 ; N section ; B 61 -184 598 727 ;
-C 168 ; WX 556 ; N currency ; B 27 76 680 636 ;
-C 169 ; WX 238 ; N quotesingle ; B 165 447 321 718 ;
-C 170 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ;
-C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ;
-C 173 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ;
-C 174 ; WX 611 ; N fi ; B 87 0 696 727 ;
-C 175 ; WX 611 ; N fl ; B 87 0 695 727 ;
-C 177 ; WX 556 ; N endash ; B 48 227 627 333 ;
-C 178 ; WX 556 ; N dagger ; B 118 -171 626 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 46 -171 628 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 110 172 276 334 ;
-C 182 ; WX 556 ; N paragraph ; B 98 -191 688 700 ;
-C 183 ; WX 350 ; N bullet ; B 83 194 420 524 ;
-C 184 ; WX 278 ; N quotesinglbase ; B 41 -146 236 127 ;
-C 185 ; WX 500 ; N quotedblbase ; B 36 -146 463 127 ;
-C 186 ; WX 500 ; N quotedblright ; B 162 445 589 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 104 76 540 484 ;
-C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ;
-C 189 ; WX 1000 ; N perthousand ; B 76 -19 1038 710 ;
-C 191 ; WX 611 ; N questiondown ; B 53 -195 559 532 ;
-C 193 ; WX 333 ; N grave ; B 136 604 353 750 ;
-C 194 ; WX 333 ; N acute ; B 236 604 515 750 ;
-C 195 ; WX 333 ; N circumflex ; B 118 604 471 750 ;
-C 196 ; WX 333 ; N tilde ; B 113 610 507 737 ;
-C 197 ; WX 333 ; N macron ; B 122 604 483 678 ;
-C 198 ; WX 333 ; N breve ; B 156 604 494 750 ;
-C 199 ; WX 333 ; N dotaccent ; B 235 614 385 729 ;
-C 200 ; WX 333 ; N dieresis ; B 137 614 482 729 ;
-C 202 ; WX 333 ; N ring ; B 200 568 420 776 ;
-C 203 ; WX 333 ; N cedilla ; B -37 -228 220 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 137 604 645 750 ;
-C 206 ; WX 333 ; N ogonek ; B 41 -228 264 0 ;
-C 207 ; WX 333 ; N caron ; B 149 604 502 750 ;
-C 208 ; WX 1000 ; N emdash ; B 48 227 1071 333 ;
-C 225 ; WX 1000 ; N AE ; B 5 0 1100 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 92 276 465 737 ;
-C 232 ; WX 611 ; N Lslash ; B 34 0 611 718 ;
-C 233 ; WX 778 ; N Oslash ; B 35 -27 894 745 ;
-C 234 ; WX 1000 ; N OE ; B 99 -19 1114 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 92 276 485 737 ;
-C 241 ; WX 889 ; N ae ; B 56 -14 923 546 ;
-C 245 ; WX 278 ; N dotlessi ; B 69 0 322 532 ;
-C 248 ; WX 278 ; N lslash ; B 40 0 407 718 ;
-C 249 ; WX 611 ; N oslash ; B 22 -29 701 560 ;
-C 250 ; WX 944 ; N oe ; B 82 -14 977 546 ;
-C 251 ; WX 611 ; N germandbls ; B 69 -14 657 731 ;
-C -1 ; WX 611 ; N Zcaron ; B 25 0 737 936 ;
-C -1 ; WX 556 ; N ccedilla ; B 79 -228 599 546 ;
-C -1 ; WX 556 ; N ydieresis ; B 42 -214 652 729 ;
-C -1 ; WX 556 ; N atilde ; B 55 -14 619 737 ;
-C -1 ; WX 278 ; N icircumflex ; B 69 0 444 750 ;
-C -1 ; WX 333 ; N threesuperior ; B 91 271 441 710 ;
-C -1 ; WX 556 ; N ecircumflex ; B 70 -14 593 750 ;
-C -1 ; WX 611 ; N thorn ; B 18 -208 645 718 ;
-C -1 ; WX 556 ; N egrave ; B 70 -14 593 750 ;
-C -1 ; WX 333 ; N twosuperior ; B 69 283 449 710 ;
-C -1 ; WX 556 ; N eacute ; B 70 -14 627 750 ;
-C -1 ; WX 611 ; N otilde ; B 82 -14 646 737 ;
-C -1 ; WX 722 ; N Aacute ; B 20 0 750 936 ;
-C -1 ; WX 611 ; N ocircumflex ; B 82 -14 643 750 ;
-C -1 ; WX 556 ; N yacute ; B 42 -214 652 750 ;
-C -1 ; WX 611 ; N udieresis ; B 98 -14 658 729 ;
-C -1 ; WX 834 ; N threequarters ; B 99 -19 839 710 ;
-C -1 ; WX 556 ; N acircumflex ; B 55 -14 583 750 ;
-C -1 ; WX 722 ; N Eth ; B 62 0 777 718 ;
-C -1 ; WX 556 ; N edieresis ; B 70 -14 594 729 ;
-C -1 ; WX 611 ; N ugrave ; B 98 -14 658 750 ;
-C -1 ; WX 1000 ; N trademark ; B 179 306 1109 718 ;
-C -1 ; WX 611 ; N ograve ; B 82 -14 643 750 ;
-C -1 ; WX 556 ; N scaron ; B 63 -14 614 750 ;
-C -1 ; WX 278 ; N Idieresis ; B 64 0 494 915 ;
-C -1 ; WX 611 ; N uacute ; B 98 -14 658 750 ;
-C -1 ; WX 556 ; N agrave ; B 55 -14 583 750 ;
-C -1 ; WX 611 ; N ntilde ; B 65 0 646 737 ;
-C -1 ; WX 556 ; N aring ; B 55 -14 583 776 ;
-C -1 ; WX 500 ; N zcaron ; B 20 0 586 750 ;
-C -1 ; WX 278 ; N Icircumflex ; B 64 0 484 936 ;
-C -1 ; WX 722 ; N Ntilde ; B 69 0 807 923 ;
-C -1 ; WX 611 ; N ucircumflex ; B 98 -14 658 750 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 76 0 757 936 ;
-C -1 ; WX 278 ; N Iacute ; B 64 0 528 936 ;
-C -1 ; WX 722 ; N Ccedilla ; B 107 -228 789 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 107 -19 823 915 ;
-C -1 ; WX 667 ; N Scaron ; B 81 -19 718 936 ;
-C -1 ; WX 667 ; N Edieresis ; B 76 0 757 915 ;
-C -1 ; WX 278 ; N Igrave ; B 64 0 367 936 ;
-C -1 ; WX 556 ; N adieresis ; B 55 -14 594 729 ;
-C -1 ; WX 778 ; N Ograve ; B 107 -19 823 936 ;
-C -1 ; WX 667 ; N Egrave ; B 76 0 757 936 ;
-C -1 ; WX 667 ; N Ydieresis ; B 168 0 806 915 ;
-C -1 ; WX 737 ; N registered ; B 55 -19 834 737 ;
-C -1 ; WX 778 ; N Otilde ; B 107 -19 823 923 ;
-C -1 ; WX 834 ; N onequarter ; B 132 -19 806 710 ;
-C -1 ; WX 722 ; N Ugrave ; B 116 -19 804 936 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 116 -19 804 936 ;
-C -1 ; WX 667 ; N Thorn ; B 76 0 716 718 ;
-C -1 ; WX 584 ; N divide ; B 82 -42 610 548 ;
-C -1 ; WX 722 ; N Atilde ; B 20 0 741 923 ;
-C -1 ; WX 722 ; N Uacute ; B 116 -19 804 936 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 107 -19 823 936 ;
-C -1 ; WX 584 ; N logicalnot ; B 105 108 633 419 ;
-C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ;
-C -1 ; WX 278 ; N idieresis ; B 69 0 455 729 ;
-C -1 ; WX 278 ; N iacute ; B 69 0 488 750 ;
-C -1 ; WX 556 ; N aacute ; B 55 -14 627 750 ;
-C -1 ; WX 584 ; N plusminus ; B 40 0 625 506 ;
-C -1 ; WX 584 ; N multiply ; B 57 1 635 505 ;
-C -1 ; WX 722 ; N Udieresis ; B 116 -19 804 915 ;
-C -1 ; WX 584 ; N minus ; B 82 197 610 309 ;
-C -1 ; WX 333 ; N onesuperior ; B 148 283 388 710 ;
-C -1 ; WX 667 ; N Eacute ; B 76 0 757 936 ;
-C -1 ; WX 722 ; N Acircumflex ; B 20 0 706 936 ;
-C -1 ; WX 737 ; N copyright ; B 56 -19 835 737 ;
-C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ;
-C -1 ; WX 611 ; N odieresis ; B 82 -14 643 729 ;
-C -1 ; WX 611 ; N oacute ; B 82 -14 654 750 ;
-C -1 ; WX 400 ; N degree ; B 175 426 467 712 ;
-C -1 ; WX 278 ; N igrave ; B 69 0 326 750 ;
-C -1 ; WX 611 ; N mu ; B 22 -207 658 532 ;
-C -1 ; WX 778 ; N Oacute ; B 107 -19 823 936 ;
-C -1 ; WX 611 ; N eth ; B 82 -14 670 737 ;
-C -1 ; WX 722 ; N Adieresis ; B 20 0 716 915 ;
-C -1 ; WX 667 ; N Yacute ; B 168 0 806 936 ;
-C -1 ; WX 280 ; N brokenbar ; B 80 -19 353 737 ;
-C -1 ; WX 834 ; N onehalf ; B 132 -19 858 710 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 209
-
-KPX A y -30
-KPX A w -30
-KPX A v -40
-KPX A u -30
-KPX A Y -110
-KPX A W -60
-KPX A V -80
-KPX A U -50
-KPX A T -90
-KPX A Q -40
-KPX A O -40
-KPX A G -50
-KPX A C -40
-
-KPX B U -10
-KPX B A -30
-
-KPX D period -30
-KPX D comma -30
-KPX D Y -70
-KPX D W -40
-KPX D V -40
-KPX D A -40
-
-KPX F period -100
-KPX F comma -100
-KPX F a -20
-KPX F A -80
-
-KPX J u -20
-KPX J period -20
-KPX J comma -20
-KPX J A -20
-
-KPX K y -40
-KPX K u -30
-KPX K o -35
-KPX K e -15
-KPX K O -30
-
-KPX L y -30
-KPX L quoteright -140
-KPX L quotedblright -140
-KPX L Y -120
-KPX L W -80
-KPX L V -110
-KPX L T -90
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -50
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -50
-
-KPX P period -120
-KPX P o -40
-KPX P e -30
-KPX P comma -120
-KPX P a -30
-KPX P A -100
-
-KPX Q period 20
-KPX Q comma 20
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -40
-KPX R V -50
-KPX R U -20
-KPX R T -20
-KPX R O -20
-
-KPX T y -60
-KPX T w -60
-KPX T u -90
-KPX T semicolon -40
-KPX T r -80
-KPX T period -80
-KPX T o -80
-KPX T hyphen -120
-KPX T e -60
-KPX T comma -80
-KPX T colon -40
-KPX T a -80
-KPX T O -40
-KPX T A -90
-
-KPX U period -30
-KPX U comma -30
-KPX U A -50
-
-KPX V u -60
-KPX V semicolon -40
-KPX V period -120
-KPX V o -90
-KPX V hyphen -80
-KPX V e -50
-KPX V comma -120
-KPX V colon -40
-KPX V a -60
-KPX V O -50
-KPX V G -50
-KPX V A -80
-
-KPX W y -20
-KPX W u -45
-KPX W semicolon -10
-KPX W period -80
-KPX W o -60
-KPX W hyphen -40
-KPX W e -35
-KPX W comma -80
-KPX W colon -10
-KPX W a -40
-KPX W O -20
-KPX W A -60
-
-KPX Y u -100
-KPX Y semicolon -50
-KPX Y period -100
-KPX Y o -100
-KPX Y e -80
-KPX Y comma -100
-KPX Y colon -50
-KPX Y a -90
-KPX Y O -70
-KPX Y A -110
-
-KPX a y -20
-KPX a w -15
-KPX a v -15
-KPX a g -10
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b l -10
-
-KPX c y -10
-KPX c l -20
-KPX c k -20
-KPX c h -10
-
-KPX colon space -40
-
-KPX comma space -40
-KPX comma quoteright -120
-KPX comma quotedblright -120
-
-KPX d y -15
-KPX d w -15
-KPX d v -15
-KPX d d -10
-
-KPX e y -15
-KPX e x -15
-KPX e w -15
-KPX e v -15
-KPX e period 20
-KPX e comma 10
-
-KPX f quoteright 30
-KPX f quotedblright 30
-KPX f period -10
-KPX f o -20
-KPX f e -10
-KPX f comma -10
-
-KPX g g -10
-KPX g e 10
-
-KPX h y -20
-
-KPX k o -15
-
-KPX l y -15
-KPX l w -15
-
-KPX m y -30
-KPX m u -20
-
-KPX n y -20
-KPX n v -40
-KPX n u -10
-
-KPX o y -20
-KPX o x -30
-KPX o w -15
-KPX o v -20
-
-KPX p y -15
-
-KPX period space -40
-KPX period quoteright -120
-KPX period quotedblright -120
-
-KPX quotedblright space -80
-
-KPX quoteleft quoteleft -46
-
-KPX quoteright v -20
-KPX quoteright space -80
-KPX quoteright s -60
-KPX quoteright r -40
-KPX quoteright quoteright -46
-KPX quoteright l -20
-KPX quoteright d -80
-
-KPX r y 10
-KPX r v 10
-KPX r t 20
-KPX r s -15
-KPX r q -20
-KPX r period -60
-KPX r o -20
-KPX r hyphen -20
-KPX r g -15
-KPX r d -20
-KPX r comma -60
-KPX r c -20
-
-KPX s w -15
-
-KPX semicolon space -40
-
-KPX space quoteleft -60
-KPX space quotedblleft -80
-KPX space Y -120
-KPX space W -80
-KPX space V -80
-KPX space T -100
-
-KPX v period -80
-KPX v o -30
-KPX v comma -80
-KPX v a -20
-
-KPX w period -40
-KPX w o -20
-KPX w comma -40
-
-KPX x e -10
-
-KPX y period -80
-KPX y o -25
-KPX y e -10
-KPX y comma -80
-KPX y a -30
-
-KPX z e 10
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 235 186 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 235 186 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 235 186 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 235 186 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 235 186 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 235 186 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 215 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 207 186 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 207 186 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 207 186 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 207 186 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 13 186 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 13 186 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 13 186 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 13 186 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 235 186 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 263 186 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 263 186 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 263 186 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 263 186 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 263 186 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 207 186 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 235 186 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 235 186 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 235 186 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 235 186 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 207 186 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 207 186 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 179 186 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 112 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 132 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 139 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 139 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 139 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 139 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 139 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 139 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 112 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 139 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 139 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 139 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 139 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 112 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 112 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Mar 15 10:24:18 1990
-Comment UniqueID 28362
-Comment VMusage 7572 42473
-FontName Helvetica-Oblique
-FullName Helvetica Oblique
-FamilyName Helvetica
-Weight Medium
-ItalicAngle -12
-IsFixedPitch false
-FontBBox -170 -225 1116 931
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.006
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 90 0 340 718 ;
-C 34 ; WX 355 ; N quotedbl ; B 168 463 438 718 ;
-C 35 ; WX 556 ; N numbersign ; B 73 0 631 688 ;
-C 36 ; WX 556 ; N dollar ; B 69 -115 617 775 ;
-C 37 ; WX 889 ; N percent ; B 147 -19 889 703 ;
-C 38 ; WX 667 ; N ampersand ; B 77 -15 647 718 ;
-C 39 ; WX 222 ; N quoteright ; B 151 463 310 718 ;
-C 40 ; WX 333 ; N parenleft ; B 108 -207 454 733 ;
-C 41 ; WX 333 ; N parenright ; B -9 -207 337 733 ;
-C 42 ; WX 389 ; N asterisk ; B 165 431 475 718 ;
-C 43 ; WX 584 ; N plus ; B 85 0 606 505 ;
-C 44 ; WX 278 ; N comma ; B 56 -147 214 106 ;
-C 45 ; WX 333 ; N hyphen ; B 93 232 357 322 ;
-C 46 ; WX 278 ; N period ; B 87 0 214 106 ;
-C 47 ; WX 278 ; N slash ; B -21 -19 452 737 ;
-C 48 ; WX 556 ; N zero ; B 93 -19 608 703 ;
-C 49 ; WX 556 ; N one ; B 207 0 508 703 ;
-C 50 ; WX 556 ; N two ; B 26 0 617 703 ;
-C 51 ; WX 556 ; N three ; B 75 -19 610 703 ;
-C 52 ; WX 556 ; N four ; B 61 0 576 703 ;
-C 53 ; WX 556 ; N five ; B 68 -19 621 688 ;
-C 54 ; WX 556 ; N six ; B 91 -19 615 703 ;
-C 55 ; WX 556 ; N seven ; B 137 0 669 688 ;
-C 56 ; WX 556 ; N eight ; B 74 -19 607 703 ;
-C 57 ; WX 556 ; N nine ; B 82 -19 609 703 ;
-C 58 ; WX 278 ; N colon ; B 87 0 301 516 ;
-C 59 ; WX 278 ; N semicolon ; B 56 -147 301 516 ;
-C 60 ; WX 584 ; N less ; B 94 11 641 495 ;
-C 61 ; WX 584 ; N equal ; B 63 115 628 390 ;
-C 62 ; WX 584 ; N greater ; B 50 11 597 495 ;
-C 63 ; WX 556 ; N question ; B 161 0 610 727 ;
-C 64 ; WX 1015 ; N at ; B 215 -19 965 737 ;
-C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
-C 66 ; WX 667 ; N B ; B 74 0 712 718 ;
-C 67 ; WX 722 ; N C ; B 108 -19 782 737 ;
-C 68 ; WX 722 ; N D ; B 81 0 764 718 ;
-C 69 ; WX 667 ; N E ; B 86 0 762 718 ;
-C 70 ; WX 611 ; N F ; B 86 0 736 718 ;
-C 71 ; WX 778 ; N G ; B 111 -19 799 737 ;
-C 72 ; WX 722 ; N H ; B 77 0 799 718 ;
-C 73 ; WX 278 ; N I ; B 91 0 341 718 ;
-C 74 ; WX 500 ; N J ; B 47 -19 581 718 ;
-C 75 ; WX 667 ; N K ; B 76 0 808 718 ;
-C 76 ; WX 556 ; N L ; B 76 0 555 718 ;
-C 77 ; WX 833 ; N M ; B 73 0 914 718 ;
-C 78 ; WX 722 ; N N ; B 76 0 799 718 ;
-C 79 ; WX 778 ; N O ; B 105 -19 826 737 ;
-C 80 ; WX 667 ; N P ; B 86 0 737 718 ;
-C 81 ; WX 778 ; N Q ; B 105 -56 826 737 ;
-C 82 ; WX 722 ; N R ; B 88 0 773 718 ;
-C 83 ; WX 667 ; N S ; B 90 -19 713 737 ;
-C 84 ; WX 611 ; N T ; B 148 0 750 718 ;
-C 85 ; WX 722 ; N U ; B 123 -19 797 718 ;
-C 86 ; WX 667 ; N V ; B 173 0 800 718 ;
-C 87 ; WX 944 ; N W ; B 169 0 1081 718 ;
-C 88 ; WX 667 ; N X ; B 19 0 790 718 ;
-C 89 ; WX 667 ; N Y ; B 167 0 806 718 ;
-C 90 ; WX 611 ; N Z ; B 23 0 741 718 ;
-C 91 ; WX 278 ; N bracketleft ; B 21 -196 403 722 ;
-C 92 ; WX 278 ; N backslash ; B 140 -19 291 737 ;
-C 93 ; WX 278 ; N bracketright ; B -14 -196 368 722 ;
-C 94 ; WX 469 ; N asciicircum ; B 42 264 539 688 ;
-C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ;
-C 96 ; WX 222 ; N quoteleft ; B 165 470 323 725 ;
-C 97 ; WX 556 ; N a ; B 61 -15 559 538 ;
-C 98 ; WX 556 ; N b ; B 58 -15 584 718 ;
-C 99 ; WX 500 ; N c ; B 74 -15 553 538 ;
-C 100 ; WX 556 ; N d ; B 84 -15 652 718 ;
-C 101 ; WX 556 ; N e ; B 84 -15 578 538 ;
-C 102 ; WX 278 ; N f ; B 86 0 416 728 ; L i fi ; L l fl ;
-C 103 ; WX 556 ; N g ; B 42 -220 610 538 ;
-C 104 ; WX 556 ; N h ; B 65 0 573 718 ;
-C 105 ; WX 222 ; N i ; B 67 0 308 718 ;
-C 106 ; WX 222 ; N j ; B -60 -210 308 718 ;
-C 107 ; WX 500 ; N k ; B 67 0 600 718 ;
-C 108 ; WX 222 ; N l ; B 67 0 308 718 ;
-C 109 ; WX 833 ; N m ; B 65 0 852 538 ;
-C 110 ; WX 556 ; N n ; B 65 0 573 538 ;
-C 111 ; WX 556 ; N o ; B 83 -14 585 538 ;
-C 112 ; WX 556 ; N p ; B 14 -207 584 538 ;
-C 113 ; WX 556 ; N q ; B 84 -207 605 538 ;
-C 114 ; WX 333 ; N r ; B 77 0 446 538 ;
-C 115 ; WX 500 ; N s ; B 63 -15 529 538 ;
-C 116 ; WX 278 ; N t ; B 102 -7 368 669 ;
-C 117 ; WX 556 ; N u ; B 94 -15 600 523 ;
-C 118 ; WX 500 ; N v ; B 119 0 603 523 ;
-C 119 ; WX 722 ; N w ; B 125 0 820 523 ;
-C 120 ; WX 500 ; N x ; B 11 0 594 523 ;
-C 121 ; WX 500 ; N y ; B 15 -214 600 523 ;
-C 122 ; WX 500 ; N z ; B 31 0 571 523 ;
-C 123 ; WX 334 ; N braceleft ; B 92 -196 445 722 ;
-C 124 ; WX 260 ; N bar ; B 90 -19 324 737 ;
-C 125 ; WX 334 ; N braceright ; B 0 -196 354 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 111 180 580 326 ;
-C 161 ; WX 333 ; N exclamdown ; B 77 -195 326 523 ;
-C 162 ; WX 556 ; N cent ; B 95 -115 584 623 ;
-C 163 ; WX 556 ; N sterling ; B 49 -16 634 718 ;
-C 164 ; WX 167 ; N fraction ; B -170 -19 482 703 ;
-C 165 ; WX 556 ; N yen ; B 81 0 699 688 ;
-C 166 ; WX 556 ; N florin ; B -52 -207 654 737 ;
-C 167 ; WX 556 ; N section ; B 76 -191 584 737 ;
-C 168 ; WX 556 ; N currency ; B 60 99 646 603 ;
-C 169 ; WX 191 ; N quotesingle ; B 157 463 285 718 ;
-C 170 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ;
-C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ;
-C 173 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ;
-C 174 ; WX 500 ; N fi ; B 86 0 587 728 ;
-C 175 ; WX 500 ; N fl ; B 86 0 585 728 ;
-C 177 ; WX 556 ; N endash ; B 51 240 623 313 ;
-C 178 ; WX 556 ; N dagger ; B 135 -159 622 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 52 -159 623 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 129 190 257 315 ;
-C 182 ; WX 537 ; N paragraph ; B 126 -173 650 718 ;
-C 183 ; WX 350 ; N bullet ; B 91 202 413 517 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 21 -149 180 106 ;
-C 185 ; WX 333 ; N quotedblbase ; B -6 -149 318 106 ;
-C 186 ; WX 333 ; N quotedblright ; B 124 463 448 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 120 108 528 446 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 908 106 ;
-C 189 ; WX 1000 ; N perthousand ; B 88 -19 1029 703 ;
-C 191 ; WX 611 ; N questiondown ; B 85 -201 534 525 ;
-C 193 ; WX 333 ; N grave ; B 170 593 337 734 ;
-C 194 ; WX 333 ; N acute ; B 248 593 475 734 ;
-C 195 ; WX 333 ; N circumflex ; B 147 593 438 734 ;
-C 196 ; WX 333 ; N tilde ; B 125 606 490 722 ;
-C 197 ; WX 333 ; N macron ; B 143 627 468 684 ;
-C 198 ; WX 333 ; N breve ; B 167 595 476 731 ;
-C 199 ; WX 333 ; N dotaccent ; B 249 604 362 706 ;
-C 200 ; WX 333 ; N dieresis ; B 168 604 443 706 ;
-C 202 ; WX 333 ; N ring ; B 214 572 402 756 ;
-C 203 ; WX 333 ; N cedilla ; B 2 -225 232 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 157 593 565 734 ;
-C 206 ; WX 333 ; N ogonek ; B 43 -225 249 0 ;
-C 207 ; WX 333 ; N caron ; B 177 593 468 734 ;
-C 208 ; WX 1000 ; N emdash ; B 51 240 1067 313 ;
-C 225 ; WX 1000 ; N AE ; B 8 0 1097 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 100 304 449 737 ;
-C 232 ; WX 556 ; N Lslash ; B 41 0 555 718 ;
-C 233 ; WX 778 ; N Oslash ; B 43 -19 890 737 ;
-C 234 ; WX 1000 ; N OE ; B 98 -19 1116 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 100 304 468 737 ;
-C 241 ; WX 889 ; N ae ; B 61 -15 909 538 ;
-C 245 ; WX 278 ; N dotlessi ; B 95 0 294 523 ;
-C 248 ; WX 222 ; N lslash ; B 41 0 347 718 ;
-C 249 ; WX 611 ; N oslash ; B 29 -22 647 545 ;
-C 250 ; WX 944 ; N oe ; B 83 -15 964 538 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -15 658 728 ;
-C -1 ; WX 611 ; N Zcaron ; B 23 0 741 929 ;
-C -1 ; WX 500 ; N ccedilla ; B 74 -225 553 538 ;
-C -1 ; WX 500 ; N ydieresis ; B 15 -214 600 706 ;
-C -1 ; WX 556 ; N atilde ; B 61 -15 592 722 ;
-C -1 ; WX 278 ; N icircumflex ; B 95 0 411 734 ;
-C -1 ; WX 333 ; N threesuperior ; B 90 270 436 703 ;
-C -1 ; WX 556 ; N ecircumflex ; B 84 -15 578 734 ;
-C -1 ; WX 556 ; N thorn ; B 14 -207 584 718 ;
-C -1 ; WX 556 ; N egrave ; B 84 -15 578 734 ;
-C -1 ; WX 333 ; N twosuperior ; B 64 281 449 703 ;
-C -1 ; WX 556 ; N eacute ; B 84 -15 587 734 ;
-C -1 ; WX 556 ; N otilde ; B 83 -14 602 722 ;
-C -1 ; WX 667 ; N Aacute ; B 14 0 683 929 ;
-C -1 ; WX 556 ; N ocircumflex ; B 83 -14 585 734 ;
-C -1 ; WX 500 ; N yacute ; B 15 -214 600 734 ;
-C -1 ; WX 556 ; N udieresis ; B 94 -15 600 706 ;
-C -1 ; WX 834 ; N threequarters ; B 130 -19 861 703 ;
-C -1 ; WX 556 ; N acircumflex ; B 61 -15 559 734 ;
-C -1 ; WX 722 ; N Eth ; B 69 0 764 718 ;
-C -1 ; WX 556 ; N edieresis ; B 84 -15 578 706 ;
-C -1 ; WX 556 ; N ugrave ; B 94 -15 600 734 ;
-C -1 ; WX 1000 ; N trademark ; B 186 306 1056 718 ;
-C -1 ; WX 556 ; N ograve ; B 83 -14 585 734 ;
-C -1 ; WX 500 ; N scaron ; B 63 -15 552 734 ;
-C -1 ; WX 278 ; N Idieresis ; B 91 0 458 901 ;
-C -1 ; WX 556 ; N uacute ; B 94 -15 600 734 ;
-C -1 ; WX 556 ; N agrave ; B 61 -15 559 734 ;
-C -1 ; WX 556 ; N ntilde ; B 65 0 592 722 ;
-C -1 ; WX 556 ; N aring ; B 61 -15 559 756 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 571 734 ;
-C -1 ; WX 278 ; N Icircumflex ; B 91 0 452 929 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 799 917 ;
-C -1 ; WX 556 ; N ucircumflex ; B 94 -15 600 734 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 86 0 762 929 ;
-C -1 ; WX 278 ; N Iacute ; B 91 0 489 929 ;
-C -1 ; WX 722 ; N Ccedilla ; B 108 -225 782 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 105 -19 826 901 ;
-C -1 ; WX 667 ; N Scaron ; B 90 -19 713 929 ;
-C -1 ; WX 667 ; N Edieresis ; B 86 0 762 901 ;
-C -1 ; WX 278 ; N Igrave ; B 91 0 351 929 ;
-C -1 ; WX 556 ; N adieresis ; B 61 -15 559 706 ;
-C -1 ; WX 778 ; N Ograve ; B 105 -19 826 929 ;
-C -1 ; WX 667 ; N Egrave ; B 86 0 762 929 ;
-C -1 ; WX 667 ; N Ydieresis ; B 167 0 806 901 ;
-C -1 ; WX 737 ; N registered ; B 54 -19 837 737 ;
-C -1 ; WX 778 ; N Otilde ; B 105 -19 826 917 ;
-C -1 ; WX 834 ; N onequarter ; B 150 -19 802 703 ;
-C -1 ; WX 722 ; N Ugrave ; B 123 -19 797 929 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 123 -19 797 929 ;
-C -1 ; WX 667 ; N Thorn ; B 86 0 712 718 ;
-C -1 ; WX 584 ; N divide ; B 85 -19 606 524 ;
-C -1 ; WX 667 ; N Atilde ; B 14 0 699 917 ;
-C -1 ; WX 722 ; N Uacute ; B 123 -19 797 929 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 105 -19 826 929 ;
-C -1 ; WX 584 ; N logicalnot ; B 106 108 628 390 ;
-C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
-C -1 ; WX 278 ; N idieresis ; B 95 0 416 706 ;
-C -1 ; WX 278 ; N iacute ; B 95 0 448 734 ;
-C -1 ; WX 556 ; N aacute ; B 61 -15 587 734 ;
-C -1 ; WX 584 ; N plusminus ; B 39 0 618 506 ;
-C -1 ; WX 584 ; N multiply ; B 50 0 642 506 ;
-C -1 ; WX 722 ; N Udieresis ; B 123 -19 797 901 ;
-C -1 ; WX 584 ; N minus ; B 85 216 606 289 ;
-C -1 ; WX 333 ; N onesuperior ; B 166 281 371 703 ;
-C -1 ; WX 667 ; N Eacute ; B 86 0 762 929 ;
-C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
-C -1 ; WX 737 ; N copyright ; B 54 -19 837 737 ;
-C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N odieresis ; B 83 -14 585 706 ;
-C -1 ; WX 556 ; N oacute ; B 83 -14 587 734 ;
-C -1 ; WX 400 ; N degree ; B 169 411 468 703 ;
-C -1 ; WX 278 ; N igrave ; B 95 0 310 734 ;
-C -1 ; WX 556 ; N mu ; B 24 -207 600 523 ;
-C -1 ; WX 778 ; N Oacute ; B 105 -19 826 929 ;
-C -1 ; WX 556 ; N eth ; B 81 -15 617 737 ;
-C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
-C -1 ; WX 667 ; N Yacute ; B 167 0 806 929 ;
-C -1 ; WX 260 ; N brokenbar ; B 90 -19 324 737 ;
-C -1 ; WX 834 ; N onehalf ; B 114 -19 839 703 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 250
-
-KPX A y -40
-KPX A w -40
-KPX A v -40
-KPX A u -30
-KPX A Y -100
-KPX A W -50
-KPX A V -70
-KPX A U -50
-KPX A T -120
-KPX A Q -30
-KPX A O -30
-KPX A G -30
-KPX A C -30
-
-KPX B period -20
-KPX B comma -20
-KPX B U -10
-
-KPX C period -30
-KPX C comma -30
-
-KPX D period -70
-KPX D comma -70
-KPX D Y -90
-KPX D W -40
-KPX D V -70
-KPX D A -40
-
-KPX F r -45
-KPX F period -150
-KPX F o -30
-KPX F e -30
-KPX F comma -150
-KPX F a -50
-KPX F A -80
-
-KPX J u -20
-KPX J period -30
-KPX J comma -30
-KPX J a -20
-KPX J A -20
-
-KPX K y -50
-KPX K u -30
-KPX K o -40
-KPX K e -40
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -160
-KPX L quotedblright -140
-KPX L Y -140
-KPX L W -70
-KPX L V -110
-KPX L T -110
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -60
-KPX O W -30
-KPX O V -50
-KPX O T -40
-KPX O A -20
-
-KPX P period -180
-KPX P o -50
-KPX P e -50
-KPX P comma -180
-KPX P a -40
-KPX P A -120
-
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -30
-KPX R V -50
-KPX R U -40
-KPX R T -30
-KPX R O -20
-
-KPX S period -20
-KPX S comma -20
-
-KPX T y -120
-KPX T w -120
-KPX T u -120
-KPX T semicolon -20
-KPX T r -120
-KPX T period -120
-KPX T o -120
-KPX T hyphen -140
-KPX T e -120
-KPX T comma -120
-KPX T colon -20
-KPX T a -120
-KPX T O -40
-KPX T A -120
-
-KPX U period -40
-KPX U comma -40
-KPX U A -40
-
-KPX V u -70
-KPX V semicolon -40
-KPX V period -125
-KPX V o -80
-KPX V hyphen -80
-KPX V e -80
-KPX V comma -125
-KPX V colon -40
-KPX V a -70
-KPX V O -40
-KPX V G -40
-KPX V A -80
-
-KPX W y -20
-KPX W u -30
-KPX W period -80
-KPX W o -30
-KPX W hyphen -40
-KPX W e -30
-KPX W comma -80
-KPX W a -40
-KPX W O -20
-KPX W A -50
-
-KPX Y u -110
-KPX Y semicolon -60
-KPX Y period -140
-KPX Y o -140
-KPX Y i -20
-KPX Y hyphen -140
-KPX Y e -140
-KPX Y comma -140
-KPX Y colon -60
-KPX Y a -140
-KPX Y O -85
-KPX Y A -110
-
-KPX a y -30
-KPX a w -20
-KPX a v -20
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b period -40
-KPX b l -20
-KPX b comma -40
-KPX b b -10
-
-KPX c k -20
-KPX c comma -15
-
-KPX colon space -50
-
-KPX comma quoteright -100
-KPX comma quotedblright -100
-
-KPX e y -20
-KPX e x -30
-KPX e w -20
-KPX e v -30
-KPX e period -15
-KPX e comma -15
-
-KPX f quoteright 50
-KPX f quotedblright 60
-KPX f period -30
-KPX f o -30
-KPX f e -30
-KPX f dotlessi -28
-KPX f comma -30
-KPX f a -30
-
-KPX g r -10
-
-KPX h y -30
-
-KPX k o -20
-KPX k e -20
-
-KPX m y -15
-KPX m u -10
-
-KPX n y -15
-KPX n v -20
-KPX n u -10
-
-KPX o y -30
-KPX o x -30
-KPX o w -15
-KPX o v -15
-KPX o period -40
-KPX o comma -40
-
-KPX oslash z -55
-KPX oslash y -70
-KPX oslash x -85
-KPX oslash w -70
-KPX oslash v -70
-KPX oslash u -55
-KPX oslash t -55
-KPX oslash s -55
-KPX oslash r -55
-KPX oslash q -55
-KPX oslash period -95
-KPX oslash p -55
-KPX oslash o -55
-KPX oslash n -55
-KPX oslash m -55
-KPX oslash l -55
-KPX oslash k -55
-KPX oslash j -55
-KPX oslash i -55
-KPX oslash h -55
-KPX oslash g -55
-KPX oslash f -55
-KPX oslash e -55
-KPX oslash d -55
-KPX oslash comma -95
-KPX oslash c -55
-KPX oslash b -55
-KPX oslash a -55
-
-KPX p y -30
-KPX p period -35
-KPX p comma -35
-
-KPX period space -60
-KPX period quoteright -100
-KPX period quotedblright -100
-
-KPX quotedblright space -40
-
-KPX quoteleft quoteleft -57
-
-KPX quoteright space -70
-KPX quoteright s -50
-KPX quoteright r -50
-KPX quoteright quoteright -57
-KPX quoteright d -50
-
-KPX r y 30
-KPX r v 30
-KPX r u 15
-KPX r t 40
-KPX r semicolon 30
-KPX r period -50
-KPX r p 30
-KPX r n 25
-KPX r m 25
-KPX r l 15
-KPX r k 15
-KPX r i 15
-KPX r comma -50
-KPX r colon 30
-KPX r a -10
-
-KPX s w -30
-KPX s period -15
-KPX s comma -15
-
-KPX semicolon space -50
-
-KPX space quoteleft -60
-KPX space quotedblleft -30
-KPX space Y -90
-KPX space W -40
-KPX space V -50
-KPX space T -50
-
-KPX v period -80
-KPX v o -25
-KPX v e -25
-KPX v comma -80
-KPX v a -25
-
-KPX w period -60
-KPX w o -10
-KPX w e -10
-KPX w comma -60
-KPX w a -15
-
-KPX x e -30
-
-KPX y period -100
-KPX y o -20
-KPX y e -20
-KPX y comma -100
-KPX y a -20
-
-KPX z o -15
-KPX z e -15
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 208 195 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 208 195 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 208 195 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 208 195 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 204 175 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 208 195 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 195 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 208 195 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 208 195 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 208 195 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 208 195 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 14 195 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 14 195 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 14 195 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 14 195 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 246 195 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 264 195 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 264 195 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 264 195 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 264 195 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 264 195 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 208 195 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 236 195 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 236 195 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 236 195 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 236 195 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 208 195 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 208 195 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 180 195 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 102 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 84 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 102 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 112 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 112 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 112 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 112 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 112 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 84 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 112 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 112 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
-Comment Creation Date: Thu Mar 15 08:58:00 1990
-Comment UniqueID 28352
-Comment VMusage 26389 33281
-FontName Helvetica
-FullName Helvetica
-FamilyName Helvetica
-Weight Medium
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -166 -225 1000 931
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.006
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.Helvetica is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 718
-XHeight 523
-Ascender 718
-Descender -207
-StartCharMetrics 228
-C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ;
-C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ;
-C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ;
-C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ;
-C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ;
-C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ;
-C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
-C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ;
-C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ;
-C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ;
-C 43 ; WX 584 ; N plus ; B 39 0 545 505 ;
-C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ;
-C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ;
-C 46 ; WX 278 ; N period ; B 87 0 191 106 ;
-C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ;
-C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ;
-C 49 ; WX 556 ; N one ; B 101 0 359 703 ;
-C 50 ; WX 556 ; N two ; B 26 0 507 703 ;
-C 51 ; WX 556 ; N three ; B 34 -19 522 703 ;
-C 52 ; WX 556 ; N four ; B 25 0 523 703 ;
-C 53 ; WX 556 ; N five ; B 32 -19 514 688 ;
-C 54 ; WX 556 ; N six ; B 38 -19 518 703 ;
-C 55 ; WX 556 ; N seven ; B 37 0 523 688 ;
-C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ;
-C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ;
-C 58 ; WX 278 ; N colon ; B 87 0 191 516 ;
-C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ;
-C 60 ; WX 584 ; N less ; B 48 11 536 495 ;
-C 61 ; WX 584 ; N equal ; B 39 115 545 390 ;
-C 62 ; WX 584 ; N greater ; B 48 11 536 495 ;
-C 63 ; WX 556 ; N question ; B 56 0 492 727 ;
-C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ;
-C 65 ; WX 667 ; N A ; B 14 0 654 718 ;
-C 66 ; WX 667 ; N B ; B 74 0 627 718 ;
-C 67 ; WX 722 ; N C ; B 44 -19 681 737 ;
-C 68 ; WX 722 ; N D ; B 81 0 674 718 ;
-C 69 ; WX 667 ; N E ; B 86 0 616 718 ;
-C 70 ; WX 611 ; N F ; B 86 0 583 718 ;
-C 71 ; WX 778 ; N G ; B 48 -19 704 737 ;
-C 72 ; WX 722 ; N H ; B 77 0 646 718 ;
-C 73 ; WX 278 ; N I ; B 91 0 188 718 ;
-C 74 ; WX 500 ; N J ; B 17 -19 428 718 ;
-C 75 ; WX 667 ; N K ; B 76 0 663 718 ;
-C 76 ; WX 556 ; N L ; B 76 0 537 718 ;
-C 77 ; WX 833 ; N M ; B 73 0 761 718 ;
-C 78 ; WX 722 ; N N ; B 76 0 646 718 ;
-C 79 ; WX 778 ; N O ; B 39 -19 739 737 ;
-C 80 ; WX 667 ; N P ; B 86 0 622 718 ;
-C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ;
-C 82 ; WX 722 ; N R ; B 88 0 684 718 ;
-C 83 ; WX 667 ; N S ; B 49 -19 620 737 ;
-C 84 ; WX 611 ; N T ; B 14 0 597 718 ;
-C 85 ; WX 722 ; N U ; B 79 -19 644 718 ;
-C 86 ; WX 667 ; N V ; B 20 0 647 718 ;
-C 87 ; WX 944 ; N W ; B 16 0 928 718 ;
-C 88 ; WX 667 ; N X ; B 19 0 648 718 ;
-C 89 ; WX 667 ; N Y ; B 14 0 653 718 ;
-C 90 ; WX 611 ; N Z ; B 23 0 588 718 ;
-C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ;
-C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ;
-C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ;
-C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ;
-C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ;
-C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ;
-C 97 ; WX 556 ; N a ; B 36 -15 530 538 ;
-C 98 ; WX 556 ; N b ; B 58 -15 517 718 ;
-C 99 ; WX 500 ; N c ; B 30 -15 477 538 ;
-C 100 ; WX 556 ; N d ; B 35 -15 499 718 ;
-C 101 ; WX 556 ; N e ; B 40 -15 516 538 ;
-C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ;
-C 103 ; WX 556 ; N g ; B 40 -220 499 538 ;
-C 104 ; WX 556 ; N h ; B 65 0 491 718 ;
-C 105 ; WX 222 ; N i ; B 67 0 155 718 ;
-C 106 ; WX 222 ; N j ; B -16 -210 155 718 ;
-C 107 ; WX 500 ; N k ; B 67 0 501 718 ;
-C 108 ; WX 222 ; N l ; B 67 0 155 718 ;
-C 109 ; WX 833 ; N m ; B 65 0 769 538 ;
-C 110 ; WX 556 ; N n ; B 65 0 491 538 ;
-C 111 ; WX 556 ; N o ; B 35 -14 521 538 ;
-C 112 ; WX 556 ; N p ; B 58 -207 517 538 ;
-C 113 ; WX 556 ; N q ; B 35 -207 494 538 ;
-C 114 ; WX 333 ; N r ; B 77 0 332 538 ;
-C 115 ; WX 500 ; N s ; B 32 -15 464 538 ;
-C 116 ; WX 278 ; N t ; B 14 -7 257 669 ;
-C 117 ; WX 556 ; N u ; B 68 -15 489 523 ;
-C 118 ; WX 500 ; N v ; B 8 0 492 523 ;
-C 119 ; WX 722 ; N w ; B 14 0 709 523 ;
-C 120 ; WX 500 ; N x ; B 11 0 490 523 ;
-C 121 ; WX 500 ; N y ; B 11 -214 489 523 ;
-C 122 ; WX 500 ; N z ; B 31 0 469 523 ;
-C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ;
-C 124 ; WX 260 ; N bar ; B 94 -19 167 737 ;
-C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ;
-C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ;
-C 161 ; WX 333 ; N exclamdown ; B 118 -195 215 523 ;
-C 162 ; WX 556 ; N cent ; B 51 -115 513 623 ;
-C 163 ; WX 556 ; N sterling ; B 33 -16 539 718 ;
-C 164 ; WX 167 ; N fraction ; B -166 -19 333 703 ;
-C 165 ; WX 556 ; N yen ; B 3 0 553 688 ;
-C 166 ; WX 556 ; N florin ; B -11 -207 501 737 ;
-C 167 ; WX 556 ; N section ; B 43 -191 512 737 ;
-C 168 ; WX 556 ; N currency ; B 28 99 528 603 ;
-C 169 ; WX 191 ; N quotesingle ; B 59 463 132 718 ;
-C 170 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ;
-C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ;
-C 173 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ;
-C 174 ; WX 500 ; N fi ; B 14 0 434 728 ;
-C 175 ; WX 500 ; N fl ; B 14 0 432 728 ;
-C 177 ; WX 556 ; N endash ; B 0 240 556 313 ;
-C 178 ; WX 556 ; N dagger ; B 43 -159 514 718 ;
-C 179 ; WX 556 ; N daggerdbl ; B 43 -159 514 718 ;
-C 180 ; WX 278 ; N periodcentered ; B 77 190 202 315 ;
-C 182 ; WX 537 ; N paragraph ; B 18 -173 497 718 ;
-C 183 ; WX 350 ; N bullet ; B 18 202 333 517 ;
-C 184 ; WX 222 ; N quotesinglbase ; B 53 -149 157 106 ;
-C 185 ; WX 333 ; N quotedblbase ; B 26 -149 295 106 ;
-C 186 ; WX 333 ; N quotedblright ; B 26 463 295 718 ;
-C 187 ; WX 556 ; N guillemotright ; B 97 108 459 446 ;
-C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 106 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 703 ;
-C 191 ; WX 611 ; N questiondown ; B 91 -201 527 525 ;
-C 193 ; WX 333 ; N grave ; B 14 593 211 734 ;
-C 194 ; WX 333 ; N acute ; B 122 593 319 734 ;
-C 195 ; WX 333 ; N circumflex ; B 21 593 312 734 ;
-C 196 ; WX 333 ; N tilde ; B -4 606 337 722 ;
-C 197 ; WX 333 ; N macron ; B 10 627 323 684 ;
-C 198 ; WX 333 ; N breve ; B 13 595 321 731 ;
-C 199 ; WX 333 ; N dotaccent ; B 121 604 212 706 ;
-C 200 ; WX 333 ; N dieresis ; B 40 604 293 706 ;
-C 202 ; WX 333 ; N ring ; B 75 572 259 756 ;
-C 203 ; WX 333 ; N cedilla ; B 45 -225 259 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 31 593 409 734 ;
-C 206 ; WX 333 ; N ogonek ; B 73 -225 287 0 ;
-C 207 ; WX 333 ; N caron ; B 21 593 312 734 ;
-C 208 ; WX 1000 ; N emdash ; B 0 240 1000 313 ;
-C 225 ; WX 1000 ; N AE ; B 8 0 951 718 ;
-C 227 ; WX 370 ; N ordfeminine ; B 24 304 346 737 ;
-C 232 ; WX 556 ; N Lslash ; B -20 0 537 718 ;
-C 233 ; WX 778 ; N Oslash ; B 39 -19 740 737 ;
-C 234 ; WX 1000 ; N OE ; B 36 -19 965 737 ;
-C 235 ; WX 365 ; N ordmasculine ; B 25 304 341 737 ;
-C 241 ; WX 889 ; N ae ; B 36 -15 847 538 ;
-C 245 ; WX 278 ; N dotlessi ; B 95 0 183 523 ;
-C 248 ; WX 222 ; N lslash ; B -20 0 242 718 ;
-C 249 ; WX 611 ; N oslash ; B 28 -22 537 545 ;
-C 250 ; WX 944 ; N oe ; B 35 -15 902 538 ;
-C 251 ; WX 611 ; N germandbls ; B 67 -15 571 728 ;
-C -1 ; WX 611 ; N Zcaron ; B 23 0 588 929 ;
-C -1 ; WX 500 ; N ccedilla ; B 30 -225 477 538 ;
-C -1 ; WX 500 ; N ydieresis ; B 11 -214 489 706 ;
-C -1 ; WX 556 ; N atilde ; B 36 -15 530 722 ;
-C -1 ; WX 278 ; N icircumflex ; B -6 0 285 734 ;
-C -1 ; WX 333 ; N threesuperior ; B 5 270 325 703 ;
-C -1 ; WX 556 ; N ecircumflex ; B 40 -15 516 734 ;
-C -1 ; WX 556 ; N thorn ; B 58 -207 517 718 ;
-C -1 ; WX 556 ; N egrave ; B 40 -15 516 734 ;
-C -1 ; WX 333 ; N twosuperior ; B 4 281 323 703 ;
-C -1 ; WX 556 ; N eacute ; B 40 -15 516 734 ;
-C -1 ; WX 556 ; N otilde ; B 35 -14 521 722 ;
-C -1 ; WX 667 ; N Aacute ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N ocircumflex ; B 35 -14 521 734 ;
-C -1 ; WX 500 ; N yacute ; B 11 -214 489 734 ;
-C -1 ; WX 556 ; N udieresis ; B 68 -15 489 706 ;
-C -1 ; WX 834 ; N threequarters ; B 45 -19 810 703 ;
-C -1 ; WX 556 ; N acircumflex ; B 36 -15 530 734 ;
-C -1 ; WX 722 ; N Eth ; B 0 0 674 718 ;
-C -1 ; WX 556 ; N edieresis ; B 40 -15 516 706 ;
-C -1 ; WX 556 ; N ugrave ; B 68 -15 489 734 ;
-C -1 ; WX 1000 ; N trademark ; B 46 306 903 718 ;
-C -1 ; WX 556 ; N ograve ; B 35 -14 521 734 ;
-C -1 ; WX 500 ; N scaron ; B 32 -15 464 734 ;
-C -1 ; WX 278 ; N Idieresis ; B 13 0 266 901 ;
-C -1 ; WX 556 ; N uacute ; B 68 -15 489 734 ;
-C -1 ; WX 556 ; N agrave ; B 36 -15 530 734 ;
-C -1 ; WX 556 ; N ntilde ; B 65 0 491 722 ;
-C -1 ; WX 556 ; N aring ; B 36 -15 530 756 ;
-C -1 ; WX 500 ; N zcaron ; B 31 0 469 734 ;
-C -1 ; WX 278 ; N Icircumflex ; B -6 0 285 929 ;
-C -1 ; WX 722 ; N Ntilde ; B 76 0 646 917 ;
-C -1 ; WX 556 ; N ucircumflex ; B 68 -15 489 734 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 86 0 616 929 ;
-C -1 ; WX 278 ; N Iacute ; B 91 0 292 929 ;
-C -1 ; WX 722 ; N Ccedilla ; B 44 -225 681 737 ;
-C -1 ; WX 778 ; N Odieresis ; B 39 -19 739 901 ;
-C -1 ; WX 667 ; N Scaron ; B 49 -19 620 929 ;
-C -1 ; WX 667 ; N Edieresis ; B 86 0 616 901 ;
-C -1 ; WX 278 ; N Igrave ; B -13 0 188 929 ;
-C -1 ; WX 556 ; N adieresis ; B 36 -15 530 706 ;
-C -1 ; WX 778 ; N Ograve ; B 39 -19 739 929 ;
-C -1 ; WX 667 ; N Egrave ; B 86 0 616 929 ;
-C -1 ; WX 667 ; N Ydieresis ; B 14 0 653 901 ;
-C -1 ; WX 737 ; N registered ; B -14 -19 752 737 ;
-C -1 ; WX 778 ; N Otilde ; B 39 -19 739 917 ;
-C -1 ; WX 834 ; N onequarter ; B 73 -19 756 703 ;
-C -1 ; WX 722 ; N Ugrave ; B 79 -19 644 929 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 79 -19 644 929 ;
-C -1 ; WX 667 ; N Thorn ; B 86 0 622 718 ;
-C -1 ; WX 584 ; N divide ; B 39 -19 545 524 ;
-C -1 ; WX 667 ; N Atilde ; B 14 0 654 917 ;
-C -1 ; WX 722 ; N Uacute ; B 79 -19 644 929 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 39 -19 739 929 ;
-C -1 ; WX 584 ; N logicalnot ; B 39 108 545 390 ;
-C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ;
-C -1 ; WX 278 ; N idieresis ; B 13 0 266 706 ;
-C -1 ; WX 278 ; N iacute ; B 95 0 292 734 ;
-C -1 ; WX 556 ; N aacute ; B 36 -15 530 734 ;
-C -1 ; WX 584 ; N plusminus ; B 39 0 545 506 ;
-C -1 ; WX 584 ; N multiply ; B 39 0 545 506 ;
-C -1 ; WX 722 ; N Udieresis ; B 79 -19 644 901 ;
-C -1 ; WX 584 ; N minus ; B 39 216 545 289 ;
-C -1 ; WX 333 ; N onesuperior ; B 43 281 222 703 ;
-C -1 ; WX 667 ; N Eacute ; B 86 0 616 929 ;
-C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ;
-C -1 ; WX 737 ; N copyright ; B -14 -19 752 737 ;
-C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ;
-C -1 ; WX 556 ; N odieresis ; B 35 -14 521 706 ;
-C -1 ; WX 556 ; N oacute ; B 35 -14 521 734 ;
-C -1 ; WX 400 ; N degree ; B 54 411 346 703 ;
-C -1 ; WX 278 ; N igrave ; B -13 0 184 734 ;
-C -1 ; WX 556 ; N mu ; B 68 -207 489 523 ;
-C -1 ; WX 778 ; N Oacute ; B 39 -19 739 929 ;
-C -1 ; WX 556 ; N eth ; B 35 -15 522 737 ;
-C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ;
-C -1 ; WX 667 ; N Yacute ; B 14 0 653 929 ;
-C -1 ; WX 260 ; N brokenbar ; B 94 -19 167 737 ;
-C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 250
-
-KPX A y -40
-KPX A w -40
-KPX A v -40
-KPX A u -30
-KPX A Y -100
-KPX A W -50
-KPX A V -70
-KPX A U -50
-KPX A T -120
-KPX A Q -30
-KPX A O -30
-KPX A G -30
-KPX A C -30
-
-KPX B period -20
-KPX B comma -20
-KPX B U -10
-
-KPX C period -30
-KPX C comma -30
-
-KPX D period -70
-KPX D comma -70
-KPX D Y -90
-KPX D W -40
-KPX D V -70
-KPX D A -40
-
-KPX F r -45
-KPX F period -150
-KPX F o -30
-KPX F e -30
-KPX F comma -150
-KPX F a -50
-KPX F A -80
-
-KPX J u -20
-KPX J period -30
-KPX J comma -30
-KPX J a -20
-KPX J A -20
-
-KPX K y -50
-KPX K u -30
-KPX K o -40
-KPX K e -40
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -160
-KPX L quotedblright -140
-KPX L Y -140
-KPX L W -70
-KPX L V -110
-KPX L T -110
-
-KPX O period -40
-KPX O comma -40
-KPX O Y -70
-KPX O X -60
-KPX O W -30
-KPX O V -50
-KPX O T -40
-KPX O A -20
-
-KPX P period -180
-KPX P o -50
-KPX P e -50
-KPX P comma -180
-KPX P a -40
-KPX P A -120
-
-KPX Q U -10
-
-KPX R Y -50
-KPX R W -30
-KPX R V -50
-KPX R U -40
-KPX R T -30
-KPX R O -20
-
-KPX S period -20
-KPX S comma -20
-
-KPX T y -120
-KPX T w -120
-KPX T u -120
-KPX T semicolon -20
-KPX T r -120
-KPX T period -120
-KPX T o -120
-KPX T hyphen -140
-KPX T e -120
-KPX T comma -120
-KPX T colon -20
-KPX T a -120
-KPX T O -40
-KPX T A -120
-
-KPX U period -40
-KPX U comma -40
-KPX U A -40
-
-KPX V u -70
-KPX V semicolon -40
-KPX V period -125
-KPX V o -80
-KPX V hyphen -80
-KPX V e -80
-KPX V comma -125
-KPX V colon -40
-KPX V a -70
-KPX V O -40
-KPX V G -40
-KPX V A -80
-
-KPX W y -20
-KPX W u -30
-KPX W period -80
-KPX W o -30
-KPX W hyphen -40
-KPX W e -30
-KPX W comma -80
-KPX W a -40
-KPX W O -20
-KPX W A -50
-
-KPX Y u -110
-KPX Y semicolon -60
-KPX Y period -140
-KPX Y o -140
-KPX Y i -20
-KPX Y hyphen -140
-KPX Y e -140
-KPX Y comma -140
-KPX Y colon -60
-KPX Y a -140
-KPX Y O -85
-KPX Y A -110
-
-KPX a y -30
-KPX a w -20
-KPX a v -20
-
-KPX b y -20
-KPX b v -20
-KPX b u -20
-KPX b period -40
-KPX b l -20
-KPX b comma -40
-KPX b b -10
-
-KPX c k -20
-KPX c comma -15
-
-KPX colon space -50
-
-KPX comma quoteright -100
-KPX comma quotedblright -100
-
-KPX e y -20
-KPX e x -30
-KPX e w -20
-KPX e v -30
-KPX e period -15
-KPX e comma -15
-
-KPX f quoteright 50
-KPX f quotedblright 60
-KPX f period -30
-KPX f o -30
-KPX f e -30
-KPX f dotlessi -28
-KPX f comma -30
-KPX f a -30
-
-KPX g r -10
-
-KPX h y -30
-
-KPX k o -20
-KPX k e -20
-
-KPX m y -15
-KPX m u -10
-
-KPX n y -15
-KPX n v -20
-KPX n u -10
-
-KPX o y -30
-KPX o x -30
-KPX o w -15
-KPX o v -15
-KPX o period -40
-KPX o comma -40
-
-KPX oslash z -55
-KPX oslash y -70
-KPX oslash x -85
-KPX oslash w -70
-KPX oslash v -70
-KPX oslash u -55
-KPX oslash t -55
-KPX oslash s -55
-KPX oslash r -55
-KPX oslash q -55
-KPX oslash period -95
-KPX oslash p -55
-KPX oslash o -55
-KPX oslash n -55
-KPX oslash m -55
-KPX oslash l -55
-KPX oslash k -55
-KPX oslash j -55
-KPX oslash i -55
-KPX oslash h -55
-KPX oslash g -55
-KPX oslash f -55
-KPX oslash e -55
-KPX oslash d -55
-KPX oslash comma -95
-KPX oslash c -55
-KPX oslash b -55
-KPX oslash a -55
-
-KPX p y -30
-KPX p period -35
-KPX p comma -35
-
-KPX period space -60
-KPX period quoteright -100
-KPX period quotedblright -100
-
-KPX quotedblright space -40
-
-KPX quoteleft quoteleft -57
-
-KPX quoteright space -70
-KPX quoteright s -50
-KPX quoteright r -50
-KPX quoteright quoteright -57
-KPX quoteright d -50
-
-KPX r y 30
-KPX r v 30
-KPX r u 15
-KPX r t 40
-KPX r semicolon 30
-KPX r period -50
-KPX r p 30
-KPX r n 25
-KPX r m 25
-KPX r l 15
-KPX r k 15
-KPX r i 15
-KPX r comma -50
-KPX r colon 30
-KPX r a -10
-
-KPX s w -30
-KPX s period -15
-KPX s comma -15
-
-KPX semicolon space -50
-
-KPX space quoteleft -60
-KPX space quotedblleft -30
-KPX space Y -90
-KPX space W -40
-KPX space V -50
-KPX space T -50
-
-KPX v period -80
-KPX v o -25
-KPX v e -25
-KPX v comma -80
-KPX v a -25
-
-KPX w period -60
-KPX w o -10
-KPX w e -10
-KPX w comma -60
-KPX w a -15
-
-KPX x e -30
-
-KPX y period -100
-KPX y o -20
-KPX y e -20
-KPX y comma -100
-KPX y a -20
-
-KPX z o -15
-KPX z e -15
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 167 195 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 167 195 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 167 195 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 167 195 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 167 175 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 167 195 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 195 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 167 195 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 167 195 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 167 195 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 167 195 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute -27 195 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex -27 195 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis -27 195 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave -27 195 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 205 195 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 195 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 195 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 195 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 195 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 195 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 167 195 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 195 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 195 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 195 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 195 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 167 195 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 167 195 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 195 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 112 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 112 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 112 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 112 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 112 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 102 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 84 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 112 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 112 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 112 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 112 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 102 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 112 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 112 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 112 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 112 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 112 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 84 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 112 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 112 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 84 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Tue Mar 20 12:17:14 1990
-Comment UniqueID 28417
-Comment VMusage 30458 37350
-FontName Times-Bold
-FullName Times Bold
-FamilyName Times
-Weight Bold
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -168 -218 1000 935
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 676
-XHeight 461
-Ascender 676
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 81 -13 251 691 ;
-C 34 ; WX 555 ; N quotedbl ; B 83 404 472 691 ;
-C 35 ; WX 500 ; N numbersign ; B 4 0 496 700 ;
-C 36 ; WX 500 ; N dollar ; B 29 -99 472 750 ;
-C 37 ; WX 1000 ; N percent ; B 124 -14 877 692 ;
-C 38 ; WX 833 ; N ampersand ; B 62 -16 787 691 ;
-C 39 ; WX 333 ; N quoteright ; B 79 356 263 691 ;
-C 40 ; WX 333 ; N parenleft ; B 46 -168 306 694 ;
-C 41 ; WX 333 ; N parenright ; B 27 -168 287 694 ;
-C 42 ; WX 500 ; N asterisk ; B 56 255 447 691 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B 39 -180 223 155 ;
-C 45 ; WX 333 ; N hyphen ; B 44 171 287 287 ;
-C 46 ; WX 250 ; N period ; B 41 -13 210 156 ;
-C 47 ; WX 278 ; N slash ; B -24 -19 302 691 ;
-C 48 ; WX 500 ; N zero ; B 24 -13 476 688 ;
-C 49 ; WX 500 ; N one ; B 65 0 442 688 ;
-C 50 ; WX 500 ; N two ; B 17 0 478 688 ;
-C 51 ; WX 500 ; N three ; B 16 -14 468 688 ;
-C 52 ; WX 500 ; N four ; B 19 0 475 688 ;
-C 53 ; WX 500 ; N five ; B 22 -8 470 676 ;
-C 54 ; WX 500 ; N six ; B 28 -13 475 688 ;
-C 55 ; WX 500 ; N seven ; B 17 0 477 676 ;
-C 56 ; WX 500 ; N eight ; B 28 -13 472 688 ;
-C 57 ; WX 500 ; N nine ; B 26 -13 473 688 ;
-C 58 ; WX 333 ; N colon ; B 82 -13 251 472 ;
-C 59 ; WX 333 ; N semicolon ; B 82 -180 266 472 ;
-C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
-C 63 ; WX 500 ; N question ; B 57 -13 445 689 ;
-C 64 ; WX 930 ; N at ; B 108 -19 822 691 ;
-C 65 ; WX 722 ; N A ; B 9 0 689 690 ;
-C 66 ; WX 667 ; N B ; B 16 0 619 676 ;
-C 67 ; WX 722 ; N C ; B 49 -19 687 691 ;
-C 68 ; WX 722 ; N D ; B 14 0 690 676 ;
-C 69 ; WX 667 ; N E ; B 16 0 641 676 ;
-C 70 ; WX 611 ; N F ; B 16 0 583 676 ;
-C 71 ; WX 778 ; N G ; B 37 -19 755 691 ;
-C 72 ; WX 778 ; N H ; B 21 0 759 676 ;
-C 73 ; WX 389 ; N I ; B 20 0 370 676 ;
-C 74 ; WX 500 ; N J ; B 3 -96 479 676 ;
-C 75 ; WX 778 ; N K ; B 30 0 769 676 ;
-C 76 ; WX 667 ; N L ; B 19 0 638 676 ;
-C 77 ; WX 944 ; N M ; B 14 0 921 676 ;
-C 78 ; WX 722 ; N N ; B 16 -18 701 676 ;
-C 79 ; WX 778 ; N O ; B 35 -19 743 691 ;
-C 80 ; WX 611 ; N P ; B 16 0 600 676 ;
-C 81 ; WX 778 ; N Q ; B 35 -176 743 691 ;
-C 82 ; WX 722 ; N R ; B 26 0 715 676 ;
-C 83 ; WX 556 ; N S ; B 35 -19 513 692 ;
-C 84 ; WX 667 ; N T ; B 31 0 636 676 ;
-C 85 ; WX 722 ; N U ; B 16 -19 701 676 ;
-C 86 ; WX 722 ; N V ; B 16 -18 701 676 ;
-C 87 ; WX 1000 ; N W ; B 19 -15 981 676 ;
-C 88 ; WX 722 ; N X ; B 16 0 699 676 ;
-C 89 ; WX 722 ; N Y ; B 15 0 699 676 ;
-C 90 ; WX 667 ; N Z ; B 28 0 634 676 ;
-C 91 ; WX 333 ; N bracketleft ; B 67 -149 301 678 ;
-C 92 ; WX 278 ; N backslash ; B -25 -19 303 691 ;
-C 93 ; WX 333 ; N bracketright ; B 32 -149 266 678 ;
-C 94 ; WX 581 ; N asciicircum ; B 73 311 509 676 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 70 356 254 691 ;
-C 97 ; WX 500 ; N a ; B 25 -14 488 473 ;
-C 98 ; WX 556 ; N b ; B 17 -14 521 676 ;
-C 99 ; WX 444 ; N c ; B 25 -14 430 473 ;
-C 100 ; WX 556 ; N d ; B 25 -14 534 676 ;
-C 101 ; WX 444 ; N e ; B 25 -14 426 473 ;
-C 102 ; WX 333 ; N f ; B 14 0 389 691 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 28 -206 483 473 ;
-C 104 ; WX 556 ; N h ; B 16 0 534 676 ;
-C 105 ; WX 278 ; N i ; B 16 0 255 691 ;
-C 106 ; WX 333 ; N j ; B -57 -203 263 691 ;
-C 107 ; WX 556 ; N k ; B 22 0 543 676 ;
-C 108 ; WX 278 ; N l ; B 16 0 255 676 ;
-C 109 ; WX 833 ; N m ; B 16 0 814 473 ;
-C 110 ; WX 556 ; N n ; B 21 0 539 473 ;
-C 111 ; WX 500 ; N o ; B 25 -14 476 473 ;
-C 112 ; WX 556 ; N p ; B 19 -205 524 473 ;
-C 113 ; WX 556 ; N q ; B 34 -205 536 473 ;
-C 114 ; WX 444 ; N r ; B 29 0 434 473 ;
-C 115 ; WX 389 ; N s ; B 25 -14 361 473 ;
-C 116 ; WX 333 ; N t ; B 20 -12 332 630 ;
-C 117 ; WX 556 ; N u ; B 16 -14 537 461 ;
-C 118 ; WX 500 ; N v ; B 21 -14 485 461 ;
-C 119 ; WX 722 ; N w ; B 23 -14 707 461 ;
-C 120 ; WX 500 ; N x ; B 12 0 484 461 ;
-C 121 ; WX 500 ; N y ; B 16 -205 480 461 ;
-C 122 ; WX 444 ; N z ; B 21 0 420 461 ;
-C 123 ; WX 394 ; N braceleft ; B 22 -175 340 698 ;
-C 124 ; WX 220 ; N bar ; B 66 -19 154 691 ;
-C 125 ; WX 394 ; N braceright ; B 54 -175 372 698 ;
-C 126 ; WX 520 ; N asciitilde ; B 29 173 491 333 ;
-C 161 ; WX 333 ; N exclamdown ; B 82 -203 252 501 ;
-C 162 ; WX 500 ; N cent ; B 53 -140 458 588 ;
-C 163 ; WX 500 ; N sterling ; B 21 -14 477 684 ;
-C 164 ; WX 167 ; N fraction ; B -168 -12 329 688 ;
-C 165 ; WX 500 ; N yen ; B -64 0 547 676 ;
-C 166 ; WX 500 ; N florin ; B 0 -155 498 706 ;
-C 167 ; WX 500 ; N section ; B 57 -132 443 691 ;
-C 168 ; WX 500 ; N currency ; B -26 61 526 613 ;
-C 169 ; WX 278 ; N quotesingle ; B 75 404 204 691 ;
-C 170 ; WX 500 ; N quotedblleft ; B 32 356 486 691 ;
-C 171 ; WX 500 ; N guillemotleft ; B 23 36 473 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 36 305 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 28 36 282 415 ;
-C 174 ; WX 556 ; N fi ; B 14 0 536 691 ;
-C 175 ; WX 556 ; N fl ; B 14 0 536 691 ;
-C 177 ; WX 500 ; N endash ; B 0 181 500 271 ;
-C 178 ; WX 500 ; N dagger ; B 47 -134 453 691 ;
-C 179 ; WX 500 ; N daggerdbl ; B 45 -132 456 691 ;
-C 180 ; WX 250 ; N periodcentered ; B 41 248 210 417 ;
-C 182 ; WX 540 ; N paragraph ; B 0 -186 519 676 ;
-C 183 ; WX 350 ; N bullet ; B 35 198 315 478 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -180 263 155 ;
-C 185 ; WX 500 ; N quotedblbase ; B 14 -180 468 155 ;
-C 186 ; WX 500 ; N quotedblright ; B 14 356 468 691 ;
-C 187 ; WX 500 ; N guillemotright ; B 27 36 477 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 82 -13 917 156 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 995 706 ;
-C 191 ; WX 500 ; N questiondown ; B 55 -201 443 501 ;
-C 193 ; WX 333 ; N grave ; B 8 528 246 713 ;
-C 194 ; WX 333 ; N acute ; B 86 528 324 713 ;
-C 195 ; WX 333 ; N circumflex ; B -2 528 335 704 ;
-C 196 ; WX 333 ; N tilde ; B -16 547 349 674 ;
-C 197 ; WX 333 ; N macron ; B 1 565 331 637 ;
-C 198 ; WX 333 ; N breve ; B 15 528 318 691 ;
-C 199 ; WX 333 ; N dotaccent ; B 103 537 230 667 ;
-C 200 ; WX 333 ; N dieresis ; B -2 537 335 667 ;
-C 202 ; WX 333 ; N ring ; B 60 527 273 740 ;
-C 203 ; WX 333 ; N cedilla ; B 68 -218 294 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -13 528 425 713 ;
-C 206 ; WX 333 ; N ogonek ; B 90 -173 319 44 ;
-C 207 ; WX 333 ; N caron ; B -2 528 335 704 ;
-C 208 ; WX 1000 ; N emdash ; B 0 181 1000 271 ;
-C 225 ; WX 1000 ; N AE ; B 4 0 951 676 ;
-C 227 ; WX 300 ; N ordfeminine ; B -1 397 301 688 ;
-C 232 ; WX 667 ; N Lslash ; B 19 0 638 676 ;
-C 233 ; WX 778 ; N Oslash ; B 35 -74 743 737 ;
-C 234 ; WX 1000 ; N OE ; B 22 -5 981 684 ;
-C 235 ; WX 330 ; N ordmasculine ; B 18 397 312 688 ;
-C 241 ; WX 722 ; N ae ; B 33 -14 693 473 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 255 461 ;
-C 248 ; WX 278 ; N lslash ; B -22 0 303 676 ;
-C 249 ; WX 500 ; N oslash ; B 25 -92 476 549 ;
-C 250 ; WX 722 ; N oe ; B 22 -14 696 473 ;
-C 251 ; WX 556 ; N germandbls ; B 19 -12 517 691 ;
-C -1 ; WX 667 ; N Zcaron ; B 28 0 634 914 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -218 430 473 ;
-C -1 ; WX 500 ; N ydieresis ; B 16 -205 480 667 ;
-C -1 ; WX 500 ; N atilde ; B 25 -14 488 674 ;
-C -1 ; WX 278 ; N icircumflex ; B -36 0 301 704 ;
-C -1 ; WX 300 ; N threesuperior ; B 3 268 297 688 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -14 426 704 ;
-C -1 ; WX 556 ; N thorn ; B 19 -205 524 676 ;
-C -1 ; WX 444 ; N egrave ; B 25 -14 426 713 ;
-C -1 ; WX 300 ; N twosuperior ; B 0 275 300 688 ;
-C -1 ; WX 444 ; N eacute ; B 25 -14 426 713 ;
-C -1 ; WX 500 ; N otilde ; B 25 -14 476 674 ;
-C -1 ; WX 722 ; N Aacute ; B 9 0 689 923 ;
-C -1 ; WX 500 ; N ocircumflex ; B 25 -14 476 704 ;
-C -1 ; WX 500 ; N yacute ; B 16 -205 480 713 ;
-C -1 ; WX 556 ; N udieresis ; B 16 -14 537 667 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -12 733 688 ;
-C -1 ; WX 500 ; N acircumflex ; B 25 -14 488 704 ;
-C -1 ; WX 722 ; N Eth ; B 6 0 690 676 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -14 426 667 ;
-C -1 ; WX 556 ; N ugrave ; B 16 -14 537 713 ;
-C -1 ; WX 1000 ; N trademark ; B 24 271 977 676 ;
-C -1 ; WX 500 ; N ograve ; B 25 -14 476 713 ;
-C -1 ; WX 389 ; N scaron ; B 25 -14 363 704 ;
-C -1 ; WX 389 ; N Idieresis ; B 20 0 370 877 ;
-C -1 ; WX 556 ; N uacute ; B 16 -14 537 713 ;
-C -1 ; WX 500 ; N agrave ; B 25 -14 488 713 ;
-C -1 ; WX 556 ; N ntilde ; B 21 0 539 674 ;
-C -1 ; WX 500 ; N aring ; B 25 -14 488 740 ;
-C -1 ; WX 444 ; N zcaron ; B 21 0 420 704 ;
-C -1 ; WX 389 ; N Icircumflex ; B 20 0 370 914 ;
-C -1 ; WX 722 ; N Ntilde ; B 16 -18 701 884 ;
-C -1 ; WX 556 ; N ucircumflex ; B 16 -14 537 704 ;
-C -1 ; WX 667 ; N Ecircumflex ; B 16 0 641 914 ;
-C -1 ; WX 389 ; N Iacute ; B 20 0 370 923 ;
-C -1 ; WX 722 ; N Ccedilla ; B 49 -218 687 691 ;
-C -1 ; WX 778 ; N Odieresis ; B 35 -19 743 877 ;
-C -1 ; WX 556 ; N Scaron ; B 35 -19 513 914 ;
-C -1 ; WX 667 ; N Edieresis ; B 16 0 641 877 ;
-C -1 ; WX 389 ; N Igrave ; B 20 0 370 923 ;
-C -1 ; WX 500 ; N adieresis ; B 25 -14 488 667 ;
-C -1 ; WX 778 ; N Ograve ; B 35 -19 743 923 ;
-C -1 ; WX 667 ; N Egrave ; B 16 0 641 923 ;
-C -1 ; WX 722 ; N Ydieresis ; B 15 0 699 877 ;
-C -1 ; WX 747 ; N registered ; B 26 -19 721 691 ;
-C -1 ; WX 778 ; N Otilde ; B 35 -19 743 884 ;
-C -1 ; WX 750 ; N onequarter ; B 28 -12 743 688 ;
-C -1 ; WX 722 ; N Ugrave ; B 16 -19 701 923 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 16 -19 701 914 ;
-C -1 ; WX 611 ; N Thorn ; B 16 0 600 676 ;
-C -1 ; WX 570 ; N divide ; B 33 -31 537 537 ;
-C -1 ; WX 722 ; N Atilde ; B 9 0 689 884 ;
-C -1 ; WX 722 ; N Uacute ; B 16 -19 701 923 ;
-C -1 ; WX 778 ; N Ocircumflex ; B 35 -19 743 914 ;
-C -1 ; WX 570 ; N logicalnot ; B 33 108 537 399 ;
-C -1 ; WX 722 ; N Aring ; B 9 0 689 935 ;
-C -1 ; WX 278 ; N idieresis ; B -36 0 301 667 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 713 ;
-C -1 ; WX 500 ; N aacute ; B 25 -14 488 713 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 722 ; N Udieresis ; B 16 -19 701 877 ;
-C -1 ; WX 570 ; N minus ; B 33 209 537 297 ;
-C -1 ; WX 300 ; N onesuperior ; B 28 275 273 688 ;
-C -1 ; WX 667 ; N Eacute ; B 16 0 641 923 ;
-C -1 ; WX 722 ; N Acircumflex ; B 9 0 689 914 ;
-C -1 ; WX 747 ; N copyright ; B 26 -19 721 691 ;
-C -1 ; WX 722 ; N Agrave ; B 9 0 689 923 ;
-C -1 ; WX 500 ; N odieresis ; B 25 -14 476 667 ;
-C -1 ; WX 500 ; N oacute ; B 25 -14 476 713 ;
-C -1 ; WX 400 ; N degree ; B 57 402 343 688 ;
-C -1 ; WX 278 ; N igrave ; B -26 0 255 713 ;
-C -1 ; WX 556 ; N mu ; B 33 -206 536 461 ;
-C -1 ; WX 778 ; N Oacute ; B 35 -19 743 923 ;
-C -1 ; WX 500 ; N eth ; B 25 -14 476 691 ;
-C -1 ; WX 722 ; N Adieresis ; B 9 0 689 877 ;
-C -1 ; WX 722 ; N Yacute ; B 15 0 699 928 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -19 154 691 ;
-C -1 ; WX 750 ; N onehalf ; B -7 -12 775 688 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -74
-KPX A w -90
-KPX A v -100
-KPX A u -50
-KPX A quoteright -74
-KPX A quotedblright 0
-KPX A p -25
-KPX A Y -100
-KPX A W -130
-KPX A V -145
-KPX A U -50
-KPX A T -95
-KPX A Q -45
-KPX A O -45
-KPX A G -55
-KPX A C -55
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -30
-
-KPX D period -20
-KPX D comma 0
-KPX D Y -40
-KPX D W -40
-KPX D V -40
-KPX D A -35
-
-KPX F r 0
-KPX F period -110
-KPX F o -25
-KPX F i 0
-KPX F e -25
-KPX F comma -92
-KPX F a -25
-KPX F A -90
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -15
-KPX J period -20
-KPX J o -15
-KPX J e -15
-KPX J comma 0
-KPX J a -15
-KPX J A -30
-
-KPX K y -45
-KPX K u -15
-KPX K o -25
-KPX K e -25
-KPX K O -30
-
-KPX L y -55
-KPX L quoteright -110
-KPX L quotedblright -20
-KPX L Y -92
-KPX L W -92
-KPX L V -92
-KPX L T -92
-
-KPX N period 0
-KPX N comma 0
-KPX N A -20
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -40
-
-KPX P period -110
-KPX P o -20
-KPX P e -20
-KPX P comma -92
-KPX P a -10
-KPX P A -74
-
-KPX Q period -20
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -35
-KPX R W -35
-KPX R V -55
-KPX R U -30
-KPX R T -40
-KPX R O -30
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -74
-KPX T w -74
-KPX T u -92
-KPX T semicolon -74
-KPX T r -74
-KPX T period -90
-KPX T o -92
-KPX T i -18
-KPX T hyphen -92
-KPX T h 0
-KPX T e -92
-KPX T comma -74
-KPX T colon -74
-KPX T a -92
-KPX T O -18
-KPX T A -90
-
-KPX U period -50
-KPX U comma -50
-KPX U A -60
-
-KPX V u -92
-KPX V semicolon -92
-KPX V period -145
-KPX V o -100
-KPX V i -37
-KPX V hyphen -74
-KPX V e -100
-KPX V comma -129
-KPX V colon -92
-KPX V a -92
-KPX V O -45
-KPX V G -30
-KPX V A -135
-
-KPX W y -60
-KPX W u -50
-KPX W semicolon -55
-KPX W period -92
-KPX W o -75
-KPX W i -18
-KPX W hyphen -37
-KPX W h 0
-KPX W e -65
-KPX W comma -92
-KPX W colon -55
-KPX W a -65
-KPX W O -10
-KPX W A -120
-
-KPX Y u -92
-KPX Y semicolon -92
-KPX Y period -92
-KPX Y o -111
-KPX Y i -37
-KPX Y hyphen -92
-KPX Y e -111
-KPX Y comma -92
-KPX Y colon -92
-KPX Y a -85
-KPX Y O -35
-KPX Y A -110
-
-KPX a y 0
-KPX a w 0
-KPX a v -25
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v -15
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b -10
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k 0
-KPX c h 0
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -55
-KPX comma quotedblright -45
-
-KPX d y 0
-KPX d w -15
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y 0
-KPX e x 0
-KPX e w 0
-KPX e v -15
-KPX e period 0
-KPX e p 0
-KPX e g 0
-KPX e comma 0
-KPX e b 0
-
-KPX f quoteright 55
-KPX f quotedblright 50
-KPX f period -15
-KPX f o -25
-KPX f l 0
-KPX f i -25
-KPX f f 0
-KPX f e 0
-KPX f dotlessi -35
-KPX f comma -15
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period -15
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a 0
-
-KPX h y -15
-
-KPX i v -10
-
-KPX k y -15
-KPX k o -15
-KPX k e -10
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y 0
-KPX o x 0
-KPX o w -10
-KPX o v -10
-KPX o g 0
-
-KPX p y 0
-
-KPX period quoteright -55
-KPX period quotedblright -55
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A -10
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -63
-KPX quoteleft A -10
-
-KPX quoteright v -20
-KPX quoteright t 0
-KPX quoteright space -74
-KPX quoteright s -37
-KPX quoteright r -20
-KPX quoteright quoteright -63
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -20
-
-KPX r y 0
-KPX r v -10
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q -18
-KPX r period -100
-KPX r p -10
-KPX r o -18
-KPX r n -15
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -37
-KPX r g -10
-KPX r e -18
-KPX r d 0
-KPX r comma -92
-KPX r c -18
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -55
-KPX space W -30
-KPX space V -45
-KPX space T -30
-KPX space A -55
-
-KPX v period -70
-KPX v o -10
-KPX v e -10
-KPX v comma -55
-KPX v a -10
-
-KPX w period -70
-KPX w o -10
-KPX w h 0
-KPX w e 0
-KPX w comma -55
-KPX w a 0
-
-KPX x e 0
-
-KPX y period -70
-KPX y o -25
-KPX y e -10
-KPX y comma -55
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 188 210 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 188 210 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 188 210 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 188 210 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 180 195 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 188 210 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 208 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 174 210 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 174 210 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 174 210 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 174 210 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 28 210 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 28 210 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 28 210 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 28 210 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 210 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 223 210 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 223 210 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 223 210 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 223 210 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 223 210 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 210 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 222 210 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 222 210 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 222 210 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 222 210 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 210 215 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 215 210 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 167 210 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 77 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 77 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 77 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 77 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 77 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 77 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 69 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 62 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 62 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 62 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 62 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -34 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -34 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -34 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -34 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 112 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 105 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 105 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 105 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 105 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 56 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Tue Mar 20 13:14:55 1990
-Comment UniqueID 28425
-Comment VMusage 32721 39613
-FontName Times-BoldItalic
-FullName Times Bold Italic
-FamilyName Times
-Weight Bold
-ItalicAngle -15
-IsFixedPitch false
-FontBBox -200 -218 996 921
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.009
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 669
-XHeight 462
-Ascender 699
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 389 ; N exclam ; B 67 -13 370 684 ;
-C 34 ; WX 555 ; N quotedbl ; B 136 398 536 685 ;
-C 35 ; WX 500 ; N numbersign ; B -33 0 533 700 ;
-C 36 ; WX 500 ; N dollar ; B -20 -100 497 733 ;
-C 37 ; WX 833 ; N percent ; B 39 -10 793 692 ;
-C 38 ; WX 778 ; N ampersand ; B 5 -19 699 682 ;
-C 39 ; WX 333 ; N quoteright ; B 98 369 302 685 ;
-C 40 ; WX 333 ; N parenleft ; B 28 -179 344 685 ;
-C 41 ; WX 333 ; N parenright ; B -44 -179 271 685 ;
-C 42 ; WX 500 ; N asterisk ; B 65 249 456 685 ;
-C 43 ; WX 570 ; N plus ; B 33 0 537 506 ;
-C 44 ; WX 250 ; N comma ; B -60 -182 144 134 ;
-C 45 ; WX 333 ; N hyphen ; B 2 166 271 282 ;
-C 46 ; WX 250 ; N period ; B -9 -13 139 135 ;
-C 47 ; WX 278 ; N slash ; B -64 -18 342 685 ;
-C 48 ; WX 500 ; N zero ; B 17 -14 477 683 ;
-C 49 ; WX 500 ; N one ; B 5 0 419 683 ;
-C 50 ; WX 500 ; N two ; B -27 0 446 683 ;
-C 51 ; WX 500 ; N three ; B -15 -13 450 683 ;
-C 52 ; WX 500 ; N four ; B -15 0 503 683 ;
-C 53 ; WX 500 ; N five ; B -11 -13 487 669 ;
-C 54 ; WX 500 ; N six ; B 23 -15 509 679 ;
-C 55 ; WX 500 ; N seven ; B 52 0 525 669 ;
-C 56 ; WX 500 ; N eight ; B 3 -13 476 683 ;
-C 57 ; WX 500 ; N nine ; B -12 -10 475 683 ;
-C 58 ; WX 333 ; N colon ; B 23 -13 264 459 ;
-C 59 ; WX 333 ; N semicolon ; B -25 -183 264 459 ;
-C 60 ; WX 570 ; N less ; B 31 -8 539 514 ;
-C 61 ; WX 570 ; N equal ; B 33 107 537 399 ;
-C 62 ; WX 570 ; N greater ; B 31 -8 539 514 ;
-C 63 ; WX 500 ; N question ; B 79 -13 470 684 ;
-C 64 ; WX 832 ; N at ; B 63 -18 770 685 ;
-C 65 ; WX 667 ; N A ; B -67 0 593 683 ;
-C 66 ; WX 667 ; N B ; B -24 0 624 669 ;
-C 67 ; WX 667 ; N C ; B 32 -18 677 685 ;
-C 68 ; WX 722 ; N D ; B -46 0 685 669 ;
-C 69 ; WX 667 ; N E ; B -27 0 653 669 ;
-C 70 ; WX 667 ; N F ; B -13 0 660 669 ;
-C 71 ; WX 722 ; N G ; B 21 -18 706 685 ;
-C 72 ; WX 778 ; N H ; B -24 0 799 669 ;
-C 73 ; WX 389 ; N I ; B -32 0 406 669 ;
-C 74 ; WX 500 ; N J ; B -46 -99 524 669 ;
-C 75 ; WX 667 ; N K ; B -21 0 702 669 ;
-C 76 ; WX 611 ; N L ; B -22 0 590 669 ;
-C 77 ; WX 889 ; N M ; B -29 -12 917 669 ;
-C 78 ; WX 722 ; N N ; B -27 -15 748 669 ;
-C 79 ; WX 722 ; N O ; B 27 -18 691 685 ;
-C 80 ; WX 611 ; N P ; B -27 0 613 669 ;
-C 81 ; WX 722 ; N Q ; B 27 -208 691 685 ;
-C 82 ; WX 667 ; N R ; B -29 0 623 669 ;
-C 83 ; WX 556 ; N S ; B 2 -18 526 685 ;
-C 84 ; WX 611 ; N T ; B 50 0 650 669 ;
-C 85 ; WX 722 ; N U ; B 67 -18 744 669 ;
-C 86 ; WX 667 ; N V ; B 65 -18 715 669 ;
-C 87 ; WX 889 ; N W ; B 65 -18 940 669 ;
-C 88 ; WX 667 ; N X ; B -24 0 694 669 ;
-C 89 ; WX 611 ; N Y ; B 73 0 659 669 ;
-C 90 ; WX 611 ; N Z ; B -11 0 590 669 ;
-C 91 ; WX 333 ; N bracketleft ; B -37 -159 362 674 ;
-C 92 ; WX 278 ; N backslash ; B -1 -18 279 685 ;
-C 93 ; WX 333 ; N bracketright ; B -56 -157 343 674 ;
-C 94 ; WX 570 ; N asciicircum ; B 67 304 503 669 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 128 369 332 685 ;
-C 97 ; WX 500 ; N a ; B -21 -14 455 462 ;
-C 98 ; WX 500 ; N b ; B -14 -13 444 699 ;
-C 99 ; WX 444 ; N c ; B -5 -13 392 462 ;
-C 100 ; WX 500 ; N d ; B -21 -13 517 699 ;
-C 101 ; WX 444 ; N e ; B 5 -13 398 462 ;
-C 102 ; WX 333 ; N f ; B -169 -205 446 698 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B -52 -203 478 462 ;
-C 104 ; WX 556 ; N h ; B -13 -9 498 699 ;
-C 105 ; WX 278 ; N i ; B 2 -9 263 684 ;
-C 106 ; WX 278 ; N j ; B -189 -207 279 684 ;
-C 107 ; WX 500 ; N k ; B -23 -8 483 699 ;
-C 108 ; WX 278 ; N l ; B 2 -9 290 699 ;
-C 109 ; WX 778 ; N m ; B -14 -9 722 462 ;
-C 110 ; WX 556 ; N n ; B -6 -9 493 462 ;
-C 111 ; WX 500 ; N o ; B -3 -13 441 462 ;
-C 112 ; WX 500 ; N p ; B -120 -205 446 462 ;
-C 113 ; WX 500 ; N q ; B 1 -205 471 462 ;
-C 114 ; WX 389 ; N r ; B -21 0 389 462 ;
-C 115 ; WX 389 ; N s ; B -19 -13 333 462 ;
-C 116 ; WX 278 ; N t ; B -11 -9 281 594 ;
-C 117 ; WX 556 ; N u ; B 15 -9 492 462 ;
-C 118 ; WX 444 ; N v ; B 16 -13 401 462 ;
-C 119 ; WX 667 ; N w ; B 16 -13 614 462 ;
-C 120 ; WX 500 ; N x ; B -46 -13 469 462 ;
-C 121 ; WX 444 ; N y ; B -94 -205 392 462 ;
-C 122 ; WX 389 ; N z ; B -43 -78 368 449 ;
-C 123 ; WX 348 ; N braceleft ; B 5 -187 436 686 ;
-C 124 ; WX 220 ; N bar ; B 66 -18 154 685 ;
-C 125 ; WX 348 ; N braceright ; B -129 -187 302 686 ;
-C 126 ; WX 570 ; N asciitilde ; B 54 173 516 333 ;
-C 161 ; WX 389 ; N exclamdown ; B 19 -205 322 492 ;
-C 162 ; WX 500 ; N cent ; B 42 -143 439 576 ;
-C 163 ; WX 500 ; N sterling ; B -32 -12 510 683 ;
-C 164 ; WX 167 ; N fraction ; B -169 -14 324 683 ;
-C 165 ; WX 500 ; N yen ; B 33 0 628 669 ;
-C 166 ; WX 500 ; N florin ; B -87 -156 537 707 ;
-C 167 ; WX 500 ; N section ; B 36 -143 459 685 ;
-C 168 ; WX 500 ; N currency ; B -26 34 526 586 ;
-C 169 ; WX 278 ; N quotesingle ; B 128 398 268 685 ;
-C 170 ; WX 500 ; N quotedblleft ; B 53 369 513 685 ;
-C 171 ; WX 500 ; N guillemotleft ; B 12 32 468 415 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 32 32 303 415 ;
-C 173 ; WX 333 ; N guilsinglright ; B 10 32 281 415 ;
-C 174 ; WX 556 ; N fi ; B -188 -205 514 703 ;
-C 175 ; WX 556 ; N fl ; B -186 -205 553 704 ;
-C 177 ; WX 500 ; N endash ; B -40 178 477 269 ;
-C 178 ; WX 500 ; N dagger ; B 91 -145 494 685 ;
-C 179 ; WX 500 ; N daggerdbl ; B 10 -139 493 685 ;
-C 180 ; WX 250 ; N periodcentered ; B 51 257 199 405 ;
-C 182 ; WX 500 ; N paragraph ; B -57 -193 562 669 ;
-C 183 ; WX 350 ; N bullet ; B 0 175 350 525 ;
-C 184 ; WX 333 ; N quotesinglbase ; B -5 -182 199 134 ;
-C 185 ; WX 500 ; N quotedblbase ; B -57 -182 403 134 ;
-C 186 ; WX 500 ; N quotedblright ; B 53 369 513 685 ;
-C 187 ; WX 500 ; N guillemotright ; B 12 32 468 415 ;
-C 188 ; WX 1000 ; N ellipsis ; B 40 -13 852 135 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -29 996 706 ;
-C 191 ; WX 500 ; N questiondown ; B 30 -205 421 492 ;
-C 193 ; WX 333 ; N grave ; B 85 516 297 697 ;
-C 194 ; WX 333 ; N acute ; B 139 516 379 697 ;
-C 195 ; WX 333 ; N circumflex ; B 40 516 367 690 ;
-C 196 ; WX 333 ; N tilde ; B 48 536 407 655 ;
-C 197 ; WX 333 ; N macron ; B 51 553 393 623 ;
-C 198 ; WX 333 ; N breve ; B 71 516 387 678 ;
-C 199 ; WX 333 ; N dotaccent ; B 163 525 293 655 ;
-C 200 ; WX 333 ; N dieresis ; B 55 525 397 655 ;
-C 202 ; WX 333 ; N ring ; B 127 516 340 729 ;
-C 203 ; WX 333 ; N cedilla ; B -80 -218 156 5 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 69 516 498 697 ;
-C 206 ; WX 333 ; N ogonek ; B -40 -173 189 44 ;
-C 207 ; WX 333 ; N caron ; B 79 516 411 690 ;
-C 208 ; WX 1000 ; N emdash ; B -40 178 977 269 ;
-C 225 ; WX 944 ; N AE ; B -64 0 918 669 ;
-C 227 ; WX 266 ; N ordfeminine ; B 16 399 330 685 ;
-C 232 ; WX 611 ; N Lslash ; B -22 0 590 669 ;
-C 233 ; WX 722 ; N Oslash ; B 27 -125 691 764 ;
-C 234 ; WX 944 ; N OE ; B 23 -8 946 677 ;
-C 235 ; WX 300 ; N ordmasculine ; B 56 400 347 685 ;
-C 241 ; WX 722 ; N ae ; B -5 -13 673 462 ;
-C 245 ; WX 278 ; N dotlessi ; B 2 -9 238 462 ;
-C 248 ; WX 278 ; N lslash ; B -13 -9 301 699 ;
-C 249 ; WX 500 ; N oslash ; B -3 -119 441 560 ;
-C 250 ; WX 722 ; N oe ; B 6 -13 674 462 ;
-C 251 ; WX 500 ; N germandbls ; B -200 -200 473 705 ;
-C -1 ; WX 611 ; N Zcaron ; B -11 0 590 897 ;
-C -1 ; WX 444 ; N ccedilla ; B -24 -218 392 462 ;
-C -1 ; WX 444 ; N ydieresis ; B -94 -205 438 655 ;
-C -1 ; WX 500 ; N atilde ; B -21 -14 491 655 ;
-C -1 ; WX 278 ; N icircumflex ; B -2 -9 325 690 ;
-C -1 ; WX 300 ; N threesuperior ; B 17 265 321 683 ;
-C -1 ; WX 444 ; N ecircumflex ; B 5 -13 423 690 ;
-C -1 ; WX 500 ; N thorn ; B -120 -205 446 699 ;
-C -1 ; WX 444 ; N egrave ; B 5 -13 398 697 ;
-C -1 ; WX 300 ; N twosuperior ; B 2 274 313 683 ;
-C -1 ; WX 444 ; N eacute ; B 5 -13 435 697 ;
-C -1 ; WX 500 ; N otilde ; B -3 -13 491 655 ;
-C -1 ; WX 667 ; N Aacute ; B -67 0 593 904 ;
-C -1 ; WX 500 ; N ocircumflex ; B -3 -13 451 690 ;
-C -1 ; WX 444 ; N yacute ; B -94 -205 435 697 ;
-C -1 ; WX 556 ; N udieresis ; B 15 -9 494 655 ;
-C -1 ; WX 750 ; N threequarters ; B 7 -14 726 683 ;
-C -1 ; WX 500 ; N acircumflex ; B -21 -14 455 690 ;
-C -1 ; WX 722 ; N Eth ; B -31 0 700 669 ;
-C -1 ; WX 444 ; N edieresis ; B 5 -13 443 655 ;
-C -1 ; WX 556 ; N ugrave ; B 15 -9 492 697 ;
-C -1 ; WX 1000 ; N trademark ; B 32 263 968 669 ;
-C -1 ; WX 500 ; N ograve ; B -3 -13 441 697 ;
-C -1 ; WX 389 ; N scaron ; B -19 -13 439 690 ;
-C -1 ; WX 389 ; N Idieresis ; B -32 0 445 862 ;
-C -1 ; WX 556 ; N uacute ; B 15 -9 492 697 ;
-C -1 ; WX 500 ; N agrave ; B -21 -14 455 697 ;
-C -1 ; WX 556 ; N ntilde ; B -6 -9 504 655 ;
-C -1 ; WX 500 ; N aring ; B -21 -14 455 729 ;
-C -1 ; WX 389 ; N zcaron ; B -43 -78 424 690 ;
-C -1 ; WX 389 ; N Icircumflex ; B -32 0 420 897 ;
-C -1 ; WX 722 ; N Ntilde ; B -27 -15 748 862 ;
-C -1 ; WX 556 ; N ucircumflex ; B 15 -9 492 690 ;
-C -1 ; WX 667 ; N Ecircumflex ; B -27 0 653 897 ;
-C -1 ; WX 389 ; N Iacute ; B -32 0 412 904 ;
-C -1 ; WX 667 ; N Ccedilla ; B 32 -218 677 685 ;
-C -1 ; WX 722 ; N Odieresis ; B 27 -18 691 862 ;
-C -1 ; WX 556 ; N Scaron ; B 2 -18 526 897 ;
-C -1 ; WX 667 ; N Edieresis ; B -27 0 653 862 ;
-C -1 ; WX 389 ; N Igrave ; B -32 0 406 904 ;
-C -1 ; WX 500 ; N adieresis ; B -21 -14 471 655 ;
-C -1 ; WX 722 ; N Ograve ; B 27 -18 691 904 ;
-C -1 ; WX 667 ; N Egrave ; B -27 0 653 904 ;
-C -1 ; WX 611 ; N Ydieresis ; B 73 0 659 862 ;
-C -1 ; WX 747 ; N registered ; B 30 -18 718 685 ;
-C -1 ; WX 722 ; N Otilde ; B 27 -18 691 862 ;
-C -1 ; WX 750 ; N onequarter ; B 7 -14 721 683 ;
-C -1 ; WX 722 ; N Ugrave ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 67 -18 744 897 ;
-C -1 ; WX 611 ; N Thorn ; B -27 0 573 669 ;
-C -1 ; WX 570 ; N divide ; B 33 -29 537 535 ;
-C -1 ; WX 667 ; N Atilde ; B -67 0 593 862 ;
-C -1 ; WX 722 ; N Uacute ; B 67 -18 744 904 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 27 -18 691 897 ;
-C -1 ; WX 606 ; N logicalnot ; B 51 108 555 399 ;
-C -1 ; WX 667 ; N Aring ; B -67 0 593 921 ;
-C -1 ; WX 278 ; N idieresis ; B 2 -9 360 655 ;
-C -1 ; WX 278 ; N iacute ; B 2 -9 352 697 ;
-C -1 ; WX 500 ; N aacute ; B -21 -14 463 697 ;
-C -1 ; WX 570 ; N plusminus ; B 33 0 537 506 ;
-C -1 ; WX 570 ; N multiply ; B 48 16 522 490 ;
-C -1 ; WX 722 ; N Udieresis ; B 67 -18 744 862 ;
-C -1 ; WX 606 ; N minus ; B 51 209 555 297 ;
-C -1 ; WX 300 ; N onesuperior ; B 30 274 301 683 ;
-C -1 ; WX 667 ; N Eacute ; B -27 0 653 904 ;
-C -1 ; WX 667 ; N Acircumflex ; B -67 0 593 897 ;
-C -1 ; WX 747 ; N copyright ; B 30 -18 718 685 ;
-C -1 ; WX 667 ; N Agrave ; B -67 0 593 904 ;
-C -1 ; WX 500 ; N odieresis ; B -3 -13 466 655 ;
-C -1 ; WX 500 ; N oacute ; B -3 -13 463 697 ;
-C -1 ; WX 400 ; N degree ; B 83 397 369 683 ;
-C -1 ; WX 278 ; N igrave ; B 2 -9 260 697 ;
-C -1 ; WX 576 ; N mu ; B -60 -207 516 449 ;
-C -1 ; WX 722 ; N Oacute ; B 27 -18 691 904 ;
-C -1 ; WX 500 ; N eth ; B -3 -13 454 699 ;
-C -1 ; WX 667 ; N Adieresis ; B -67 0 593 862 ;
-C -1 ; WX 611 ; N Yacute ; B 73 0 659 904 ;
-C -1 ; WX 220 ; N brokenbar ; B 66 -18 154 685 ;
-C -1 ; WX 750 ; N onehalf ; B -9 -14 723 683 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -74
-KPX A w -74
-KPX A v -74
-KPX A u -30
-KPX A quoteright -74
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -70
-KPX A W -100
-KPX A V -95
-KPX A U -50
-KPX A T -55
-KPX A Q -55
-KPX A O -50
-KPX A G -60
-KPX A C -65
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -25
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -50
-KPX D W -40
-KPX D V -50
-KPX D A -25
-
-KPX F r -50
-KPX F period -129
-KPX F o -70
-KPX F i -40
-KPX F e -100
-KPX F comma -129
-KPX F a -95
-KPX F A -100
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -40
-KPX J period -10
-KPX J o -40
-KPX J e -40
-KPX J comma -10
-KPX J a -40
-KPX J A -25
-
-KPX K y -20
-KPX K u -20
-KPX K o -25
-KPX K e -25
-KPX K O -30
-
-KPX L y -37
-KPX L quoteright -55
-KPX L quotedblright 0
-KPX L Y -37
-KPX L W -37
-KPX L V -37
-KPX L T -18
-
-KPX N period 0
-KPX N comma 0
-KPX N A -30
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -40
-
-KPX P period -129
-KPX P o -55
-KPX P e -50
-KPX P comma -129
-KPX P a -40
-KPX P A -85
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -18
-KPX R W -18
-KPX R V -18
-KPX R U -40
-KPX R T -30
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -37
-KPX T w -37
-KPX T u -37
-KPX T semicolon -74
-KPX T r -37
-KPX T period -92
-KPX T o -95
-KPX T i -37
-KPX T hyphen -92
-KPX T h 0
-KPX T e -92
-KPX T comma -92
-KPX T colon -74
-KPX T a -92
-KPX T O -18
-KPX T A -55
-
-KPX U period 0
-KPX U comma 0
-KPX U A -45
-
-KPX V u -55
-KPX V semicolon -74
-KPX V period -129
-KPX V o -111
-KPX V i -55
-KPX V hyphen -70
-KPX V e -111
-KPX V comma -129
-KPX V colon -74
-KPX V a -111
-KPX V O -30
-KPX V G -10
-KPX V A -85
-
-KPX W y -55
-KPX W u -55
-KPX W semicolon -55
-KPX W period -74
-KPX W o -80
-KPX W i -37
-KPX W hyphen -50
-KPX W h 0
-KPX W e -90
-KPX W comma -74
-KPX W colon -55
-KPX W a -85
-KPX W O -15
-KPX W A -74
-
-KPX Y u -92
-KPX Y semicolon -92
-KPX Y period -74
-KPX Y o -111
-KPX Y i -55
-KPX Y hyphen -92
-KPX Y e -111
-KPX Y comma -92
-KPX Y colon -92
-KPX Y a -92
-KPX Y O -25
-KPX Y A -74
-
-KPX a y 0
-KPX a w 0
-KPX a v 0
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v 0
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b -10
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k -10
-KPX c h -10
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -95
-KPX comma quotedblright -95
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y 0
-KPX e x 0
-KPX e w 0
-KPX e v 0
-KPX e period 0
-KPX e p 0
-KPX e g 0
-KPX e comma 0
-KPX e b -10
-
-KPX f quoteright 55
-KPX f quotedblright 0
-KPX f period -10
-KPX f o -10
-KPX f l 0
-KPX f i 0
-KPX f f -18
-KPX f e -10
-KPX f dotlessi -30
-KPX f comma -10
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period 0
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a 0
-
-KPX h y 0
-
-KPX i v 0
-
-KPX k y 0
-KPX k o -10
-KPX k e -30
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y -10
-KPX o x -10
-KPX o w -25
-KPX o v -15
-KPX o g 0
-
-KPX p y 0
-
-KPX period quoteright -95
-KPX period quotedblright -95
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A 0
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -74
-KPX quoteleft A 0
-
-KPX quoteright v -15
-KPX quoteright t -37
-KPX quoteright space -74
-KPX quoteright s -74
-KPX quoteright r -15
-KPX quoteright quoteright -74
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -15
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q 0
-KPX r period -65
-KPX r p 0
-KPX r o 0
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen 0
-KPX r g 0
-KPX r e 0
-KPX r d 0
-KPX r comma -65
-KPX r c 0
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -70
-KPX space W -70
-KPX space V -70
-KPX space T 0
-KPX space A -37
-
-KPX v period -37
-KPX v o -15
-KPX v e -15
-KPX v comma -37
-KPX v a 0
-
-KPX w period -37
-KPX w o -15
-KPX w h 0
-KPX w e -10
-KPX w comma -37
-KPX w a -10
-
-KPX x e -10
-
-KPX y period -37
-KPX y o 0
-KPX y e 0
-KPX y comma -37
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 172 207 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 187 207 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 167 207 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 172 207 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 157 192 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 167 207 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 172 207 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 187 207 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 187 207 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 172 207 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 33 207 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 53 207 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 48 207 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 33 207 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 210 207 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 200 207 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 230 207 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 215 207 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 200 207 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 215 207 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 207 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 210 207 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 230 207 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 230 207 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 200 207 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 154 207 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 169 207 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 207 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 84 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 84 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 74 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 74 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 84 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 84 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 46 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 46 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -42 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -37 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -37 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 97 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 69 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 74 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 112 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 112 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 97 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 102 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 56 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 41 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 13 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Tue Mar 20 13:14:56 1990
-Comment UniqueID 28427
-Comment VMusage 32912 39804
-FontName Times-Italic
-FullName Times Italic
-FamilyName Times
-Weight Medium
-ItalicAngle -15.5
-IsFixedPitch false
-FontBBox -169 -217 1010 883
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 653
-XHeight 441
-Ascender 683
-Descender -205
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 39 -11 302 667 ;
-C 34 ; WX 420 ; N quotedbl ; B 144 421 432 666 ;
-C 35 ; WX 500 ; N numbersign ; B 2 0 540 676 ;
-C 36 ; WX 500 ; N dollar ; B 31 -89 497 731 ;
-C 37 ; WX 833 ; N percent ; B 79 -13 790 676 ;
-C 38 ; WX 778 ; N ampersand ; B 76 -18 723 666 ;
-C 39 ; WX 333 ; N quoteright ; B 151 436 290 666 ;
-C 40 ; WX 333 ; N parenleft ; B 42 -181 315 669 ;
-C 41 ; WX 333 ; N parenright ; B 16 -180 289 669 ;
-C 42 ; WX 500 ; N asterisk ; B 128 255 492 666 ;
-C 43 ; WX 675 ; N plus ; B 86 0 590 506 ;
-C 44 ; WX 250 ; N comma ; B -4 -129 135 101 ;
-C 45 ; WX 333 ; N hyphen ; B 49 192 282 255 ;
-C 46 ; WX 250 ; N period ; B 27 -11 138 100 ;
-C 47 ; WX 278 ; N slash ; B -65 -18 386 666 ;
-C 48 ; WX 500 ; N zero ; B 32 -7 497 676 ;
-C 49 ; WX 500 ; N one ; B 49 0 409 676 ;
-C 50 ; WX 500 ; N two ; B 12 0 452 676 ;
-C 51 ; WX 500 ; N three ; B 15 -7 465 676 ;
-C 52 ; WX 500 ; N four ; B 1 0 479 676 ;
-C 53 ; WX 500 ; N five ; B 15 -7 491 666 ;
-C 54 ; WX 500 ; N six ; B 30 -7 521 686 ;
-C 55 ; WX 500 ; N seven ; B 75 -8 537 666 ;
-C 56 ; WX 500 ; N eight ; B 30 -7 493 676 ;
-C 57 ; WX 500 ; N nine ; B 23 -17 492 676 ;
-C 58 ; WX 333 ; N colon ; B 50 -11 261 441 ;
-C 59 ; WX 333 ; N semicolon ; B 27 -129 261 441 ;
-C 60 ; WX 675 ; N less ; B 84 -8 592 514 ;
-C 61 ; WX 675 ; N equal ; B 86 120 590 386 ;
-C 62 ; WX 675 ; N greater ; B 84 -8 592 514 ;
-C 63 ; WX 500 ; N question ; B 132 -12 472 664 ;
-C 64 ; WX 920 ; N at ; B 118 -18 806 666 ;
-C 65 ; WX 611 ; N A ; B -51 0 564 668 ;
-C 66 ; WX 611 ; N B ; B -8 0 588 653 ;
-C 67 ; WX 667 ; N C ; B 66 -18 689 666 ;
-C 68 ; WX 722 ; N D ; B -8 0 700 653 ;
-C 69 ; WX 611 ; N E ; B -1 0 634 653 ;
-C 70 ; WX 611 ; N F ; B 8 0 645 653 ;
-C 71 ; WX 722 ; N G ; B 52 -18 722 666 ;
-C 72 ; WX 722 ; N H ; B -8 0 767 653 ;
-C 73 ; WX 333 ; N I ; B -8 0 384 653 ;
-C 74 ; WX 444 ; N J ; B -6 -18 491 653 ;
-C 75 ; WX 667 ; N K ; B 7 0 722 653 ;
-C 76 ; WX 556 ; N L ; B -8 0 559 653 ;
-C 77 ; WX 833 ; N M ; B -18 0 873 653 ;
-C 78 ; WX 667 ; N N ; B -20 -15 727 653 ;
-C 79 ; WX 722 ; N O ; B 60 -18 699 666 ;
-C 80 ; WX 611 ; N P ; B 0 0 605 653 ;
-C 81 ; WX 722 ; N Q ; B 59 -182 699 666 ;
-C 82 ; WX 611 ; N R ; B -13 0 588 653 ;
-C 83 ; WX 500 ; N S ; B 17 -18 508 667 ;
-C 84 ; WX 556 ; N T ; B 59 0 633 653 ;
-C 85 ; WX 722 ; N U ; B 102 -18 765 653 ;
-C 86 ; WX 611 ; N V ; B 76 -18 688 653 ;
-C 87 ; WX 833 ; N W ; B 71 -18 906 653 ;
-C 88 ; WX 611 ; N X ; B -29 0 655 653 ;
-C 89 ; WX 556 ; N Y ; B 78 0 633 653 ;
-C 90 ; WX 556 ; N Z ; B -6 0 606 653 ;
-C 91 ; WX 389 ; N bracketleft ; B 21 -153 391 663 ;
-C 92 ; WX 278 ; N backslash ; B -41 -18 319 666 ;
-C 93 ; WX 389 ; N bracketright ; B 12 -153 382 663 ;
-C 94 ; WX 422 ; N asciicircum ; B 0 301 422 666 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 171 436 310 666 ;
-C 97 ; WX 500 ; N a ; B 17 -11 476 441 ;
-C 98 ; WX 500 ; N b ; B 23 -11 473 683 ;
-C 99 ; WX 444 ; N c ; B 30 -11 425 441 ;
-C 100 ; WX 500 ; N d ; B 15 -13 527 683 ;
-C 101 ; WX 444 ; N e ; B 31 -11 412 441 ;
-C 102 ; WX 278 ; N f ; B -147 -207 424 678 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 8 -206 472 441 ;
-C 104 ; WX 500 ; N h ; B 19 -9 478 683 ;
-C 105 ; WX 278 ; N i ; B 49 -11 264 654 ;
-C 106 ; WX 278 ; N j ; B -124 -207 276 654 ;
-C 107 ; WX 444 ; N k ; B 14 -11 461 683 ;
-C 108 ; WX 278 ; N l ; B 41 -11 279 683 ;
-C 109 ; WX 722 ; N m ; B 12 -9 704 441 ;
-C 110 ; WX 500 ; N n ; B 14 -9 474 441 ;
-C 111 ; WX 500 ; N o ; B 27 -11 468 441 ;
-C 112 ; WX 500 ; N p ; B -75 -205 469 441 ;
-C 113 ; WX 500 ; N q ; B 25 -209 483 441 ;
-C 114 ; WX 389 ; N r ; B 45 0 412 441 ;
-C 115 ; WX 389 ; N s ; B 16 -13 366 442 ;
-C 116 ; WX 278 ; N t ; B 37 -11 296 546 ;
-C 117 ; WX 500 ; N u ; B 42 -11 475 441 ;
-C 118 ; WX 444 ; N v ; B 21 -18 426 441 ;
-C 119 ; WX 667 ; N w ; B 16 -18 648 441 ;
-C 120 ; WX 444 ; N x ; B -27 -11 447 441 ;
-C 121 ; WX 444 ; N y ; B -24 -206 426 441 ;
-C 122 ; WX 389 ; N z ; B -2 -81 380 428 ;
-C 123 ; WX 400 ; N braceleft ; B 51 -177 407 687 ;
-C 124 ; WX 275 ; N bar ; B 105 -18 171 666 ;
-C 125 ; WX 400 ; N braceright ; B -7 -177 349 687 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
-C 161 ; WX 389 ; N exclamdown ; B 59 -205 322 473 ;
-C 162 ; WX 500 ; N cent ; B 77 -143 472 560 ;
-C 163 ; WX 500 ; N sterling ; B 10 -6 517 670 ;
-C 164 ; WX 167 ; N fraction ; B -169 -10 337 676 ;
-C 165 ; WX 500 ; N yen ; B 27 0 603 653 ;
-C 166 ; WX 500 ; N florin ; B 25 -182 507 682 ;
-C 167 ; WX 500 ; N section ; B 53 -162 461 666 ;
-C 168 ; WX 500 ; N currency ; B -22 53 522 597 ;
-C 169 ; WX 214 ; N quotesingle ; B 132 421 241 666 ;
-C 170 ; WX 556 ; N quotedblleft ; B 166 436 514 666 ;
-C 171 ; WX 500 ; N guillemotleft ; B 53 37 445 403 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 51 37 281 403 ;
-C 173 ; WX 333 ; N guilsinglright ; B 52 37 282 403 ;
-C 174 ; WX 500 ; N fi ; B -141 -207 481 681 ;
-C 175 ; WX 500 ; N fl ; B -141 -204 518 682 ;
-C 177 ; WX 500 ; N endash ; B -6 197 505 243 ;
-C 178 ; WX 500 ; N dagger ; B 101 -159 488 666 ;
-C 179 ; WX 500 ; N daggerdbl ; B 22 -143 491 666 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 523 ; N paragraph ; B 55 -123 616 653 ;
-C 183 ; WX 350 ; N bullet ; B 40 191 310 461 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 44 -129 183 101 ;
-C 185 ; WX 556 ; N quotedblbase ; B 57 -129 405 101 ;
-C 186 ; WX 556 ; N quotedblright ; B 151 436 499 666 ;
-C 187 ; WX 500 ; N guillemotright ; B 55 37 447 403 ;
-C 188 ; WX 889 ; N ellipsis ; B 57 -11 762 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 25 -19 1010 706 ;
-C 191 ; WX 500 ; N questiondown ; B 28 -205 368 471 ;
-C 193 ; WX 333 ; N grave ; B 121 492 311 664 ;
-C 194 ; WX 333 ; N acute ; B 180 494 403 664 ;
-C 195 ; WX 333 ; N circumflex ; B 91 492 385 661 ;
-C 196 ; WX 333 ; N tilde ; B 100 517 427 624 ;
-C 197 ; WX 333 ; N macron ; B 99 532 411 583 ;
-C 198 ; WX 333 ; N breve ; B 117 492 418 650 ;
-C 199 ; WX 333 ; N dotaccent ; B 207 508 305 606 ;
-C 200 ; WX 333 ; N dieresis ; B 107 508 405 606 ;
-C 202 ; WX 333 ; N ring ; B 155 492 355 691 ;
-C 203 ; WX 333 ; N cedilla ; B -30 -217 182 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B 93 494 486 664 ;
-C 206 ; WX 333 ; N ogonek ; B -20 -169 200 40 ;
-C 207 ; WX 333 ; N caron ; B 121 492 426 661 ;
-C 208 ; WX 889 ; N emdash ; B -6 197 894 243 ;
-C 225 ; WX 889 ; N AE ; B -27 0 911 653 ;
-C 227 ; WX 276 ; N ordfeminine ; B 42 406 352 676 ;
-C 232 ; WX 556 ; N Lslash ; B -8 0 559 653 ;
-C 233 ; WX 722 ; N Oslash ; B 60 -105 699 722 ;
-C 234 ; WX 944 ; N OE ; B 49 -8 964 666 ;
-C 235 ; WX 310 ; N ordmasculine ; B 67 406 362 676 ;
-C 241 ; WX 667 ; N ae ; B 23 -11 640 441 ;
-C 245 ; WX 278 ; N dotlessi ; B 49 -11 235 441 ;
-C 248 ; WX 278 ; N lslash ; B 37 -11 307 683 ;
-C 249 ; WX 500 ; N oslash ; B 28 -135 469 554 ;
-C 250 ; WX 667 ; N oe ; B 20 -12 646 441 ;
-C 251 ; WX 500 ; N germandbls ; B -168 -207 493 679 ;
-C -1 ; WX 556 ; N Zcaron ; B -6 0 606 873 ;
-C -1 ; WX 444 ; N ccedilla ; B 26 -217 425 441 ;
-C -1 ; WX 444 ; N ydieresis ; B -24 -206 441 606 ;
-C -1 ; WX 500 ; N atilde ; B 17 -11 511 624 ;
-C -1 ; WX 278 ; N icircumflex ; B 34 -11 328 661 ;
-C -1 ; WX 300 ; N threesuperior ; B 43 268 339 676 ;
-C -1 ; WX 444 ; N ecircumflex ; B 31 -11 441 661 ;
-C -1 ; WX 500 ; N thorn ; B -75 -205 469 683 ;
-C -1 ; WX 444 ; N egrave ; B 31 -11 412 664 ;
-C -1 ; WX 300 ; N twosuperior ; B 33 271 324 676 ;
-C -1 ; WX 444 ; N eacute ; B 31 -11 459 664 ;
-C -1 ; WX 500 ; N otilde ; B 27 -11 496 624 ;
-C -1 ; WX 611 ; N Aacute ; B -51 0 564 876 ;
-C -1 ; WX 500 ; N ocircumflex ; B 27 -11 468 661 ;
-C -1 ; WX 444 ; N yacute ; B -24 -206 459 664 ;
-C -1 ; WX 500 ; N udieresis ; B 42 -11 479 606 ;
-C -1 ; WX 750 ; N threequarters ; B 23 -10 736 676 ;
-C -1 ; WX 500 ; N acircumflex ; B 17 -11 476 661 ;
-C -1 ; WX 722 ; N Eth ; B -8 0 700 653 ;
-C -1 ; WX 444 ; N edieresis ; B 31 -11 451 606 ;
-C -1 ; WX 500 ; N ugrave ; B 42 -11 475 664 ;
-C -1 ; WX 980 ; N trademark ; B 30 247 957 653 ;
-C -1 ; WX 500 ; N ograve ; B 27 -11 468 664 ;
-C -1 ; WX 389 ; N scaron ; B 16 -13 454 661 ;
-C -1 ; WX 333 ; N Idieresis ; B -8 0 435 818 ;
-C -1 ; WX 500 ; N uacute ; B 42 -11 477 664 ;
-C -1 ; WX 500 ; N agrave ; B 17 -11 476 664 ;
-C -1 ; WX 500 ; N ntilde ; B 14 -9 476 624 ;
-C -1 ; WX 500 ; N aring ; B 17 -11 476 691 ;
-C -1 ; WX 389 ; N zcaron ; B -2 -81 434 661 ;
-C -1 ; WX 333 ; N Icircumflex ; B -8 0 425 873 ;
-C -1 ; WX 667 ; N Ntilde ; B -20 -15 727 836 ;
-C -1 ; WX 500 ; N ucircumflex ; B 42 -11 475 661 ;
-C -1 ; WX 611 ; N Ecircumflex ; B -1 0 634 873 ;
-C -1 ; WX 333 ; N Iacute ; B -8 0 413 876 ;
-C -1 ; WX 667 ; N Ccedilla ; B 66 -217 689 666 ;
-C -1 ; WX 722 ; N Odieresis ; B 60 -18 699 818 ;
-C -1 ; WX 500 ; N Scaron ; B 17 -18 520 873 ;
-C -1 ; WX 611 ; N Edieresis ; B -1 0 634 818 ;
-C -1 ; WX 333 ; N Igrave ; B -8 0 384 876 ;
-C -1 ; WX 500 ; N adieresis ; B 17 -11 489 606 ;
-C -1 ; WX 722 ; N Ograve ; B 60 -18 699 876 ;
-C -1 ; WX 611 ; N Egrave ; B -1 0 634 876 ;
-C -1 ; WX 556 ; N Ydieresis ; B 78 0 633 818 ;
-C -1 ; WX 760 ; N registered ; B 41 -18 719 666 ;
-C -1 ; WX 722 ; N Otilde ; B 60 -18 699 836 ;
-C -1 ; WX 750 ; N onequarter ; B 33 -10 736 676 ;
-C -1 ; WX 722 ; N Ugrave ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 102 -18 765 873 ;
-C -1 ; WX 611 ; N Thorn ; B 0 0 569 653 ;
-C -1 ; WX 675 ; N divide ; B 86 -11 590 517 ;
-C -1 ; WX 611 ; N Atilde ; B -51 0 566 836 ;
-C -1 ; WX 722 ; N Uacute ; B 102 -18 765 876 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 60 -18 699 873 ;
-C -1 ; WX 675 ; N logicalnot ; B 86 108 590 386 ;
-C -1 ; WX 611 ; N Aring ; B -51 0 564 883 ;
-C -1 ; WX 278 ; N idieresis ; B 49 -11 353 606 ;
-C -1 ; WX 278 ; N iacute ; B 49 -11 356 664 ;
-C -1 ; WX 500 ; N aacute ; B 17 -11 487 664 ;
-C -1 ; WX 675 ; N plusminus ; B 86 0 590 506 ;
-C -1 ; WX 675 ; N multiply ; B 93 8 582 497 ;
-C -1 ; WX 722 ; N Udieresis ; B 102 -18 765 818 ;
-C -1 ; WX 675 ; N minus ; B 86 220 590 286 ;
-C -1 ; WX 300 ; N onesuperior ; B 43 271 284 676 ;
-C -1 ; WX 611 ; N Eacute ; B -1 0 634 876 ;
-C -1 ; WX 611 ; N Acircumflex ; B -51 0 564 873 ;
-C -1 ; WX 760 ; N copyright ; B 41 -18 719 666 ;
-C -1 ; WX 611 ; N Agrave ; B -51 0 564 876 ;
-C -1 ; WX 500 ; N odieresis ; B 27 -11 489 606 ;
-C -1 ; WX 500 ; N oacute ; B 27 -11 487 664 ;
-C -1 ; WX 400 ; N degree ; B 101 390 387 676 ;
-C -1 ; WX 278 ; N igrave ; B 49 -11 284 664 ;
-C -1 ; WX 500 ; N mu ; B -30 -209 497 428 ;
-C -1 ; WX 722 ; N Oacute ; B 60 -18 699 876 ;
-C -1 ; WX 500 ; N eth ; B 27 -11 482 683 ;
-C -1 ; WX 611 ; N Adieresis ; B -51 0 564 818 ;
-C -1 ; WX 556 ; N Yacute ; B 78 0 633 876 ;
-C -1 ; WX 275 ; N brokenbar ; B 105 -18 171 666 ;
-C -1 ; WX 750 ; N onehalf ; B 34 -10 749 676 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -55
-KPX A w -55
-KPX A v -55
-KPX A u -20
-KPX A quoteright -37
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -55
-KPX A W -95
-KPX A V -105
-KPX A U -50
-KPX A T -37
-KPX A Q -40
-KPX A O -40
-KPX A G -35
-KPX A C -30
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -25
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -40
-KPX D W -40
-KPX D V -40
-KPX D A -35
-
-KPX F r -55
-KPX F period -135
-KPX F o -105
-KPX F i -45
-KPX F e -75
-KPX F comma -135
-KPX F a -75
-KPX F A -115
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u -35
-KPX J period -25
-KPX J o -25
-KPX J e -25
-KPX J comma -25
-KPX J a -35
-KPX J A -40
-
-KPX K y -40
-KPX K u -40
-KPX K o -40
-KPX K e -35
-KPX K O -50
-
-KPX L y -30
-KPX L quoteright -37
-KPX L quotedblright 0
-KPX L Y -20
-KPX L W -55
-KPX L V -55
-KPX L T -20
-
-KPX N period 0
-KPX N comma 0
-KPX N A -27
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -50
-KPX O V -50
-KPX O T -40
-KPX O A -55
-
-KPX P period -135
-KPX P o -80
-KPX P e -80
-KPX P comma -135
-KPX P a -80
-KPX P A -90
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -18
-KPX R W -18
-KPX R V -18
-KPX R U -40
-KPX R T 0
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -74
-KPX T w -74
-KPX T u -55
-KPX T semicolon -65
-KPX T r -55
-KPX T period -74
-KPX T o -92
-KPX T i -55
-KPX T hyphen -74
-KPX T h 0
-KPX T e -92
-KPX T comma -74
-KPX T colon -55
-KPX T a -92
-KPX T O -18
-KPX T A -50
-
-KPX U period -25
-KPX U comma -25
-KPX U A -40
-
-KPX V u -74
-KPX V semicolon -74
-KPX V period -129
-KPX V o -111
-KPX V i -74
-KPX V hyphen -55
-KPX V e -111
-KPX V comma -129
-KPX V colon -65
-KPX V a -111
-KPX V O -30
-KPX V G 0
-KPX V A -60
-
-KPX W y -70
-KPX W u -55
-KPX W semicolon -65
-KPX W period -92
-KPX W o -92
-KPX W i -55
-KPX W hyphen -37
-KPX W h 0
-KPX W e -92
-KPX W comma -92
-KPX W colon -65
-KPX W a -92
-KPX W O -25
-KPX W A -60
-
-KPX Y u -92
-KPX Y semicolon -65
-KPX Y period -92
-KPX Y o -92
-KPX Y i -74
-KPX Y hyphen -74
-KPX Y e -92
-KPX Y comma -92
-KPX Y colon -65
-KPX Y a -92
-KPX Y O -15
-KPX Y A -50
-
-KPX a y 0
-KPX a w 0
-KPX a v 0
-KPX a t 0
-KPX a p 0
-KPX a g -10
-KPX a b 0
-
-KPX b y 0
-KPX b v 0
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b 0
-
-KPX c y 0
-KPX c period 0
-KPX c l 0
-KPX c k -20
-KPX c h -15
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -140
-KPX comma quotedblright -140
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y -30
-KPX e x -20
-KPX e w -15
-KPX e v -15
-KPX e period -15
-KPX e p 0
-KPX e g -40
-KPX e comma -10
-KPX e b 0
-
-KPX f quoteright 92
-KPX f quotedblright 0
-KPX f period -15
-KPX f o 0
-KPX f l 0
-KPX f i -20
-KPX f f -18
-KPX f e 0
-KPX f dotlessi -60
-KPX f comma -10
-KPX f a 0
-
-KPX g y 0
-KPX g r 0
-KPX g period -15
-KPX g o 0
-KPX g i 0
-KPX g g -10
-KPX g e -10
-KPX g comma -10
-KPX g a 0
-
-KPX h y 0
-
-KPX i v 0
-
-KPX k y -10
-KPX k o -10
-KPX k e -10
-
-KPX l y 0
-KPX l w 0
-
-KPX m y 0
-KPX m u 0
-
-KPX n y 0
-KPX n v -40
-KPX n u 0
-
-KPX o y 0
-KPX o x 0
-KPX o w 0
-KPX o v -10
-KPX o g -10
-
-KPX p y 0
-
-KPX period quoteright -140
-KPX period quotedblright -140
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A 0
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -111
-KPX quoteleft A 0
-
-KPX quoteright v -10
-KPX quoteright t -30
-KPX quoteright space -111
-KPX quoteright s -40
-KPX quoteright r -25
-KPX quoteright quoteright -111
-KPX quoteright quotedblright 0
-KPX quoteright l 0
-KPX quoteright d -25
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s -10
-KPX r r 0
-KPX r q -37
-KPX r period -111
-KPX r p 0
-KPX r o -45
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -20
-KPX r g -37
-KPX r e -37
-KPX r d -37
-KPX r comma -111
-KPX r c -37
-KPX r a -15
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -75
-KPX space W -40
-KPX space V -35
-KPX space T -18
-KPX space A -18
-
-KPX v period -74
-KPX v o 0
-KPX v e 0
-KPX v comma -74
-KPX v a 0
-
-KPX w period -74
-KPX w o 0
-KPX w h 0
-KPX w e 0
-KPX w comma -74
-KPX w a 0
-
-KPX x e 0
-
-KPX y period -55
-KPX y o 0
-KPX y e 0
-KPX y comma -55
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 139 212 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 144 212 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 139 212 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 149 212 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 129 192 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 139 212 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 149 212 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 169 212 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 159 212 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 149 212 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 10 212 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 40 212 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 30 212 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 10 212 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 177 212 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 195 212 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 230 212 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 230 212 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 205 212 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 215 212 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 94 212 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 212 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 215 212 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 225 212 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 215 212 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 132 212 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 142 212 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 112 212 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 84 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 84 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 84 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 84 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 84 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 84 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 46 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 56 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -47 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -57 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -52 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 49 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 74 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 69 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 74 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 74 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 74 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 84 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 56 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 36 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 8 0 ;
-EndComposites
-EndFontMetrics
+++ /dev/null
-StartFontMetrics 2.0
-Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.
-Comment Creation Date: Tue Mar 20 12:15:44 1990
-Comment UniqueID 28416
-Comment VMusage 30487 37379
-FontName Times-Roman
-FullName Times Roman
-FamilyName Times
-Weight Roman
-ItalicAngle 0
-IsFixedPitch false
-FontBBox -168 -218 1000 898
-UnderlinePosition -100
-UnderlineThickness 50
-Version 001.007
-Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype AG and/or its subsidiaries.
-EncodingScheme AdobeStandardEncoding
-CapHeight 662
-XHeight 450
-Ascender 683
-Descender -217
-StartCharMetrics 228
-C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
-C 33 ; WX 333 ; N exclam ; B 130 -9 238 676 ;
-C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ;
-C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ;
-C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ;
-C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ;
-C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ;
-C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ;
-C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ;
-C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ;
-C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ;
-C 43 ; WX 564 ; N plus ; B 30 0 534 506 ;
-C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ;
-C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ;
-C 46 ; WX 250 ; N period ; B 70 -11 181 100 ;
-C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ;
-C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ;
-C 49 ; WX 500 ; N one ; B 111 0 394 676 ;
-C 50 ; WX 500 ; N two ; B 30 0 475 676 ;
-C 51 ; WX 500 ; N three ; B 43 -14 431 676 ;
-C 52 ; WX 500 ; N four ; B 12 0 472 676 ;
-C 53 ; WX 500 ; N five ; B 32 -14 438 688 ;
-C 54 ; WX 500 ; N six ; B 34 -14 468 684 ;
-C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ;
-C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ;
-C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ;
-C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ;
-C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ;
-C 60 ; WX 564 ; N less ; B 28 -8 536 514 ;
-C 61 ; WX 564 ; N equal ; B 30 120 534 386 ;
-C 62 ; WX 564 ; N greater ; B 28 -8 536 514 ;
-C 63 ; WX 444 ; N question ; B 68 -8 414 676 ;
-C 64 ; WX 921 ; N at ; B 116 -14 809 676 ;
-C 65 ; WX 722 ; N A ; B 15 0 706 674 ;
-C 66 ; WX 667 ; N B ; B 17 0 593 662 ;
-C 67 ; WX 667 ; N C ; B 28 -14 633 676 ;
-C 68 ; WX 722 ; N D ; B 16 0 685 662 ;
-C 69 ; WX 611 ; N E ; B 12 0 597 662 ;
-C 70 ; WX 556 ; N F ; B 12 0 546 662 ;
-C 71 ; WX 722 ; N G ; B 32 -14 709 676 ;
-C 72 ; WX 722 ; N H ; B 19 0 702 662 ;
-C 73 ; WX 333 ; N I ; B 18 0 315 662 ;
-C 74 ; WX 389 ; N J ; B 10 -14 370 662 ;
-C 75 ; WX 722 ; N K ; B 34 0 723 662 ;
-C 76 ; WX 611 ; N L ; B 12 0 598 662 ;
-C 77 ; WX 889 ; N M ; B 12 0 863 662 ;
-C 78 ; WX 722 ; N N ; B 12 -11 707 662 ;
-C 79 ; WX 722 ; N O ; B 34 -14 688 676 ;
-C 80 ; WX 556 ; N P ; B 16 0 542 662 ;
-C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ;
-C 82 ; WX 667 ; N R ; B 17 0 659 662 ;
-C 83 ; WX 556 ; N S ; B 42 -14 491 676 ;
-C 84 ; WX 611 ; N T ; B 17 0 593 662 ;
-C 85 ; WX 722 ; N U ; B 14 -14 705 662 ;
-C 86 ; WX 722 ; N V ; B 16 -11 697 662 ;
-C 87 ; WX 944 ; N W ; B 5 -11 932 662 ;
-C 88 ; WX 722 ; N X ; B 10 0 704 662 ;
-C 89 ; WX 722 ; N Y ; B 22 0 703 662 ;
-C 90 ; WX 611 ; N Z ; B 9 0 597 662 ;
-C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ;
-C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ;
-C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ;
-C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ;
-C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ;
-C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ;
-C 97 ; WX 444 ; N a ; B 37 -10 442 460 ;
-C 98 ; WX 500 ; N b ; B 3 -10 468 683 ;
-C 99 ; WX 444 ; N c ; B 25 -10 412 460 ;
-C 100 ; WX 500 ; N d ; B 27 -10 491 683 ;
-C 101 ; WX 444 ; N e ; B 25 -10 424 460 ;
-C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ;
-C 103 ; WX 500 ; N g ; B 28 -218 470 460 ;
-C 104 ; WX 500 ; N h ; B 9 0 487 683 ;
-C 105 ; WX 278 ; N i ; B 16 0 253 683 ;
-C 106 ; WX 278 ; N j ; B -70 -218 194 683 ;
-C 107 ; WX 500 ; N k ; B 7 0 505 683 ;
-C 108 ; WX 278 ; N l ; B 19 0 257 683 ;
-C 109 ; WX 778 ; N m ; B 16 0 775 460 ;
-C 110 ; WX 500 ; N n ; B 16 0 485 460 ;
-C 111 ; WX 500 ; N o ; B 29 -10 470 460 ;
-C 112 ; WX 500 ; N p ; B 5 -217 470 460 ;
-C 113 ; WX 500 ; N q ; B 24 -217 488 460 ;
-C 114 ; WX 333 ; N r ; B 5 0 335 460 ;
-C 115 ; WX 389 ; N s ; B 51 -10 348 460 ;
-C 116 ; WX 278 ; N t ; B 13 -10 279 579 ;
-C 117 ; WX 500 ; N u ; B 9 -10 479 450 ;
-C 118 ; WX 500 ; N v ; B 19 -14 477 450 ;
-C 119 ; WX 722 ; N w ; B 21 -14 694 450 ;
-C 120 ; WX 500 ; N x ; B 17 0 479 450 ;
-C 121 ; WX 500 ; N y ; B 14 -218 475 450 ;
-C 122 ; WX 444 ; N z ; B 27 0 418 450 ;
-C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ;
-C 124 ; WX 200 ; N bar ; B 67 -14 133 676 ;
-C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ;
-C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;
-C 161 ; WX 333 ; N exclamdown ; B 97 -218 205 467 ;
-C 162 ; WX 500 ; N cent ; B 53 -138 448 579 ;
-C 163 ; WX 500 ; N sterling ; B 12 -8 490 676 ;
-C 164 ; WX 167 ; N fraction ; B -168 -14 331 676 ;
-C 165 ; WX 500 ; N yen ; B -53 0 512 662 ;
-C 166 ; WX 500 ; N florin ; B 7 -189 490 676 ;
-C 167 ; WX 500 ; N section ; B 70 -148 426 676 ;
-C 168 ; WX 500 ; N currency ; B -22 58 522 602 ;
-C 169 ; WX 180 ; N quotesingle ; B 48 431 133 676 ;
-C 170 ; WX 444 ; N quotedblleft ; B 43 433 414 676 ;
-C 171 ; WX 500 ; N guillemotleft ; B 42 33 456 416 ;
-C 172 ; WX 333 ; N guilsinglleft ; B 63 33 285 416 ;
-C 173 ; WX 333 ; N guilsinglright ; B 48 33 270 416 ;
-C 174 ; WX 556 ; N fi ; B 31 0 521 683 ;
-C 175 ; WX 556 ; N fl ; B 32 0 521 683 ;
-C 177 ; WX 500 ; N endash ; B 0 201 500 250 ;
-C 178 ; WX 500 ; N dagger ; B 59 -149 442 676 ;
-C 179 ; WX 500 ; N daggerdbl ; B 58 -153 442 676 ;
-C 180 ; WX 250 ; N periodcentered ; B 70 199 181 310 ;
-C 182 ; WX 453 ; N paragraph ; B -22 -154 450 662 ;
-C 183 ; WX 350 ; N bullet ; B 40 196 310 466 ;
-C 184 ; WX 333 ; N quotesinglbase ; B 79 -141 218 102 ;
-C 185 ; WX 444 ; N quotedblbase ; B 45 -141 416 102 ;
-C 186 ; WX 444 ; N quotedblright ; B 30 433 401 676 ;
-C 187 ; WX 500 ; N guillemotright ; B 44 33 458 416 ;
-C 188 ; WX 1000 ; N ellipsis ; B 111 -11 888 100 ;
-C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 706 ;
-C 191 ; WX 444 ; N questiondown ; B 30 -218 376 466 ;
-C 193 ; WX 333 ; N grave ; B 19 507 242 678 ;
-C 194 ; WX 333 ; N acute ; B 93 507 317 678 ;
-C 195 ; WX 333 ; N circumflex ; B 11 507 322 674 ;
-C 196 ; WX 333 ; N tilde ; B 1 532 331 638 ;
-C 197 ; WX 333 ; N macron ; B 11 547 322 601 ;
-C 198 ; WX 333 ; N breve ; B 26 507 307 664 ;
-C 199 ; WX 333 ; N dotaccent ; B 118 523 216 623 ;
-C 200 ; WX 333 ; N dieresis ; B 18 523 315 623 ;
-C 202 ; WX 333 ; N ring ; B 67 512 266 711 ;
-C 203 ; WX 333 ; N cedilla ; B 52 -215 261 0 ;
-C 205 ; WX 333 ; N hungarumlaut ; B -3 507 377 678 ;
-C 206 ; WX 333 ; N ogonek ; B 64 -165 249 0 ;
-C 207 ; WX 333 ; N caron ; B 11 507 322 674 ;
-C 208 ; WX 1000 ; N emdash ; B 0 201 1000 250 ;
-C 225 ; WX 889 ; N AE ; B 0 0 863 662 ;
-C 227 ; WX 276 ; N ordfeminine ; B 4 394 270 676 ;
-C 232 ; WX 611 ; N Lslash ; B 12 0 598 662 ;
-C 233 ; WX 722 ; N Oslash ; B 34 -80 688 734 ;
-C 234 ; WX 889 ; N OE ; B 30 -6 885 668 ;
-C 235 ; WX 310 ; N ordmasculine ; B 6 394 304 676 ;
-C 241 ; WX 667 ; N ae ; B 38 -10 632 460 ;
-C 245 ; WX 278 ; N dotlessi ; B 16 0 253 460 ;
-C 248 ; WX 278 ; N lslash ; B 19 0 259 683 ;
-C 249 ; WX 500 ; N oslash ; B 29 -112 470 551 ;
-C 250 ; WX 722 ; N oe ; B 30 -10 690 460 ;
-C 251 ; WX 500 ; N germandbls ; B 12 -9 468 683 ;
-C -1 ; WX 611 ; N Zcaron ; B 9 0 597 886 ;
-C -1 ; WX 444 ; N ccedilla ; B 25 -215 412 460 ;
-C -1 ; WX 500 ; N ydieresis ; B 14 -218 475 623 ;
-C -1 ; WX 444 ; N atilde ; B 37 -10 442 638 ;
-C -1 ; WX 278 ; N icircumflex ; B -16 0 295 674 ;
-C -1 ; WX 300 ; N threesuperior ; B 15 262 291 676 ;
-C -1 ; WX 444 ; N ecircumflex ; B 25 -10 424 674 ;
-C -1 ; WX 500 ; N thorn ; B 5 -217 470 683 ;
-C -1 ; WX 444 ; N egrave ; B 25 -10 424 678 ;
-C -1 ; WX 300 ; N twosuperior ; B 1 270 296 676 ;
-C -1 ; WX 444 ; N eacute ; B 25 -10 424 678 ;
-C -1 ; WX 500 ; N otilde ; B 29 -10 470 638 ;
-C -1 ; WX 722 ; N Aacute ; B 15 0 706 890 ;
-C -1 ; WX 500 ; N ocircumflex ; B 29 -10 470 674 ;
-C -1 ; WX 500 ; N yacute ; B 14 -218 475 678 ;
-C -1 ; WX 500 ; N udieresis ; B 9 -10 479 623 ;
-C -1 ; WX 750 ; N threequarters ; B 15 -14 718 676 ;
-C -1 ; WX 444 ; N acircumflex ; B 37 -10 442 674 ;
-C -1 ; WX 722 ; N Eth ; B 16 0 685 662 ;
-C -1 ; WX 444 ; N edieresis ; B 25 -10 424 623 ;
-C -1 ; WX 500 ; N ugrave ; B 9 -10 479 678 ;
-C -1 ; WX 980 ; N trademark ; B 30 256 957 662 ;
-C -1 ; WX 500 ; N ograve ; B 29 -10 470 678 ;
-C -1 ; WX 389 ; N scaron ; B 39 -10 350 674 ;
-C -1 ; WX 333 ; N Idieresis ; B 18 0 315 835 ;
-C -1 ; WX 500 ; N uacute ; B 9 -10 479 678 ;
-C -1 ; WX 444 ; N agrave ; B 37 -10 442 678 ;
-C -1 ; WX 500 ; N ntilde ; B 16 0 485 638 ;
-C -1 ; WX 444 ; N aring ; B 37 -10 442 711 ;
-C -1 ; WX 444 ; N zcaron ; B 27 0 418 674 ;
-C -1 ; WX 333 ; N Icircumflex ; B 11 0 322 886 ;
-C -1 ; WX 722 ; N Ntilde ; B 12 -11 707 850 ;
-C -1 ; WX 500 ; N ucircumflex ; B 9 -10 479 674 ;
-C -1 ; WX 611 ; N Ecircumflex ; B 12 0 597 886 ;
-C -1 ; WX 333 ; N Iacute ; B 18 0 317 890 ;
-C -1 ; WX 667 ; N Ccedilla ; B 28 -215 633 676 ;
-C -1 ; WX 722 ; N Odieresis ; B 34 -14 688 835 ;
-C -1 ; WX 556 ; N Scaron ; B 42 -14 491 886 ;
-C -1 ; WX 611 ; N Edieresis ; B 12 0 597 835 ;
-C -1 ; WX 333 ; N Igrave ; B 18 0 315 890 ;
-C -1 ; WX 444 ; N adieresis ; B 37 -10 442 623 ;
-C -1 ; WX 722 ; N Ograve ; B 34 -14 688 890 ;
-C -1 ; WX 611 ; N Egrave ; B 12 0 597 890 ;
-C -1 ; WX 722 ; N Ydieresis ; B 22 0 703 835 ;
-C -1 ; WX 760 ; N registered ; B 38 -14 722 676 ;
-C -1 ; WX 722 ; N Otilde ; B 34 -14 688 850 ;
-C -1 ; WX 750 ; N onequarter ; B 37 -14 718 676 ;
-C -1 ; WX 722 ; N Ugrave ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ucircumflex ; B 14 -14 705 886 ;
-C -1 ; WX 556 ; N Thorn ; B 16 0 542 662 ;
-C -1 ; WX 564 ; N divide ; B 30 -10 534 516 ;
-C -1 ; WX 722 ; N Atilde ; B 15 0 706 850 ;
-C -1 ; WX 722 ; N Uacute ; B 14 -14 705 890 ;
-C -1 ; WX 722 ; N Ocircumflex ; B 34 -14 688 886 ;
-C -1 ; WX 564 ; N logicalnot ; B 30 108 534 386 ;
-C -1 ; WX 722 ; N Aring ; B 15 0 706 898 ;
-C -1 ; WX 278 ; N idieresis ; B -9 0 288 623 ;
-C -1 ; WX 278 ; N iacute ; B 16 0 290 678 ;
-C -1 ; WX 444 ; N aacute ; B 37 -10 442 678 ;
-C -1 ; WX 564 ; N plusminus ; B 30 0 534 506 ;
-C -1 ; WX 564 ; N multiply ; B 38 8 527 497 ;
-C -1 ; WX 722 ; N Udieresis ; B 14 -14 705 835 ;
-C -1 ; WX 564 ; N minus ; B 30 220 534 286 ;
-C -1 ; WX 300 ; N onesuperior ; B 57 270 248 676 ;
-C -1 ; WX 611 ; N Eacute ; B 12 0 597 890 ;
-C -1 ; WX 722 ; N Acircumflex ; B 15 0 706 886 ;
-C -1 ; WX 760 ; N copyright ; B 38 -14 722 676 ;
-C -1 ; WX 722 ; N Agrave ; B 15 0 706 890 ;
-C -1 ; WX 500 ; N odieresis ; B 29 -10 470 623 ;
-C -1 ; WX 500 ; N oacute ; B 29 -10 470 678 ;
-C -1 ; WX 400 ; N degree ; B 57 390 343 676 ;
-C -1 ; WX 278 ; N igrave ; B -8 0 253 678 ;
-C -1 ; WX 500 ; N mu ; B 36 -218 512 450 ;
-C -1 ; WX 722 ; N Oacute ; B 34 -14 688 890 ;
-C -1 ; WX 500 ; N eth ; B 29 -10 471 686 ;
-C -1 ; WX 722 ; N Adieresis ; B 15 0 706 835 ;
-C -1 ; WX 722 ; N Yacute ; B 22 0 703 890 ;
-C -1 ; WX 200 ; N brokenbar ; B 67 -14 133 676 ;
-C -1 ; WX 750 ; N onehalf ; B 31 -14 746 676 ;
-EndCharMetrics
-StartKernData
-StartKernPairs 283
-
-KPX A y -92
-KPX A w -92
-KPX A v -74
-KPX A u 0
-KPX A quoteright -111
-KPX A quotedblright 0
-KPX A p 0
-KPX A Y -105
-KPX A W -90
-KPX A V -135
-KPX A U -55
-KPX A T -111
-KPX A Q -55
-KPX A O -55
-KPX A G -40
-KPX A C -40
-
-KPX B period 0
-KPX B comma 0
-KPX B U -10
-KPX B A -35
-
-KPX D period 0
-KPX D comma 0
-KPX D Y -55
-KPX D W -30
-KPX D V -40
-KPX D A -40
-
-KPX F r 0
-KPX F period -80
-KPX F o -15
-KPX F i 0
-KPX F e 0
-KPX F comma -80
-KPX F a -15
-KPX F A -74
-
-KPX G period 0
-KPX G comma 0
-
-KPX J u 0
-KPX J period 0
-KPX J o 0
-KPX J e 0
-KPX J comma 0
-KPX J a 0
-KPX J A -60
-
-KPX K y -25
-KPX K u -15
-KPX K o -35
-KPX K e -25
-KPX K O -30
-
-KPX L y -55
-KPX L quoteright -92
-KPX L quotedblright 0
-KPX L Y -100
-KPX L W -74
-KPX L V -100
-KPX L T -92
-
-KPX N period 0
-KPX N comma 0
-KPX N A -35
-
-KPX O period 0
-KPX O comma 0
-KPX O Y -50
-KPX O X -40
-KPX O W -35
-KPX O V -50
-KPX O T -40
-KPX O A -35
-
-KPX P period -111
-KPX P o 0
-KPX P e 0
-KPX P comma -111
-KPX P a -15
-KPX P A -92
-
-KPX Q period 0
-KPX Q comma 0
-KPX Q U -10
-
-KPX R Y -65
-KPX R W -55
-KPX R V -80
-KPX R U -40
-KPX R T -60
-KPX R O -40
-
-KPX S period 0
-KPX S comma 0
-
-KPX T y -80
-KPX T w -80
-KPX T u -45
-KPX T semicolon -55
-KPX T r -35
-KPX T period -74
-KPX T o -80
-KPX T i -35
-KPX T hyphen -92
-KPX T h 0
-KPX T e -70
-KPX T comma -74
-KPX T colon -50
-KPX T a -80
-KPX T O -18
-KPX T A -93
-
-KPX U period 0
-KPX U comma 0
-KPX U A -40
-
-KPX V u -75
-KPX V semicolon -74
-KPX V period -129
-KPX V o -129
-KPX V i -60
-KPX V hyphen -100
-KPX V e -111
-KPX V comma -129
-KPX V colon -74
-KPX V a -111
-KPX V O -40
-KPX V G -15
-KPX V A -135
-
-KPX W y -73
-KPX W u -50
-KPX W semicolon -37
-KPX W period -92
-KPX W o -80
-KPX W i -40
-KPX W hyphen -65
-KPX W h 0
-KPX W e -80
-KPX W comma -92
-KPX W colon -37
-KPX W a -80
-KPX W O -10
-KPX W A -120
-
-KPX Y u -111
-KPX Y semicolon -92
-KPX Y period -129
-KPX Y o -110
-KPX Y i -55
-KPX Y hyphen -111
-KPX Y e -100
-KPX Y comma -129
-KPX Y colon -92
-KPX Y a -100
-KPX Y O -30
-KPX Y A -120
-
-KPX a y 0
-KPX a w -15
-KPX a v -20
-KPX a t 0
-KPX a p 0
-KPX a g 0
-KPX a b 0
-
-KPX b y 0
-KPX b v -15
-KPX b u -20
-KPX b period -40
-KPX b l 0
-KPX b comma 0
-KPX b b 0
-
-KPX c y -15
-KPX c period 0
-KPX c l 0
-KPX c k 0
-KPX c h 0
-KPX c comma 0
-
-KPX colon space 0
-
-KPX comma space 0
-KPX comma quoteright -70
-KPX comma quotedblright -70
-
-KPX d y 0
-KPX d w 0
-KPX d v 0
-KPX d period 0
-KPX d d 0
-KPX d comma 0
-
-KPX e y -15
-KPX e x -15
-KPX e w -25
-KPX e v -25
-KPX e period 0
-KPX e p 0
-KPX e g -15
-KPX e comma 0
-KPX e b 0
-
-KPX f quoteright 55
-KPX f quotedblright 0
-KPX f period 0
-KPX f o 0
-KPX f l 0
-KPX f i -20
-KPX f f -25
-KPX f e 0
-KPX f dotlessi -50
-KPX f comma 0
-KPX f a -10
-
-KPX g y 0
-KPX g r 0
-KPX g period 0
-KPX g o 0
-KPX g i 0
-KPX g g 0
-KPX g e 0
-KPX g comma 0
-KPX g a -5
-
-KPX h y -5
-
-KPX i v -25
-
-KPX k y -15
-KPX k o -10
-KPX k e -10
-
-KPX l y 0
-KPX l w -10
-
-KPX m y 0
-KPX m u 0
-
-KPX n y -15
-KPX n v -40
-KPX n u 0
-
-KPX o y -10
-KPX o x 0
-KPX o w -25
-KPX o v -15
-KPX o g 0
-
-KPX p y -10
-
-KPX period quoteright -70
-KPX period quotedblright -70
-
-KPX quotedblleft quoteleft 0
-KPX quotedblleft A -80
-
-KPX quotedblright space 0
-
-KPX quoteleft quoteleft -74
-KPX quoteleft A -80
-
-KPX quoteright v -50
-KPX quoteright t -18
-KPX quoteright space -74
-KPX quoteright s -55
-KPX quoteright r -50
-KPX quoteright quoteright -74
-KPX quoteright quotedblright 0
-KPX quoteright l -10
-KPX quoteright d -50
-
-KPX r y 0
-KPX r v 0
-KPX r u 0
-KPX r t 0
-KPX r s 0
-KPX r r 0
-KPX r q 0
-KPX r period -55
-KPX r p 0
-KPX r o 0
-KPX r n 0
-KPX r m 0
-KPX r l 0
-KPX r k 0
-KPX r i 0
-KPX r hyphen -20
-KPX r g -18
-KPX r e 0
-KPX r d 0
-KPX r comma -40
-KPX r c 0
-KPX r a 0
-
-KPX s w 0
-
-KPX space quoteleft 0
-KPX space quotedblleft 0
-KPX space Y -90
-KPX space W -30
-KPX space V -50
-KPX space T -18
-KPX space A -55
-
-KPX v period -65
-KPX v o -20
-KPX v e -15
-KPX v comma -65
-KPX v a -25
-
-KPX w period -65
-KPX w o -10
-KPX w h 0
-KPX w e 0
-KPX w comma -65
-KPX w a -10
-
-KPX x e -15
-
-KPX y period -65
-KPX y o 0
-KPX y e 0
-KPX y comma -65
-KPX y a 0
-
-KPX z o 0
-KPX z e 0
-EndKernPairs
-EndKernData
-StartComposites 58
-CC Aacute 2 ; PCC A 0 0 ; PCC acute 195 212 ;
-CC Acircumflex 2 ; PCC A 0 0 ; PCC circumflex 195 212 ;
-CC Adieresis 2 ; PCC A 0 0 ; PCC dieresis 195 212 ;
-CC Agrave 2 ; PCC A 0 0 ; PCC grave 195 212 ;
-CC Aring 2 ; PCC A 0 0 ; PCC ring 185 187 ;
-CC Atilde 2 ; PCC A 0 0 ; PCC tilde 195 212 ;
-CC Ccedilla 2 ; PCC C 0 0 ; PCC cedilla 167 0 ;
-CC Eacute 2 ; PCC E 0 0 ; PCC acute 139 212 ;
-CC Ecircumflex 2 ; PCC E 0 0 ; PCC circumflex 139 212 ;
-CC Edieresis 2 ; PCC E 0 0 ; PCC dieresis 139 212 ;
-CC Egrave 2 ; PCC E 0 0 ; PCC grave 139 212 ;
-CC Iacute 2 ; PCC I 0 0 ; PCC acute 0 212 ;
-CC Icircumflex 2 ; PCC I 0 0 ; PCC circumflex 0 212 ;
-CC Idieresis 2 ; PCC I 0 0 ; PCC dieresis 0 212 ;
-CC Igrave 2 ; PCC I 0 0 ; PCC grave 0 212 ;
-CC Ntilde 2 ; PCC N 0 0 ; PCC tilde 195 212 ;
-CC Oacute 2 ; PCC O 0 0 ; PCC acute 195 212 ;
-CC Ocircumflex 2 ; PCC O 0 0 ; PCC circumflex 195 212 ;
-CC Odieresis 2 ; PCC O 0 0 ; PCC dieresis 195 212 ;
-CC Ograve 2 ; PCC O 0 0 ; PCC grave 195 212 ;
-CC Otilde 2 ; PCC O 0 0 ; PCC tilde 195 212 ;
-CC Scaron 2 ; PCC S 0 0 ; PCC caron 112 212 ;
-CC Uacute 2 ; PCC U 0 0 ; PCC acute 195 212 ;
-CC Ucircumflex 2 ; PCC U 0 0 ; PCC circumflex 195 212 ;
-CC Udieresis 2 ; PCC U 0 0 ; PCC dieresis 195 212 ;
-CC Ugrave 2 ; PCC U 0 0 ; PCC grave 195 212 ;
-CC Yacute 2 ; PCC Y 0 0 ; PCC acute 195 212 ;
-CC Ydieresis 2 ; PCC Y 0 0 ; PCC dieresis 195 212 ;
-CC Zcaron 2 ; PCC Z 0 0 ; PCC caron 139 212 ;
-CC aacute 2 ; PCC a 0 0 ; PCC acute 56 0 ;
-CC acircumflex 2 ; PCC a 0 0 ; PCC circumflex 56 0 ;
-CC adieresis 2 ; PCC a 0 0 ; PCC dieresis 56 0 ;
-CC agrave 2 ; PCC a 0 0 ; PCC grave 56 0 ;
-CC aring 2 ; PCC a 0 0 ; PCC ring 56 0 ;
-CC atilde 2 ; PCC a 0 0 ; PCC tilde 56 0 ;
-CC ccedilla 2 ; PCC c 0 0 ; PCC cedilla 56 0 ;
-CC eacute 2 ; PCC e 0 0 ; PCC acute 56 0 ;
-CC ecircumflex 2 ; PCC e 0 0 ; PCC circumflex 56 0 ;
-CC edieresis 2 ; PCC e 0 0 ; PCC dieresis 56 0 ;
-CC egrave 2 ; PCC e 0 0 ; PCC grave 56 0 ;
-CC iacute 2 ; PCC dotlessi 0 0 ; PCC acute -27 0 ;
-CC icircumflex 2 ; PCC dotlessi 0 0 ; PCC circumflex -27 0 ;
-CC idieresis 2 ; PCC dotlessi 0 0 ; PCC dieresis -27 0 ;
-CC igrave 2 ; PCC dotlessi 0 0 ; PCC grave -27 0 ;
-CC ntilde 2 ; PCC n 0 0 ; PCC tilde 84 0 ;
-CC oacute 2 ; PCC o 0 0 ; PCC acute 84 0 ;
-CC ocircumflex 2 ; PCC o 0 0 ; PCC circumflex 84 0 ;
-CC odieresis 2 ; PCC o 0 0 ; PCC dieresis 84 0 ;
-CC ograve 2 ; PCC o 0 0 ; PCC grave 84 0 ;
-CC otilde 2 ; PCC o 0 0 ; PCC tilde 84 0 ;
-CC scaron 2 ; PCC s 0 0 ; PCC caron 28 0 ;
-CC uacute 2 ; PCC u 0 0 ; PCC acute 84 0 ;
-CC ucircumflex 2 ; PCC u 0 0 ; PCC circumflex 84 0 ;
-CC udieresis 2 ; PCC u 0 0 ; PCC dieresis 84 0 ;
-CC ugrave 2 ; PCC u 0 0 ; PCC grave 84 0 ;
-CC yacute 2 ; PCC y 0 0 ; PCC acute 84 0 ;
-CC ydieresis 2 ; PCC y 0 0 ; PCC dieresis 84 0 ;
-CC zcaron 2 ; PCC z 0 0 ; PCC caron 56 0 ;
-EndComposites
-EndFontMetrics
dnl Initialize.
AC_PREREQ(2.60)
-AC_INIT([pspp],[0.7.2],[bug-gnu-pspp@gnu.org])
+AC_INIT([pspp],[0.7.3],[bug-gnu-pspp@gnu.org])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE
AC_SYS_LARGEFILE
AC_SEARCH_LIBS([sin], [m])
AC_SEARCH_LIBS([dcgettext], [intl])
-PSPP_LIBPLOT
PSPP_LC_PAPER
-AM_CONDITIONAL(WITHCHARTS, test x"$with_libplot" != x"no")
AC_ARG_VAR([PSPP_LDFLAGS], [linker flags to be used for linking the pspp binary only])
AC_ARG_VAR([PSPPIRE_LDFLAGS], [linker flags to be used for linking the psppire binary only])
-
-AC_ARG_WITH(
- gui,
- [AS_HELP_STRING([--without-gui], [don't build the PSPPIRE gui])])
-
-required_gtk_version=2.12
-
-if test x"$with_gui" != x"no" ; then
- PKG_CHECK_MODULES(GTK, gtk+-2.0 >= $required_gtk_version,,
- [PSPP_REQUIRED_PREREQ([gtk+ 2.0 v$required_gtk_version or later (or use --without-gui)])])
+# Support for Cairo and Pango.
+AC_ARG_WITH([cairo],
+ [AS_HELP_STRING(
+ [--without-cairo],
+ [Don't build support for charts (using Cairo and Pango);
+ implies --without-gui])],
+ [], [with_cairo=yes])
+AM_CONDITIONAL([HAVE_CAIRO], [test "$with_cairo" != no])
+if test "$with_cairo" != no; then
+ PKG_CHECK_MODULES([CAIRO], [cairo >= 1.5 pango >= 1.20 pangocairo],
+ [CPPFLAGS="$CPPFLAGS $CAIRO_CFLAGS"
+ AC_DEFINE([HAVE_CAIRO], 1,
+ [Define to 1 if Cairo and Pango are available.])],
+ [PSPP_REQUIRED_PREREQ([cairo 1.5 or later and pango 1.20 or later (or use --without-cairo)])])
fi
-AM_CONDITIONAL(WITHGUI, test x"$with_gui" != x"no")
+# Support for GUI.
+AC_ARG_WITH([gui],
+ [AS_HELP_STRING([--without-gui],
+ [Don't build the PSPPIRE GUI (using GTK+)])],
+ [], [with_gui=yes])
+AM_CONDITIONAL([HAVE_GUI],
+ [test "$with_cairo" != no && test "$with_gui" != "no"])
+if test "$with_cairo" != no && test "$with_gui" != "no"; then
+ PKG_CHECK_MODULES([GTK], [gtk+-2.0 >= 2.12], [],
+ [PSPP_REQUIRED_PREREQ([gtk+ 2.0 version 2.12 or later (or use --without-gui)])])
+fi
dnl Checks needed for psql reader
* Configuration files:: How configuration files are read.
* Environment variables:: All about environment variables.
* Output devices:: Describing your terminal(s) and printer(s).
-* PostScript driver class:: Configuration of PostScript devices.
+* Cairo driver class:: Configuration of Cairo devices.
* ASCII driver class:: Configuration of character-code devices.
* HTML driver class:: Configuration for HTML output.
* Miscellaneous configuring:: Even more configuration variables.
@item class name
One of the predefined driver classes supported by PSPP. The
-currently supported driver classes include `postscript' and `ascii'.
+currently supported driver classes include `cairo' and `ascii'.
@item device type(s)
Zero or more of the following keywords, delimited by spaces:
Tokens, outside of quoted strings, are delimited by white space or equals
signs.
-@node PostScript driver class
-@section The PostScript driver class
+@node Cairo driver class
+@section The Cairo driver class
-The @code{postscript} driver class is used to produce output that is
-acceptable to PostScript printers and other interpreters.
+The @code{cairo} driver class can produce output in PDF, PostScript,
+and SVG formats. It has full support for international character
+sets.
+
+The Cairo driver is only available if your copy of PSPP was built with
+the Cairo library.
The available options are listed below.
@table @code
@item output-file=@var{file-name}
-File to which output should be sent. This can be an ordinary file name
-(i.e., @code{"pspp.ps"}), a pipe (i.e., @code{"|lpr"}), or
-stdout (@code{"-"}). Default: @code{"pspp.ps"}.
+File to which output should be sent. Default: @code{"pspp.pdf"}.
-@item headers=@var{boolean}
+@item output-type=@var{output-type}
-Controls whether the standard headers showing the time and date and
-title and subtitle are printed at the top of each page. Default:
-@code{on}.
+Type of output to write to the output file, one of @code{pdf},
+@code{ps}, or @code{svg}. Default: @code{pdf}.
@item paper-size=@var{paper-size}
Either @code{portrait} or @code{landscape}. Default: @code{portrait}.
+@item headers=@var{boolean}
+
+Controls whether the standard headers showing the time and date and
+title and subtitle are printed at the top of each page. Default:
+@code{on}.
+
@item left-margin=@var{dimension}
@itemx right-margin=@var{dimension}
@itemx top-margin=@var{dimension}
included in the margins; they are in addition to the margins. For a
description of dimensions, see @ref{Dimensions}. Default: @code{0.5in}.
-@item prop-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
-@itemx emph-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
-@itemx fixed-font=@var{afm-file}[,@var{font-file}[,@var{encoding-file}]]
+@item prop-font=@var{font-name}
+@itemx emph-font=@var{font-name}
+@itemx fixed-font=@var{font-name}
Sets the font used for proportional, emphasized, or fixed-pitch text.
-The only required value is @var{afm-file}, the AFM file for the font.
-
-If specified, @var{font-file} will be downloaded to the printer at the
-beginning of the print job. The font file may be in PFA or PFB format.
-
-The font is reencoded as specified in @var{encoding-file}, if specified.
-Each line in @var{encoding-file} should consist of a PostScript
-character name and a decimal encoding value (between 0 and 255),
-separated by white space. Blank lines and comments introduced by
-@samp{#} are also allowed.
-
-The files specified on these options are located as follows. If
-the file name begins with @samp{/}, then it is taken as an absolute
-path. Otherwise, PSPP searches its configuration path for the specified
-name prefixed by @code{psfonts/} (@pxref{File locations}).
+Most systems support CSS-like font names such as ``serif'' and
+``monospace'', but a wide range of system-specific font are likely to
+be supported as well.
-Default: proportional font @code{Times-Roman.afm}, emphasis font
-@code{Times-Italic.afm}, fixed-pitch font @code{Courier.afm}.
+Default: proportional font @code{serif}, emphasis font @code{serif
+italic}, fixed-pitch font @code{monospace}.
@item font-size=@var{font-size}
@file{"pspp-#.png"}.
@item chart-type=@var{type}.
-Type of charts to output. Available types typically include @samp{X},
-@samp{png}, @samp{gif}, @samp{svg}, @samp{ps}, @samp{cgm}, @samp{fig},
-@samp{pcl}, @samp{hpgl}, @samp{regis}, @samp{tek}, and @samp{meta}.
+Type of charts to output, either @samp{png} or @samp{none}.
Default: @samp{png}.
-You may specify @samp{none} to disable chart output. Charts are also
-disabled if your installation of PSPP was compiled without
-@code{libplot}.
+Charts are always disabled if your installation of PSPP was compiled
+without the @code{cairo} library.
@item paginate=@var{boolean}
include $(top_srcdir)/lib/linreg/automake.mk
-if WITHGUI
+if HAVE_GUI
include $(top_srcdir)/lib/gtk-contrib/automake.mk
endif
=cut
BEGIN {
- $PSPP::VERSION='0.7.2';
+ $PSPP::VERSION='0.7.3';
require XSLoader;
XSLoader::load('PSPP', $PSPP::VERSION);
}
src/data/caseinit.c \
src/data/caseinit.h \
src/data/casereader-filter.c \
+ src/data/casereader-project.c \
src/data/casereader-provider.h \
+ src/data/casereader-select.c \
src/data/casereader-translator.c \
src/data/casereader.c \
src/data/casereader.h \
void
caseproto_refresh_long_string_cache__ (const struct caseproto *proto_)
{
- struct caseproto *proto = (struct caseproto *) proto_;
+ struct caseproto *proto = CONST_CAST (struct caseproto *, proto_);
size_t n, i;
assert (proto->long_strings == NULL);
#include <stddef.h>
#include <stdlib.h>
#include <data/value.h>
+#include <libpspp/cast.h>
#include <libpspp/compiler.h>
/* Case prototype.
static inline struct caseproto *
caseproto_ref (const struct caseproto *proto_)
{
- struct caseproto *proto = (struct caseproto *) proto_;
+ struct caseproto *proto = CONST_CAST (struct caseproto *, proto_);
proto->ref_cnt++;
return proto;
}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <data/casereader-provider.h>
+#include <data/subcase.h>
+
+#include "gl/xalloc.h"
+
+static bool
+projection_is_no_op (const struct casereader *reader, const struct subcase *sc)
+{
+ size_t n = subcase_get_n_fields (sc);
+ size_t i;
+
+ if (n != caseproto_get_n_widths (casereader_get_proto (reader)))
+ return false;
+
+ for (i = 0; i < n; i++)
+ if (subcase_get_case_index (sc, i) != i)
+ return false;
+
+ return true;
+}
+
+struct casereader_project
+ {
+ struct subcase old_sc;
+ struct subcase new_sc;
+ };
+
+static struct ccase *
+project_case (struct ccase *old, casenumber idx UNUSED, const void *project_)
+{
+ const struct casereader_project *project = project_;
+ struct ccase *new = case_create (subcase_get_proto (&project->new_sc));
+ subcase_copy (&project->old_sc, old, &project->new_sc, new);
+ case_unref (old);
+ return new;
+}
+
+static bool
+destroy_projection (void *project_)
+{
+ struct casereader_project *project = project_;
+ subcase_destroy (&project->old_sc);
+ subcase_destroy (&project->new_sc);
+ free (project);
+ return true;
+}
+
+/* Returns a casereader in which each row is obtained by extracting the subcase
+ SC from the corresponding row of SUBREADER. */
+struct casereader *
+casereader_project (struct casereader *subreader, const struct subcase *sc)
+{
+ if (projection_is_no_op (subreader, sc))
+ return casereader_rename (subreader);
+ else
+ {
+ struct casereader_project *project = xmalloc (sizeof *project);
+ const struct caseproto *proto;
+
+ subcase_clone (&project->old_sc, sc);
+ proto = subcase_get_proto (&project->old_sc);
+
+ subcase_init_empty (&project->new_sc);
+ subcase_add_proto_always (&project->new_sc, proto);
+
+ return casereader_translate_stateless (subreader, proto,
+ project_case, destroy_projection,
+ project);
+ }
+}
+
+/* Returns a casereader in which each row is obtained by extracting the value
+ with index COLUMN from the corresponding row of SUBREADER. */
+struct casereader *
+casereader_project_1 (struct casereader *subreader, int column)
+{
+ const struct caseproto *subproto = casereader_get_proto (subreader);
+ struct casereader *reader;
+ struct subcase sc;
+
+ subcase_init (&sc, column, caseproto_get_width (subproto, column),
+ SC_ASCEND);
+ reader = casereader_project (subreader, &sc);
+ subcase_destroy (&sc);
+
+ return reader;
+}
+
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <data/casereader-provider.h>
+
+#include "gl/xalloc.h"
+
+struct casereader_select
+ {
+ casenumber by;
+ casenumber i;
+ };
+
+static bool
+casereader_select_include (const struct ccase *c UNUSED, void *cs_)
+{
+ struct casereader_select *cs = cs_;
+ if (++cs->i >= cs->by)
+ {
+ cs->i = 0;
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool
+casereader_select_destroy (void *cs_)
+{
+ struct casereader_select *cs = cs_;
+ free (cs);
+ return true;
+}
+
+/* Returns a casereader that contains cases FIRST though LAST, exclusive, of
+ those within SUBREADER. (The first case in SUBREADER is number 0.) If BY
+ is greater than 1, then it specifies a step between cases, e.g. a BY value
+ of 2 causes the cases numbered FIRST + 1, FIRST + 3, FIRST + 5, and so on
+ to be omitted.
+
+ The caller gives up ownership of SUBREADER, transferring it into this
+ function. */
+struct casereader *
+casereader_select (struct casereader *subreader,
+ casenumber first, casenumber last, casenumber by)
+{
+ if (by == 0)
+ by = 1;
+
+ casereader_advance (subreader, first);
+ if (last >= first)
+ casereader_truncate (subreader, (last - first) / by * by);
+
+ if (by == 1)
+ return casereader_rename (subreader);
+ else
+ {
+ struct casereader_select *cs = xmalloc (sizeof *cs);
+ cs->by = by;
+ cs->i = 0;
+ return casereader_create_filter_func (subreader,
+ casereader_select_include,
+ casereader_select_destroy,
+ cs, NULL);
+ }
+}
INPUT and auxiliary data AUX. TRANSLATE must destroy its
input case.
+ TRANSLATE may be stateful, that is, the output for a given
+ case may depend on previous cases. If TRANSLATE is stateless,
+ then you may want to use casereader_translate_stateless
+ instead, since it sometimes performs better.
+
The cases returned by TRANSLATE must match OUTPUT_PROTO.
When the translating casereader is destroyed, DESTROY will be
NULL,
NULL,
};
+\f
+/* Casereader that applies a user-supplied function to translate
+ each case into another in a stateless fashion. */
+
+/* A statelessly translating casereader. */
+struct casereader_stateless_translator
+ {
+ struct casereader *subreader; /* Source of input cases. */
+
+ casenumber case_offset;
+ struct ccase *(*translate) (struct ccase *input, casenumber,
+ const void *aux);
+ bool (*destroy) (void *aux);
+ void *aux;
+ };
+
+static const struct casereader_random_class
+casereader_stateless_translator_class;
+
+/* Creates and returns a new casereader whose cases are produced by reading
+ from SUBREADER and passing through the TRANSLATE function. TRANSLATE must
+ takes ownership of its input case and returns a translated case, populating
+ the translated case based on INPUT and auxiliary data AUX.
+
+ TRANSLATE must be stateless, that is, the output for a given case must not
+ depend on previous cases. This is because cases may be retrieved in
+ arbitrary order, and some cases may be retrieved multiple times, and some
+ cases may be skipped and never retrieved at all. If TRANSLATE is stateful,
+ use casereader_create_translator instead.
+
+ The casenumber argument to the TRANSLATE function is the absolute case
+ number in SUBREADER, that is, 0 when the first case in SUBREADER is being
+ translated, 1 when the second case is being translated, and so on.
+
+ The cases returned by TRANSLATE must match OUTPUT_PROTO.
+
+ When the stateless translating casereader is destroyed, DESTROY will be
+ called to allow any auxiliary data maintained by TRANSLATE to be freed.
+
+ After this function is called, SUBREADER must not ever again be referenced
+ directly. It will be destroyed automatically when the translating
+ casereader is destroyed. */
+struct casereader *
+casereader_translate_stateless (
+ struct casereader *subreader,
+ const struct caseproto *output_proto,
+ struct ccase *(*translate) (struct ccase *input, casenumber,
+ const void *aux),
+ bool (*destroy) (void *aux),
+ void *aux)
+{
+ struct casereader_stateless_translator *cst = xmalloc (sizeof *cst);
+ struct casereader *reader;
+ cst->subreader = casereader_rename (subreader);
+ cst->translate = translate;
+ cst->destroy = destroy;
+ cst->aux = aux;
+ reader = casereader_create_random (
+ output_proto, casereader_get_case_cnt (cst->subreader),
+ &casereader_stateless_translator_class, cst);
+ taint_propagate (casereader_get_taint (cst->subreader),
+ casereader_get_taint (reader));
+ return reader;
+}
+
+/* Internal read function for stateless translating casereader. */
+static struct ccase *
+casereader_stateless_translator_read (struct casereader *reader UNUSED,
+ void *cst_, casenumber idx)
+{
+ struct casereader_stateless_translator *cst = cst_;
+ struct ccase *tmp = casereader_peek (cst->subreader, idx);
+ if (tmp != NULL)
+ tmp = cst->translate (tmp, cst->case_offset + idx, cst->aux);
+ return tmp;
+}
+
+/* Internal destroy function for translating casereader. */
+static void
+casereader_stateless_translator_destroy (struct casereader *reader UNUSED,
+ void *cst_)
+{
+ struct casereader_stateless_translator *cst = cst_;
+ casereader_destroy (cst->subreader);
+ cst->destroy (cst->aux);
+ free (cst);
+}
+
+static void
+casereader_stateless_translator_advance (struct casereader *reader UNUSED,
+ void *cst_, casenumber cnt)
+{
+ struct casereader_stateless_translator *cst = cst_;
+ cst->case_offset += casereader_advance (cst->subreader, cnt);
+}
+/* Casereader class for stateless translating casereader. */
+static const struct casereader_random_class
+casereader_stateless_translator_class =
+ {
+ casereader_stateless_translator_read,
+ casereader_stateless_translator_destroy,
+ casereader_stateless_translator_advance,
+ };
\f
struct casereader_append_numeric
struct casereader *
casereader_clone (const struct casereader *reader_)
{
- struct casereader *reader = (struct casereader *) reader_;
+ struct casereader *reader = CONST_CAST (struct casereader *, reader_);
struct casereader *clone;
if ( reader == NULL )
return NULL;
return reader->case_cnt;
}
+static casenumber
+casereader_count_cases__ (struct casereader *reader, casenumber max_cases)
+{
+ struct casereader *clone;
+ casenumber n_cases;
+
+ clone = casereader_clone (reader);
+ n_cases = casereader_advance (clone, max_cases);
+ casereader_destroy (clone);
+
+ return n_cases;
+}
+
/* Returns the number of cases that will be read by successive
calls to casereader_read for READER, assuming that no errors
occur. Upon an error condition, the case count drops to 0, so
casereader_count_cases (struct casereader *reader)
{
if (reader->case_cnt == CASENUMBER_MAX)
- {
- casenumber n_cases = 0;
- struct ccase *c;
-
- struct casereader *clone = casereader_clone (reader);
-
- for (; (c = casereader_read (clone)) != NULL; case_unref (c))
- n_cases++;
-
- casereader_destroy (clone);
- reader->case_cnt = n_cases;
- }
-
+ reader->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX);
return reader->case_cnt;
}
+/* Truncates READER to at most N cases. */
+void
+casereader_truncate (struct casereader *reader, casenumber n)
+{
+ /* This could be optimized, if it ever becomes too expensive, by adding a
+ "max_cases" member to struct casereader. We could also add a "truncate"
+ function to the casereader implementation, to allow the casereader to
+ throw away data that cannot ever be read. */
+ if (reader->case_cnt == CASENUMBER_MAX)
+ reader->case_cnt = casereader_count_cases__ (reader, n);
+ if (reader->case_cnt > n)
+ reader->case_cnt = n;
+}
+
/* Returns the prototype for the cases in READER. The caller
must not unref the returned prototype. */
const struct caseproto *
return reader->proto;
}
+/* Skips past N cases in READER, stopping when the last case in
+ READER has been read or on an input error. Returns the number
+ of cases successfully skipped. */
+casenumber
+casereader_advance (struct casereader *reader, casenumber n)
+{
+ casenumber i;
+
+ for (i = 0; i < n; i++)
+ {
+ struct ccase *c = casereader_read (reader);
+ if (c == NULL)
+ break;
+ case_unref (c);
+ }
+
+ return i;
+}
+
+
/* Copies all the cases in READER to WRITER, propagating errors
appropriately. */
void
shim_destroy,
shim_advance,
};
+\f
+static const struct casereader_class casereader_null_class;
+
+/* Returns a casereader with no cases. The casereader has the prototype
+ specified by PROTO. PROTO may be specified as a null pointer, in which case
+ the casereader has no variables. */
+struct casereader *
+casereader_create_empty (const struct caseproto *proto_)
+{
+ struct casereader *reader;
+ struct caseproto *proto;
+
+ proto = proto_ != NULL ? caseproto_ref (proto_) : caseproto_create ();
+ reader = casereader_create_sequential (NULL, proto, 0,
+ &casereader_null_class, NULL);
+ caseproto_unref (proto);
+
+ return reader;
+}
+
+static struct ccase *
+casereader_null_read (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+ return NULL;
+}
+
+static void
+casereader_null_destroy (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+ /* Nothing to do. */
+}
+
+static const struct casereader_class casereader_null_class =
+ {
+ casereader_null_read,
+ casereader_null_destroy,
+ NULL, /* clone */
+ NULL, /* peek */
+ };
struct dictionary;
struct casereader;
struct casewriter;
+struct subcase;
struct ccase *casereader_read (struct casereader *);
bool casereader_destroy (struct casereader *);
casenumber casereader_get_case_cnt (struct casereader *);
casenumber casereader_count_cases (struct casereader *);
+void casereader_truncate (struct casereader *, casenumber);
const struct caseproto *casereader_get_proto (const struct casereader *);
+casenumber casereader_advance (struct casereader *, casenumber);
void casereader_transfer (struct casereader *, struct casewriter *);
\f
+struct casereader *casereader_create_empty (const struct caseproto *);
+
struct casereader *
casereader_create_filter_func (struct casereader *,
bool (*include) (const struct ccase *,
bool (*destroy) (void *aux),
void *aux);
+struct casereader *
+casereader_translate_stateless (struct casereader *,
+ const struct caseproto *output_proto,
+ struct ccase *(*translate) (struct ccase *,
+ casenumber idx,
+ const void *aux),
+ bool (*destroy) (void *aux),
+ void *aux);
+
+struct casereader *casereader_project (struct casereader *,
+ const struct subcase *);
+struct casereader *casereader_project_1 (struct casereader *, int column);
+struct casereader *casereader_select (struct casereader *,
+ casenumber first, casenumber last,
+ casenumber by);
+
/* A function which creates a numberic value from an existing case */
typedef double new_value_func (const struct ccase *, casenumber, void *);
struct ccase *
casewindow_get_case (const struct casewindow *cw_, casenumber case_idx)
{
- struct casewindow *cw = (struct casewindow *) cw_;
+ struct casewindow *cw = CONST_CAST (struct casewindow *, cw_);
assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
if (casewindow_error (cw))
const struct caseproto *
datasheet_get_proto (const struct datasheet *ds_)
{
- struct datasheet *ds = (struct datasheet *) ds_;
+ struct datasheet *ds = CONST_CAST (struct datasheet *, ds_);
if (ds->proto == NULL)
{
size_t i;
{
size_t n_columns = datasheet_get_n_columns (ds);
struct ccase *c = case_create (datasheet_get_proto (ds));
- if (rw_case ((struct datasheet *) ds, OP_READ,
+ if (rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
row, 0, n_columns, case_data_all_rw (c)))
return c;
else
size_t column, union value *value)
{
assert (row >= 0);
- return rw_case ((struct datasheet *) ds, OP_READ, row, column, 1, value);
+ return rw_case (CONST_CAST (struct datasheet *, ds), OP_READ,
+ row, column, 1, value);
}
/* Stores VALUE into DS in the given ROW and COLUMN. VALUE must
const struct caseproto *
dict_get_proto (const struct dictionary *d_)
{
- struct dictionary *d = (struct dictionary *) d_;
+ struct dictionary *d = CONST_CAST (struct dictionary *, d_);
if (d->proto == NULL)
{
size_t i;
struct attrset *
dict_get_attributes (const struct dictionary *d)
{
- return (struct attrset *) &d->attributes;
+ return CONST_CAST (struct attrset *, &d->attributes);
}
/* Replaces D's attributes set by a copy of ATTRS. */
/* Functions for performing operations on file names. */
-/* Substitutes $variables in SRC, putting the result in DST,
- properly handling the case where SRC is a substring of DST.
- Variables are as defined by GETENV. Supports $var and ${var}
- syntaxes; $$ substitutes as $. */
+/* Copies from SRC to DST, calling INSERT_VARIABLE to handle each
+ instance of $var or ${var} in SRC. $$ is replaced by $. */
void
-fn_interp_vars (struct substring src, const char *(*getenv) (const char *),
- struct string *dst_)
+fn_interp_vars (struct substring src,
+ void (*insert_variable) (const char *var,
+ struct string *dst, void *aux),
+ void *aux, struct string *dst_)
{
struct string dst = DS_EMPTY_INITIALIZER;
int c;
else
{
struct substring var_name;
- size_t start;
- const char *value;
+ char *var;
if (ss_match_char (&src, '('))
ss_get_until (&src, ')', &var_name);
ss_get_chars (&src, MAX (1, ss_span (src, ss_cstr (CC_ALNUM))),
&var_name);
- start = ds_length (&dst);
- ds_put_substring (&dst, var_name);
- value = getenv (ds_cstr (&dst) + start);
- ds_truncate (&dst, start);
-
- ds_put_cstr (&dst, value);
+ var = ss_xstrdup (var_name);
+ insert_variable (var, &dst, aux);
+ free (var);
}
}
ds_destroy (&dst);
}
+static void
+insert_env_var (const char *var, struct string *dst, void *aux UNUSED)
+{
+ const char *value = fn_getenv (var);
+ if (value != NULL)
+ ds_put_cstr (dst, value);
+}
+
/* Searches for a configuration file with name NAME in the path
given by PATH, which is environment-interpolated.
Directories in PATH are delimited by ':'. Returns the
/* Interpolate environment variables. */
ds_init_cstr (&path, path_);
- fn_interp_vars (ds_ss (&path), fn_getenv, &path);
+ fn_interp_vars (ds_ss (&path), insert_env_var, NULL, &path);
verbose_msg (2, _("searching for \"%s\" in path \"%s\""),
base_name, ds_cstr (&path));
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
void fn_init (void);
void fn_interp_vars (struct substring src,
- const char *(*getenv) (const char *),
- struct string *dst);
+ void (*insert_variable) (const char *var,
+ struct string *dst, void *aux),
+ void *aux, struct string *dst);
char *fn_search_path (const char *base_name, const char *path);
char *fn_dir_name (const char *fn);
char *fn_extension (const char *fn);
else
{
const struct taint *taint = casereader_get_taint (ds->source);
- taint_reset_successor_taint ((struct taint *) taint);
+ taint_reset_successor_taint (CONST_CAST (struct taint *, taint));
assert (!taint_has_tainted_successor (taint));
}
}
caseproto_unref (sc->proto);
}
+/* Returns true if VAR already has a field in SC,
+ false otherwise. */
+bool
+subcase_contains_var (const struct subcase *sc, const struct variable *var)
+{
+ return subcase_contains (sc, var_get_case_index (var));
+}
+
+/* Returns true if CASE_INDEX already has a field in SC,
+ false otherwise. */
+bool
+subcase_contains (const struct subcase *sc, int case_index)
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ if (sc->fields[i].case_index == case_index)
+ return true;
+
+ return false;
+}
/* Add a field for VAR to SC, with DIRECTION as the sort order.
Returns true if successful, false if VAR already has a field
subcase_add_var (struct subcase *sc, const struct variable *var,
enum subcase_direction direction)
{
- return subcase_add (sc, var_get_case_index (var),
- var_get_width (var), direction);
+ if (!subcase_contains_var (sc, var))
+ {
+ subcase_add_var_always (sc, var, direction);
+ return true;
+ }
+ else
+ return false;
}
/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the sort order.
in SC. */
bool
subcase_add (struct subcase *sc, int case_index, int width,
- enum subcase_direction direction)
+ enum subcase_direction direction)
{
- struct subcase_field *field;
- size_t i;
+ if (!subcase_contains (sc, case_index))
+ {
+ subcase_add_always (sc, case_index, width, direction);
+ return true;
+ }
+ else
+ return false;
+}
- for (i = 0; i < sc->n_fields; i++)
- if (sc->fields[i].case_index == case_index)
- return false;
+/* Add a field for VAR to SC, with DIRECTION as the sort order,
+ regardless of whether VAR already has a field in SC. */
+void
+subcase_add_var_always (struct subcase *sc, const struct variable *var,
+ enum subcase_direction direction)
+{
+ return subcase_add_always (sc, var_get_case_index (var),
+ var_get_width (var), direction);
+}
+
+/* Add a field for CASE_INDEX, WIDTH to SC, with DIRECTION as the
+ sort order, regardless of whether CASE_INDEX already has a
+ field in SC. */
+void
+subcase_add_always (struct subcase *sc, int case_index, int width,
+ enum subcase_direction direction)
+{
+ struct subcase_field *field;
sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
field = &sc->fields[sc->n_fields++];
field->width = width;
field->direction = direction;
invalidate_proto (sc);
- return true;
+}
+
+/* Adds a field to SC for each column in PROTO, so that SC
+ contains all of the columns in PROTO in the same order as a
+ case conforming to PROTO. The fields are added with
+ ascending direction. */
+void
+subcase_add_proto_always (struct subcase *sc, const struct caseproto *proto)
+{
+ size_t n = caseproto_get_n_widths (proto);
+ size_t i;
+
+ sc->fields = xnrealloc (sc->fields, sc->n_fields + n, sizeof *sc->fields);
+ for (i = 0; i < n; i++)
+ {
+ struct subcase_field *field = &sc->fields[sc->n_fields++];
+ field->case_index = i;
+ field->width = caseproto_get_width (proto, i);
+ field->direction = SC_ASCEND;
+ }
+ invalidate_proto (sc);
}
/* Obtains a caseproto for a case described by SC. The caller
const struct caseproto *
subcase_get_proto (const struct subcase *sc_)
{
- struct subcase *sc = (struct subcase *) sc_;
+ struct subcase *sc = CONST_CAST (struct subcase *, sc_);
if (sc->proto == NULL)
{
void subcase_clear (struct subcase *);
void subcase_destroy (struct subcase *);
-bool subcase_add (struct subcase *sc, int index, int width,
- enum subcase_direction direction);
+bool subcase_contains (const struct subcase *, int case_index);
+bool subcase_contains_var (const struct subcase *, const struct variable *);
+bool subcase_add (struct subcase *, int case_index, int width,
+ enum subcase_direction direction);
bool subcase_add_var (struct subcase *, const struct variable *,
enum subcase_direction);
+void subcase_add_always (struct subcase *sc, int case_index, int width,
+ enum subcase_direction direction);
+void subcase_add_var_always (struct subcase *, const struct variable *,
+ enum subcase_direction);
+void subcase_add_proto_always (struct subcase *, const struct caseproto *);
+
const struct caseproto *subcase_get_proto (const struct subcase *);
static inline bool subcase_is_empty (const struct subcase *);
static inline size_t subcase_get_n_fields (const struct subcase *);
+static inline size_t subcase_get_case_index (const struct subcase *,
+ size_t idx);
static inline enum subcase_direction subcase_get_direction (
const struct subcase *, size_t idx);
bool subcase_equal_xx (const struct subcase *,
const union value *a, const union value *b);
+static inline size_t
+subcase_get_case_index (const struct subcase *sc, size_t idx)
+{
+ return sc->fields[idx].case_index;
+}
+
static inline enum subcase_direction
subcase_get_direction (const struct subcase *sc, size_t idx)
{
#include <data/value.h>
#include <data/variable.h>
#include <libpspp/array.h>
+#include <libpspp/cast.h>
#include <libpspp/compiler.h>
#include <libpspp/hash-functions.h>
#include <libpspp/hmap.h>
val_labs_replace (struct val_labs *vls, const union value *value,
const char *label)
{
- struct val_lab *vl = (struct val_lab *) val_labs_lookup (vls, value);
+ struct val_lab *vl = val_labs_lookup (vls, value);
if (vl != NULL)
{
atom_destroy (vl->label);
/* Removes LABEL from VLS. */
void
-val_labs_remove (struct val_labs *vls, const struct val_lab *label_)
+val_labs_remove (struct val_labs *vls, struct val_lab *label)
{
- struct val_lab *label = (struct val_lab *) label_;
hmap_delete (&vls->labels, &label->node);
value_destroy (&label->value, vls->width);
atom_destroy (label->label);
/* Searches VLS for a value label for VALUE. If successful,
returns the value label; otherwise, returns a null pointer.
Returns a null pointer if VLS is null. */
-const struct val_lab *
+struct val_lab *
val_labs_lookup (const struct val_labs *vls, const union value *value)
{
if (vls != NULL)
/* Looking up value labels. */
const char *val_labs_find (const struct val_labs *, const union value *);
-const struct val_lab *val_labs_lookup (const struct val_labs *,
+struct val_lab *val_labs_lookup (const struct val_labs *,
const union value *);
/* Basic properties. */
/* Adding value labels. */
bool val_labs_add (struct val_labs *, const union value *, const char *);
void val_labs_replace (struct val_labs *, const union value *, const char *);
-void val_labs_remove (struct val_labs *, const struct val_lab *);
+void val_labs_remove (struct val_labs *, struct val_lab *);
/* Iterating through value labels. */
const struct val_lab *val_labs_first (const struct val_labs *);
var_attach_aux (const struct variable *v_,
void *aux, void (*aux_dtor) (struct variable *))
{
- struct variable *v = (struct variable *) v_ ; /* cast away const */
+ struct variable *v = CONST_CAST (struct variable *, v_);
assert (v->aux == NULL);
assert (aux != NULL);
v->aux = aux;
void
var_set_obs_vals (const struct variable *v_, struct cat_vals *cat_vals)
{
- struct variable *v = (struct variable *) v_ ; /* cast away const */
+ struct variable *v = CONST_CAST (struct variable *, v_ );
cat_stored_values_destroy (v->obs_vals);
v->obs_vals = cat_vals;
}
struct attrset *
var_get_attributes (const struct variable *v)
{
- return (struct attrset *) &v->attributes;
+ return CONST_CAST (struct attrset *, &v->attributes);
}
/* Replaces variable V's attributes set by a copy of ATTRS. */
noinst_LTLIBRARIES += src/language/liblanguage.la
-src_language_liblanguage_la_LIBADD = \
- src/output/charts/libcharts.la
-
src_language_liblanguage_la_SOURCES = \
src/language/syntax-file.c \
src/language/syntax-file.h \
#include <libpspp/message.h>
#include <libpspp/str.h>
#include <output/manager.h>
-#include <output/table.h>
#include <libpspp/getl.h>
#if HAVE_SYS_WAIT_H
/* Execute command. */
msg_set_command_name (command->name);
- tab_set_command_name (command->name);
+ som_set_command_name (command->name);
result = command->function (lexer, ds);
- tab_set_command_name (NULL);
+ som_set_command_name (NULL);
msg_set_command_name (NULL);
assert (cmd_result_is_valid (result));
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <language/command.h>
#include <language/lexer/lexer.h>
#include <language/lexer/variable-parser.h>
+#include <libpspp/cast.h>
#include <libpspp/ll.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
/* Makes appropriate DO REPEAT macro substitutions within the
repeated lines. */
static void
-do_repeat_filter (struct getl_interface *block_,
- struct string *line)
+do_repeat_filter (struct getl_interface *interface, struct string *line)
{
- struct repeat_block *block = (struct repeat_block *) block_;
+ struct repeat_block *block
+ = UP_CAST (interface, struct repeat_block, parent);
bool in_apos, in_quote, dot;
struct substring input;
struct string output;
static struct repeat_line *
current_line (const struct getl_interface *interface)
{
- struct repeat_block *block = (struct repeat_block *) interface;
+ struct repeat_block *block
+ = UP_CAST (interface, struct repeat_block, parent);
return (block->cur_line != ll_null (&block->lines)
? ll_data (block->cur_line, struct repeat_line, ll)
: NULL);
do_repeat_read (struct getl_interface *interface,
struct string *output)
{
- struct repeat_block *block = (struct repeat_block *) interface;
+ struct repeat_block *block
+ = UP_CAST (interface, struct repeat_block, parent);
struct repeat_line *line;
block->cur_line = ll_next (block->cur_line);
/* Frees a DO REPEAT block.
Called by getl to close out the DO REPEAT block. */
static void
-do_repeat_close (struct getl_interface *block_)
+do_repeat_close (struct getl_interface *interface)
{
- struct repeat_block *block = (struct repeat_block *) block_;
+ struct repeat_block *block
+ = UP_CAST (interface, struct repeat_block, parent);
pool_destroy (block->pool);
}
struct tab_table *t;
size_t i;
- t = tab_create (4, parser->field_cnt + 1, 0);
- tab_columns (t, TAB_COL_DOWN, 1);
+ t = tab_create (4, parser->field_cnt + 1);
+ tab_columns (t, TAB_COL_DOWN);
tab_headers (t, 0, 0, 1, 0);
tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, parser->field_cnt);
tab_hline (t, TAL_2, 0, 3, 1);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
for (i = 0; i < parser->field_cnt; i++)
{
struct tab_table *t;
size_t i;
- t = tab_create (2, parser->field_cnt + 1, 0);
- tab_columns (t, TAB_COL_DOWN, 1);
+ t = tab_create (2, parser->field_cnt + 1);
+ tab_columns (t, TAB_COL_DOWN);
tab_headers (t, 0, 0, 1, 0);
tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Variable"));
tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Format"));
tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, parser->field_cnt);
tab_hline (t, TAL_2, 0, 1, 1);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
for (i = 0; i < parser->field_cnt; i++)
{
#include <language/dictionary/split-file.h>
#include <language/lexer/lexer.h>
#include <libpspp/compiler.h>
-#include <libpspp/message.h>
+#include <libpspp/ll.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <output/htmlP.h>
/* (functions) */
/* Layout for one output driver. */
-struct list_ext
+struct list_target
{
+ struct ll ll;
+ struct outp_driver *driver;
int type; /* 0=Values and labels fit across the page. */
size_t n_vertical; /* Number of labels to list vertically. */
size_t header_rows; /* Number of header rows. */
/* Other functions. */
static void list_case (const struct ccase *, casenumber case_idx,
- const struct dataset *);
-static void determine_layout (void);
-static void clean_up (void);
-static void write_header (struct outp_driver *);
-static void write_all_headers (struct casereader *, const struct dataset*);
+ const struct dataset *, struct ll_list *targets);
+static void determine_layout (struct ll_list *targets);
+static void clean_up (struct ll_list *targets);
+static void write_header (struct list_target *);
+static void write_all_headers (struct casereader *, const struct dataset *,
+ struct ll_list *targets);
/* Returns the number of text lines that can fit on the remainder of
the page. */
struct variable *casenum_var = NULL;
struct casegrouper *grouper;
struct casereader *group;
+ struct ll_list targets;
casenumber case_idx;
bool ok;
cmd.v_variables[0] = casenum_var;
}
- determine_layout ();
+ determine_layout (&targets);
case_idx = 0;
for (grouper = casegrouper_create_splits (proc_open (ds), dict);
{
struct ccase *c;
- write_all_headers (group, ds);
+ write_all_headers (group, ds, &targets);
for (; (c = casereader_read (group)) != NULL; case_unref (c))
{
case_idx++;
if (case_idx >= cmd.first && case_idx <= cmd.last
&& (case_idx - cmd.first) % cmd.step == 0)
- list_case (c, case_idx, ds);
+ list_case (c, case_idx, ds, &targets);
}
}
ok = casegrouper_destroy (grouper);
ds_destroy(&line_buffer);
- clean_up ();
+ clean_up (&targets);
var_destroy (casenum_var);
/* Writes headers to all devices. This is done at the beginning of
each SPLIT FILE group. */
static void
-write_all_headers (struct casereader *input, const struct dataset *ds)
+write_all_headers (struct casereader *input, const struct dataset *ds,
+ struct ll_list *targets)
{
- struct outp_driver *d;
+ struct list_target *target;
struct ccase *c;
c = casereader_peek (input, 0);
output_split_file_values (ds, c);
case_unref (c);
- for (d = outp_drivers (NULL); d; d = outp_drivers (d))
+ ll_for_each (target, struct list_target, ll, targets)
{
+ struct outp_driver *d = target->driver;
if (!d->class->special)
{
d->cp_y += d->font_height; /* Blank line. */
- write_header (d);
+ write_header (target);
}
else if (d->class == &html_class)
{
/* Writes the headers. Some of them might be vertical; most are
probably horizontal. */
static void
-write_header (struct outp_driver *d)
+write_header (struct list_target *target)
{
- struct list_ext *prc = d->prc;
+ struct outp_driver *d = target->driver;
- if (!prc->header_rows)
+ if (d->class->special || !target->header_rows)
return;
- if (n_lines_remaining (d) < prc->header_rows + 1)
+ if (n_lines_remaining (d) < target->header_rows + 1)
{
outp_eject_page (d);
- assert (n_lines_remaining (d) >= prc->header_rows + 1);
+ assert (n_lines_remaining (d) >= target->header_rows + 1);
}
/* Design the header. */
- if (!prc->header)
+ if (!target->header)
{
size_t i;
size_t x;
/* Allocate, initialize header. */
- prc->header = xnmalloc (prc->header_rows, sizeof *prc->header);
+ target->header = xnmalloc (target->header_rows, sizeof *target->header);
{
int w = n_chars_width (d);
- for (i = 0; i < prc->header_rows; i++)
+ for (i = 0; i < target->header_rows; i++)
{
- prc->header[i] = xmalloc (w + 1);
- memset (prc->header[i], ' ', w);
+ target->header[i] = xmalloc (w + 1);
+ memset (target->header[i], ' ', w);
}
}
/* Put in vertical names. */
- for (i = x = 0; i < prc->n_vertical; i++)
+ for (i = x = 0; i < target->n_vertical; i++)
{
const struct variable *v = cmd.v_variables[i];
const char *name = var_get_name (v);
const struct fmt_spec *print = var_get_print_format (v);
size_t j;
- memset (&prc->header[prc->header_rows - 1][x], '-', print->w);
+ memset (&target->header[target->header_rows - 1][x], '-', print->w);
x += print->w - 1;
for (j = 0; j < name_len; j++)
- prc->header[name_len - j - 1][x] = name[j];
+ target->header[name_len - j - 1][x] = name[j];
x += 2;
}
size_t name_len = strlen (name);
const struct fmt_spec *print = var_get_print_format (v);
- memset (&prc->header[prc->header_rows - 1][x], '-',
+ memset (&target->header[target->header_rows - 1][x], '-',
MAX (print->w, (int) name_len));
if ((int) name_len < print->w)
x += print->w - name_len;
- memcpy (&prc->header[0][x], name, name_len);
+ memcpy (&target->header[0][x], name, name_len);
x += name_len + 1;
}
/* Add null bytes. */
- for (i = 0; i < prc->header_rows; i++)
+ for (i = 0; i < target->header_rows; i++)
{
for (x = n_chars_width (d); x >= 1; x--)
- if (prc->header[i][x - 1] != ' ')
+ if (target->header[i][x - 1] != ' ')
{
- prc->header[i][x] = 0;
+ target->header[i][x] = 0;
break;
}
assert (x);
}
/* Write out the header, in back-to-front order except for the last line. */
- if (prc->header_rows >= 2)
+ if (target->header_rows >= 2)
{
size_t i;
- for (i = prc->header_rows - 1; i-- != 0; )
- write_line (d, prc->header[i]);
+ for (i = target->header_rows - 1; i-- != 0; )
+ write_line (d, target->header[i]);
}
- write_line (d, prc->header[prc->header_rows - 1]);
+ write_line (d, target->header[target->header_rows - 1]);
}
/* Frees up all the memory we've allocated. */
static void
-clean_up (void)
+clean_up (struct ll_list *targets)
{
- struct outp_driver *d;
+ struct list_target *target, *next;
- for (d = outp_drivers (NULL); d; d = outp_drivers (d))
- if (d->class->special == 0)
- {
- struct list_ext *prc = d->prc;
- size_t i;
-
- if (prc->header)
- {
- for (i = 0; i < prc->header_rows; i++)
- free (prc->header[i]);
- free (prc->header);
- }
- free (prc);
- }
- else if (d->class == &html_class)
- {
- if (d->page_open)
- {
- struct html_driver_ext *x = d->ext;
+ ll_for_each_safe (target, next, struct list_target, ll, targets)
+ {
+ struct outp_driver *d = target->driver;
+ if (d->class->special == 0)
+ {
+ if (target->header)
+ {
+ size_t i;
+ for (i = 0; i < target->header_rows; i++)
+ free (target->header[i]);
+ free (target->header);
+ }
+ }
+ else if (d->class == &html_class)
+ {
+ if (d->page_open)
+ {
+ struct html_driver_ext *x = d->ext;
- fputs ("</TABLE>\n", x->file);
- }
- }
- else
- NOT_REACHED ();
+ fputs ("</TABLE>\n", x->file);
+ }
+ }
+ else
+ NOT_REACHED ();
+ ll_remove (&target->ll);
+ free (target);
+ }
+
free (cmd.v_variables);
}
This is complicated by the fact that we have to do all this for
every output driver, not just once. */
static void
-determine_layout (void)
+determine_layout (struct ll_list *targets)
{
struct outp_driver *d;
size buffer to allocate. */
int largest_page_width = 0;
+ ll_init (targets);
for (d = outp_drivers (NULL); d; d = outp_drivers (d))
{
size_t column; /* Current column. */
int height; /* Height of vertical names. */
int max_width; /* Page width. */
- struct list_ext *prc;
+ struct list_target *target;
+
+ target = xmalloc (sizeof *target);
+ ll_push_tail (targets, &target->ll);
+ target->driver = d;
+ target->type = 0;
+ target->n_vertical = 0;
+ target->header = NULL;
if (d->class == &html_class)
continue;
-
assert (d->class->special == 0);
outp_open_page (d);
max_width = n_chars_width (d);
largest_page_width = MAX (largest_page_width, max_width);
- prc = d->prc = xmalloc (sizeof *prc);
- prc->type = 0;
- prc->n_vertical = 0;
- prc->header = NULL;
-
/* Try layout #1. */
for (width = cmd.n_variables - 1, column = 0; column < cmd.n_variables; column++)
{
}
if (width <= max_width)
{
- prc->header_rows = 2;
+ target->header_rows = 2;
continue;
}
if (width <= max_width && height <= SHORT_NAME_LEN)
{
#ifndef NDEBUG
- prc->n_vertical = SIZE_MAX;
+ target->n_vertical = SIZE_MAX;
#endif
for (column = cmd.n_variables; column-- != 0; )
{
int trial_width = width - fmt_width + MAX (fmt_width, name_len);
if (trial_width > max_width)
{
- prc->n_vertical = column + 1;
+ target->n_vertical = column + 1;
break;
}
width = trial_width;
}
- assert (prc->n_vertical != SIZE_MAX);
+ assert (target->n_vertical != SIZE_MAX);
- prc->n_vertical = cmd.n_variables;
+ target->n_vertical = cmd.n_variables;
/* Finally determine the length of the headers. */
- for (prc->header_rows = 0, column = 0;
- column < prc->n_vertical;
+ for (target->header_rows = 0, column = 0;
+ column < target->n_vertical;
column++)
{
const struct variable *var = cmd.v_variables[column];
size_t name_len = strlen (var_get_name (var));
- prc->header_rows = MAX (prc->header_rows, name_len);
+ target->header_rows = MAX (target->header_rows, name_len);
}
- prc->header_rows++;
+ target->header_rows++;
continue;
}
/* Otherwise use the ugly fallback listing format. */
- prc->type = 1;
- prc->header_rows = 0;
+ target->type = 1;
+ target->header_rows = 0;
d->cp_y += d->font_height;
write_fallback_headers (d);
/* Writes case C to output. */
static void
list_case (const struct ccase *c, casenumber case_idx,
- const struct dataset *ds)
+ const struct dataset *ds, struct ll_list *targets)
{
struct dictionary *dict = dataset_dict (ds);
- struct outp_driver *d;
+ const char *encoding = dict_get_encoding (dict);
+ struct list_target *target;
- for (d = outp_drivers (NULL); d; d = outp_drivers (d))
- if (d->class->special == 0)
- {
- const struct list_ext *prc = d->prc;
- const int max_width = n_chars_width (d);
- int column;
-
- if (!prc->header_rows)
- {
- ds_put_format(&line_buffer, "%8s: ",
- var_get_name (cmd.v_variables[0]));
- }
-
-
- for (column = 0; column < cmd.n_variables; column++)
- {
- const struct variable *v = cmd.v_variables[column];
- const struct fmt_spec *print = var_get_print_format (v);
- int width;
-
- if (prc->type == 0 && column >= prc->n_vertical)
- {
- int name_len = strlen (var_get_name (v));
- width = MAX (name_len, print->w);
- }
- else
- width = print->w;
-
- if (width + ds_length(&line_buffer) > max_width &&
- ds_length(&line_buffer) != 0)
- {
- if (!n_lines_remaining (d))
- {
- outp_eject_page (d);
- write_header (d);
- }
+ ll_for_each (target, struct list_target, ll, targets)
+ {
+ struct outp_driver *d = target->driver;
- write_line (d, ds_cstr (&line_buffer));
- ds_clear(&line_buffer);
+ if (d->class->special == 0)
+ {
+ const int max_width = n_chars_width (d);
+ int column;
- if (!prc->header_rows)
- ds_put_format (&line_buffer, "%8s: ", var_get_name (v));
- }
+ if (!target->header_rows)
+ {
+ ds_put_format(&line_buffer, "%8s: ",
+ var_get_name (cmd.v_variables[0]));
+ }
- if (width > print->w)
- ds_put_char_multiple(&line_buffer, ' ', width - print->w);
- if (fmt_is_string (print->type)
- || dict_contains_var (dict, v))
- {
- char *s = data_out (case_data (c, v), dict_get_encoding (dict), print);
- ds_put_cstr (&line_buffer, s);
- free (s);
- }
- else
- {
- char *s;
- union value case_idx_value;
- case_idx_value.f = case_idx;
- s = data_out (&case_idx_value, dict_get_encoding (dict), print);
- ds_put_cstr (&line_buffer, s);
- free (s);
- }
-
- ds_put_char (&line_buffer, ' ');
- }
+ for (column = 0; column < cmd.n_variables; column++)
+ {
+ const struct variable *v = cmd.v_variables[column];
+ const struct fmt_spec *print = var_get_print_format (v);
+ int width;
+ char *s;
+
+ if (target->type == 0 && column >= target->n_vertical)
+ {
+ int name_len = strlen (var_get_name (v));
+ width = MAX (name_len, print->w);
+ }
+ else
+ width = print->w;
+
+ if (width + ds_length(&line_buffer) > max_width &&
+ ds_length(&line_buffer) != 0)
+ {
+ if (!n_lines_remaining (d))
+ {
+ outp_eject_page (d);
+ write_header (target);
+ }
+
+ write_line (d, ds_cstr (&line_buffer));
+ ds_clear(&line_buffer);
+
+ if (!target->header_rows)
+ ds_put_format (&line_buffer, "%8s: ", var_get_name (v));
+ }
+
+ if (width > print->w)
+ ds_put_char_multiple(&line_buffer, ' ', width - print->w);
+
+ if (fmt_is_string (print->type) || dict_contains_var (dict, v))
+ s = data_out (case_data (c, v), encoding, print);
+ else
+ {
+ union value case_idx_value;
+ case_idx_value.f = case_idx;
+ s = data_out (&case_idx_value, encoding, print);
+ }
+
+ ds_put_cstr (&line_buffer, s);
+ free (s);
+ ds_put_char(&line_buffer, ' ');
+ }
- if (!n_lines_remaining (d))
- {
- outp_eject_page (d);
- write_header (d);
- }
+ if (!n_lines_remaining (d))
+ {
+ outp_eject_page (d);
+ write_header (target);
+ }
- write_line (d, ds_cstr (&line_buffer));
- ds_clear(&line_buffer);
- }
- else if (d->class == &html_class)
- {
- struct html_driver_ext *x = d->ext;
- int column;
+ write_line (d, ds_cstr (&line_buffer));
+ ds_clear(&line_buffer);
+ }
+ else if (d->class == &html_class)
+ {
+ struct html_driver_ext *x = d->ext;
+ int column;
- fputs (" <TR>\n", x->file);
+ fputs (" <TR>\n", x->file);
- for (column = 0; column < cmd.n_variables; column++)
- {
- const struct variable *v = cmd.v_variables[column];
- const struct fmt_spec *print = var_get_print_format (v);
- char *s = NULL;
-
- if (fmt_is_string (print->type)
- || dict_contains_var (dict, v))
- s = data_out (case_data (c, v), dict_get_encoding (dict), print);
- else
- {
- union value case_idx_value;
- case_idx_value.f = case_idx;
- s = data_out (&case_idx_value, dict_get_encoding (dict), print);
- }
-
- fputs (" <TD>", x->file);
- html_put_cell_contents (d, TAB_FIX, ss_buffer (s, print->w));
- free (s);
- fputs ("</TD>\n", x->file);
- }
+ for (column = 0; column < cmd.n_variables; column++)
+ {
+ const struct variable *v = cmd.v_variables[column];
+ const struct fmt_spec *print = var_get_print_format (v);
+ char *s;
+
+ if (fmt_is_string (print->type)
+ || dict_contains_var (dict, v))
+ s = data_out (case_data (c, v), encoding, print);
+ else
+ {
+ union value case_idx_value;
+ case_idx_value.f = case_idx;
+ s = data_out (&case_idx_value, encoding, print);
+ }
+
+ fputs (" <TD>", x->file);
+ html_put_cell_contents (d, TAB_FIX, ss_cstr (s));
+ fputs ("</TD>\n", x->file);
+
+ free (s);
+ }
- fputs (" </TR>\n", x->file);
- }
- else
- NOT_REACHED ();
+ fputs (" </TR>\n", x->file);
+ }
+ else
+ NOT_REACHED ();
+ }
}
+
/*
Local Variables:
mode: c
int row;
spec_cnt = ll_count (&trns->specs);
- t = tab_create (4, spec_cnt + 1, 0);
- tab_columns (t, TAB_COL_DOWN, 1);
+ t = tab_create (4, spec_cnt + 1);
+ tab_columns (t, TAB_COL_DOWN);
tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt);
tab_hline (t, TAL_2, 0, 3, 1);
tab_headers (t, 0, 0, 1, 0);
tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
row = 1;
ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
{
if (split_cnt == 0)
return;
- t = tab_create (3, split_cnt + 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ t = tab_create (3, split_cnt + 1);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_vline (t, TAL_GAP, 1, 0, split_cnt);
tab_vline (t, TAL_GAP, 2, 0, split_cnt);
tab_text (t, 0, 0, TAB_NONE, _("Variable"));
tab_text_format (t, 0, i + 1, TAB_LEFT, "%s", var_get_name (v));
s = data_out (case_data (c, v), dict_get_encoding (dict), print);
+
tab_text_format (t, 1, i + 1, 0, "%.*s", print->w, s);
free (s);
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-sysfile_info_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+sysfile_info_dim (struct tab_rendering *r, void *aux UNUSED)
{
+ const struct tab_table *t = r->table;
static const int max[] = {20, 5, 35, 3, 0};
const int *p;
int i;
for (p = max; *p; p++)
- t->w[p - max] = MIN (tab_natural_width (t, d, p - max),
- *p * d->prop_em_width);
- for (i = 0; i < t->nr; i++)
- t->h[i] = tab_natural_height (t, d, i);
+ r->w[p - max] = MIN (tab_natural_width (r, p - max),
+ *p * r->driver->prop_em_width);
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = tab_natural_height (r, i);
}
/* SYSFILE INFO utility. */
}
casereader_destroy (reader);
- t = tab_create (2, 11, 0);
+ t = tab_create (2, 11);
tab_vline (t, TAL_GAP, 1, 0, 8);
tab_text (t, 0, 0, TAB_LEFT, _("File:"));
tab_text (t, 1, 0, TAB_LEFT, fh_get_file_name (h));
dict_get_encoding(d) ? dict_get_encoding(d) : _("Unknown"));
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_submit (t);
- t = tab_create (4, 1 + 2 * dict_get_var_cnt (d), 1);
- tab_dim (t, sysfile_info_dim, NULL);
+ t = tab_create (4, 1 + 2 * dict_get_var_cnt (d));
+ tab_dim (t, sysfile_info_dim, NULL, NULL);
tab_headers (t, 0, 0, 1, 0);
tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
tab_joint_text (t, 1, 0, 2, 0, TAB_LEFT | TAT_TITLE, _("Description"));
}
}
-static int _flags;
+struct variables_dim_aux
+ {
+ int flags;
+ };
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-variables_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+variables_dim (struct tab_rendering *r, void *aux_)
{
- int pc;
- int i;
+ const struct outp_driver *d = r->driver;
+ struct variables_dim_aux *aux = aux_;
- t->w[0] = tab_natural_width (t, d, 0);
- if (_flags & (DF_VALUE_LABELS | DF_VARIABLE_LABELS | DF_MISSING_VALUES
- | DF_AT_ATTRIBUTES | DF_ATTRIBUTES))
+ tab_natural_dimensions (r, NULL);
+ if (aux->flags & (DF_VALUE_LABELS | DF_VARIABLE_LABELS | DF_MISSING_VALUES
+ | DF_AT_ATTRIBUTES | DF_ATTRIBUTES))
{
- t->w[1] = MAX (tab_natural_width (t, d, 1), d->prop_em_width * 5);
- t->w[2] = MAX (tab_natural_width (t, d, 2), d->prop_em_width * 35);
- pc = 3;
+ r->w[1] = MAX (r->w[1], d->prop_em_width * 5);
+ r->w[2] = MAX (r->w[2], d->prop_em_width * 35);
}
- else
- pc = 1;
- if (_flags & DF_DICT_INDEX)
- t->w[pc] = tab_natural_width (t, d, pc);
+}
- for (i = 0; i < t->nr; i++)
- t->h[i] = tab_natural_height (t, d, i);
+static void
+variables_dim_free (void *aux_)
+{
+ struct variables_dim_aux *aux = aux_;
+ free (aux);
}
static void
display_variables (const struct variable **vl, size_t n, int flags)
{
struct tab_table *t;
+ struct variables_dim_aux *aux;
int nc; /* Number of columns. */
int pc; /* `Position column' */
int r; /* Current row. */
size_t i;
- _flags = flags;
-
/* One column for the name,
two columns for general description,
one column for dictionary index. */
if (flags & DF_DICT_INDEX)
nc++;
- t = tab_create (nc, n + 5, 1);
+ t = tab_create (nc, n + 5);
tab_headers (t, 0, 0, 1, 0);
tab_hline (t, TAL_2, 0, nc - 1, 1);
tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
? _("Description") : _("Label")));
if (flags & DF_DICT_INDEX)
tab_text (t, pc, 0, TAB_LEFT | TAT_TITLE, _("Position"));
- tab_dim (t, variables_dim, NULL);
+
+ aux = xmalloc (sizeof *aux);
+ aux->flags = flags;
+ tab_dim (t, variables_dim, variables_dim_free, aux);
r = 1;
for (i = 0; i < n; i++)
if (flags & ~DF_DICT_INDEX)
tab_vline (t, TAL_1, nc - 1, 0, r - 1);
tab_resize (t, -1, r);
- tab_columns (t, TAB_COL_DOWN, 1);
+ tab_columns (t, TAB_COL_DOWN);
tab_submit (t);
}
\f
if (!n_attrs)
return;
- t = tab_create (2, n_attrs + 1, 0);
+ t = tab_create (2, n_attrs + 1);
tab_headers (t, 0, 0, 1, 0);
tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
tab_hline (t, TAL_2, 0, 1, 1);
tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Attribute"));
tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value"));
display_attributes (t, set, flags, 0, 1);
- tab_columns (t, TAB_COL_DOWN, 1);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_columns (t, TAB_COL_DOWN);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_title (t, "Custom data file attributes.");
tab_submit (t);
}
if (sorted)
qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name);
- t = tab_create (4, nrow + 1, 0);
+ t = tab_create (4, nrow + 1);
tab_headers (t, 0, 0, 1, 0);
- tab_columns (t, TAB_COL_DOWN, 1);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_columns (t, TAB_COL_DOWN);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 3, nrow);
tab_box (t, -1, -1, -1, TAL_1, 0, 0, 3, nrow);
tab_hline (t, TAL_2, 0, 3, 1);
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
{
struct array_var_set *avs = vs->aux;
- return (struct variable *) avs->var[idx];
+ return CONST_CAST (struct variable *, avs->var[idx]);
}
/* If VS contains a variable named NAME, sets *IDX to its index
case MEDIAN:
{
struct casereader *sorted_reader;
- struct order_stats *median = percentile_create (0.5, i->cc);
+ struct percentile *median = percentile_create (0.5, i->cc);
+ struct order_stats *os = &median->parent;
sorted_reader = casewriter_make_reader (i->writer);
- order_stats_accumulate (&median, 1,
+ order_stats_accumulate (&os, 1,
sorted_reader,
i->weight,
i->subject,
i->exclude);
- v->f = percentile_calculate ((struct percentile *) median,
- PC_HAVERAGE);
+ v->f = percentile_calculate (median, PC_HAVERAGE);
- statistic_destroy ((struct statistic *) median);
+ statistic_destroy (&median->parent.parent);
}
break;
case SD:
const struct fmt_spec *wfmt = wvar ?
var_get_print_format (wvar) : & F_8_0;
- struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1, 0);
+ struct tab_table *table = tab_create (7, ost->n_vars * 3 + 1);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Binomial Test"));
tab_headers (table, 2, 0, 1, 0);
tab_box (table, TAL_1, TAL_1, -1, TAL_1,
- 0, 0, table->nc - 1, tab_nr(table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
for (v = 0 ; v < ost->n_vars; ++v)
{
#include <language/stats/freq.h>
#include <language/stats/npar.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <libpspp/compiler.h>
#include <libpspp/hash.h>
#include <libpspp/message.h>
return NULL;
}
- table = tab_create(4, n_cells + 2, 0);
- tab_dim (table, tab_natural_dimensions, NULL);
+ table = tab_create(4, n_cells + 2);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, var_to_string(var));
tab_text (table, 1, 0, TAB_LEFT, _("Observed N"));
tab_headers (table, 1, 0, 1, 0);
tab_box (table, TAL_1, TAL_1, -1, -1,
- 0, 0, table->nc - 1, tab_nr(table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 1);
tab_vline (table, TAL_1, i, 0, tab_nr(table) - 1);
- tab_text (table, 0, table->nr - 1, TAB_LEFT, _("Total"));
+ tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
return table;
}
int n_cells = test->hi - test->lo + 1;
- table = tab_create(1 + ost->n_vars * 4, n_cells + 3, 0);
- tab_dim (table, tab_natural_dimensions, NULL);
+ table = tab_create(1 + ost->n_vars * 4, n_cells + 3);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Frequencies"));
for ( i = 0 ; i < ost->n_vars ; ++i )
tab_headers (table, 1, 0, 2, 0);
tab_box (table, TAL_1, TAL_1, -1, -1,
- 0, 0, table->nc - 1, tab_nr(table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
tab_hline (table, TAL_1, 1, tab_nc(table) - 1, 1);
tab_hline (table, TAL_1, 0, tab_nc(table) - 1, 2);
- tab_text (table, 0, table->nr - 1, TAB_LEFT, _("Total"));
+ tab_text (table, 0, tab_nr (table) - 1, TAB_LEFT, _("Total"));
return table;
}
const struct one_sample_test *ost = (const struct one_sample_test*) test;
struct tab_table *table;
- table = tab_create (1 + ost->n_vars, 4, 0);
- tab_dim (table, tab_natural_dimensions, NULL);
+ table = tab_create (1 + ost->n_vars, 4);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Test Statistics"));
tab_headers (table, 1, 0, 1, 0);
{
const struct dictionary *dict = dataset_dict (ds);
int v, i;
- struct one_sample_test *ost = (struct one_sample_test *) test;
- struct chisquare_test *cst = (struct chisquare_test *) test;
+ struct chisquare_test *cst = UP_CAST (test, struct chisquare_test,
+ parent.parent);
+ struct one_sample_test *ost = &cst->parent;
int n_cells = 0;
double total_expected = 0.0;
const struct variable *wvar = dict_get_weight (dict);
const int heading_columns = 1;
const int heading_rows = 1;
- struct tab_table *t = tab_create (nc, nr, 0);
+ struct tab_table *t = tab_create (nc, nr);
tab_title (t, _("Descriptive Statistics"));
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_headers (t, heading_columns, 0, heading_rows, 0);
/* One header row */
nr += heading_rows;
- t = tab_create (nc, nr, 0);
+ t = tab_create (nc, nr);
tab_title (t, _("Correlations"));
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_headers (t, heading_columns, 0, heading_rows, 0);
unsigned int statistics; /* Bit k is 1 if statistic k is requested. */
};
+/* Auxiliary data structure for tab_dim. */
+struct crosstabs_dim_aux
+ {
+ enum mv_class exclude;
+ };
+
static void
init_proc (struct crosstabs_proc *proc, struct dataset *ds)
{
The rest of the data was allocated and destroyed at a
lower level already. */
- free (pt);
}
+ free (proc->pivots);
}
static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds,
struct string name;
int i;
- summary = tab_create (7, 3 + proc->n_pivots, 1);
+ summary = tab_create (7, 3 + proc->n_pivots);
tab_title (summary, _("Summary."));
tab_headers (summary, 1, 0, 3, 0);
tab_joint_text (summary, 1, 0, 6, 0, TAB_CENTER, _("Cases"));
static void display_risk (struct pivot_table *, struct tab_table *);
static void display_directional (struct crosstabs_proc *, struct pivot_table *,
struct tab_table *);
-static void crosstabs_dim (struct tab_table *, struct outp_driver *,
- void *proc);
+static void crosstabs_dim (struct tab_rendering *, void *aux);
+static void crosstabs_dim_free (void *aux);
static void table_value_missing (struct crosstabs_proc *proc,
struct tab_table *table, int c, int r,
unsigned char opt, const union value *v,
int i;
table = tab_create (pt->n_consts + 1 + pt->n_cols + 1,
- (pt->n_entries / pt->n_cols) * 3 / 2 * proc->n_cells + 10,
- true);
+ (pt->n_entries / pt->n_cols) * 3 / 2 * proc->n_cells + 10);
tab_headers (table, pt->n_consts + 1, 0, 2, 0);
/* First header line. */
struct tab_table *chisq;
chisq = tab_create (6 + (pt->n_vars - 2),
- pt->n_entries / pt->n_cols * 3 / 2 * N_CHISQ + 10,
- 1);
+ pt->n_entries / pt->n_cols * 3 / 2 * N_CHISQ + 10);
tab_headers (chisq, 1 + (pt->n_vars - 2), 0, 1, 0);
tab_title (chisq, _("Chi-square tests."));
struct tab_table *sym;
sym = tab_create (6 + (pt->n_vars - 2),
- pt->n_entries / pt->n_cols * 7 + 10, 1);
+ pt->n_entries / pt->n_cols * 7 + 10);
tab_headers (sym, 2 + (pt->n_vars - 2), 0, 1, 0);
tab_title (sym, _("Symmetric measures."));
{
struct tab_table *risk;
- risk = tab_create (4 + (pt->n_vars - 2), pt->n_entries / pt->n_cols * 4 + 10,
- 1);
+ risk = tab_create (4 + (pt->n_vars - 2), pt->n_entries / pt->n_cols * 4 + 10);
tab_headers (risk, 1 + pt->n_vars - 2, 0, 2, 0);
tab_title (risk, _("Risk estimate."));
struct tab_table *direct;
direct = tab_create (7 + (pt->n_vars - 2),
- pt->n_entries / pt->n_cols * 7 + 10, 1);
+ pt->n_entries / pt->n_cols * 7 + 10);
tab_headers (direct, 3 + (pt->n_vars - 2), 0, 1, 0);
tab_title (direct, _("Directional measures."));
submit (struct crosstabs_proc *proc, struct pivot_table *pt,
struct tab_table *t)
{
+ struct crosstabs_dim_aux *aux;
int i;
if (t == NULL)
tab_box (t, -1, -1, -1, TAL_GAP, 0, tab_t (t), tab_l (t) - 1,
tab_nr (t) - 1);
tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1);
- tab_dim (t, crosstabs_dim, proc);
+
+ aux = xmalloc (sizeof *aux);
+ aux->exclude = proc->exclude;
+ tab_dim (t, crosstabs_dim, crosstabs_dim_free, aux);
+
tab_submit (t);
}
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-crosstabs_dim (struct tab_table *t, struct outp_driver *d, void *proc_)
+crosstabs_dim (struct tab_rendering *r, void *aux_)
{
- struct crosstabs_proc *proc = proc_;
+ const struct tab_table *t = r->table;
+ struct outp_driver *d = r->driver;
+ struct crosstabs_dim_aux *aux = aux_;
int i;
/* Width of a numerical column. */
int c = outp_string_width (d, "0.000000", OUTP_PROPORTIONAL);
- if (proc->exclude == MV_NEVER)
+ if (aux->exclude == MV_NEVER)
c += outp_string_width (d, "M", OUTP_PROPORTIONAL);
/* Set width for header columns. */
- if (t->l != 0)
+ if (tab_l (t) != 0)
{
size_t i;
int w;
- w = d->width - c * (t->nc - t->l);
- for (i = 0; i <= t->nc; i++)
- w -= t->wrv[i];
- w /= t->l;
+ w = d->width - c * (tab_nc (t) - tab_l (t));
+ for (i = 0; i <= tab_nc (t); i++)
+ w -= r->wrv[i];
+ w /= tab_l (t);
if (w < d->prop_em_width * 8)
w = d->prop_em_width * 8;
if (w > d->prop_em_width * 15)
w = d->prop_em_width * 15;
- for (i = 0; i < t->l; i++)
- t->w[i] = w;
+ for (i = 0; i < tab_l (t); i++)
+ r->w[i] = w;
}
- for (i = t->l; i < t->nc; i++)
- t->w[i] = c;
+ for (i = tab_l (t); i < tab_nc (t); i++)
+ r->w[i] = c;
+
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = tab_natural_height (r, i);
+}
- for (i = 0; i < t->nr; i++)
- t->h[i] = tab_natural_height (t, d, i);
+static void
+crosstabs_dim_free (void *aux_)
+{
+ struct crosstabs_dim_aux *aux = aux_;
+ free (aux);
}
static bool
struct tab_table *table, int c, int r, unsigned char opt,
const union value *v, const struct variable *var)
{
- struct substring s;
- const struct fmt_spec *print = var_get_print_format (var);
-
const char *label = var_lookup_value_label (var, v);
- if (label)
- {
- tab_text (table, c, r, TAB_LEFT, label);
- return;
- }
-
- s = ss_cstr (data_out_pool (v, dict_get_encoding (proc->dict), print,
- table->container));
- if (proc->exclude == MV_NEVER && var_is_num_missing (var, v->f, MV_USER))
- s.string[s.length++] = 'M';
- while (s.length && *s.string == ' ')
+ if (label != NULL)
+ tab_text (table, c, r, TAB_LEFT, label);
+ else
{
- s.length--;
- s.string++;
+ const struct fmt_spec *print = var_get_print_format (var);
+ if (proc->exclude == MV_NEVER && var_is_value_missing (var, v, MV_USER))
+ {
+ char *s = data_out (v, dict_get_encoding (proc->dict), print);
+ tab_text_format (table, c, r, opt, "%sM", s + strspn (s, " "));
+ free (s);
+ }
+ else
+ tab_value (table, c, r, opt, v, proc->dict, print);
}
- tab_raw (table, c, r, opt, &s);
}
/* Draws a line across TABLE at the current row to indicate the most
{
const struct fmt_spec f = {FMT_F, 10, 1};
union value v;
- struct substring s;
+ char suffixes[3];
+ int suffix_len;
+ char *s;
v.f = value;
- s = ss_cstr (data_out_pool (&v, dict_get_encoding (dict), &f, table->container));
+ s = data_out (&v, dict_get_encoding (dict), &f);
- while (*s.string == ' ')
- {
- s.length--;
- s.string++;
- }
+ suffix_len = 0;
if (suffix != 0)
- s.string[s.length++] = suffix;
+ suffixes[suffix_len++] = suffix;
if (mark_missing)
- s.string[s.length++] = 'M';
+ suffixes[suffix_len++] = 'M';
+ suffixes[suffix_len] = '\0';
- tab_raw (table, c, r, TAB_RIGHT, &s);
+ tab_text_format (table, c, r, TAB_RIGHT, "%s%s",
+ s + strspn (s, " "), suffixes);
}
/* Displays the crosstabulation table. */
cnt++;
}
- t = tab_create (2, cnt + 1, 0);
+ t = tab_create (2, cnt + 1);
tab_title (t, _("Mapping of variables to corresponding Z-scores."));
- tab_columns (t, SOM_COL_DOWN, 1);
+ tab_columns (t, SOM_COL_DOWN);
tab_headers (t, 0, 0, 1, 0);
tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, cnt);
tab_hline (t, TAL_2, 0, 1, 1);
tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source"));
tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Target"));
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
{
size_t i, y;
sort (dsc->vars, dsc->var_cnt, sizeof *dsc->vars,
descriptives_compare_dsc_vars, dsc);
- t = tab_create (nc, dsc->var_cnt + 1, 0);
+ t = tab_create (nc, dsc->var_cnt + 1);
tab_headers (t, 1, 0, 1, 0);
tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, nc - 1, dsc->var_cnt);
tab_box (t, -1, -1, -1, TAL_1, 1, 0, nc - 1, dsc->var_cnt);
tab_hline (t, TAL_2, 0, nc - 1, 1);
tab_vline (t, TAL_2, 1, 0, dsc->var_cnt);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
nc = 0;
tab_text (t, nc++, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
#include <libpspp/misc.h>
#include <libpspp/str.h>
#include <math/moments.h>
-#include <output/charts/box-whisker.h>
-#include <output/charts/cartesian.h>
+#include <output/charts/boxplot.h>
+#include <output/charts/np-plot.h>
#include <output/manager.h>
#include <output/table.h>
struct percentile **ptl;
size_t n_ptiles;
- struct statistic *tukey_hinges;
- struct statistic *box_whisker;
- struct statistic *trimmed_mean;
- struct statistic *histogram;
- struct order_stats *np;
+ struct tukey_hinges *tukey_hinges;
+ struct box_whisker *box_whisker;
+ struct trimmed_mean *trimmed_mean;
+ struct histogram *histogram;
+ struct np *np;
/* Three quartiles indexing into PTL */
struct percentile **quartiles;
moments1_destroy (result->metrics[v].moments);
extrema_destroy (result->metrics[v].minima);
extrema_destroy (result->metrics[v].maxima);
- statistic_destroy (result->metrics[v].trimmed_mean);
- statistic_destroy (result->metrics[v].tukey_hinges);
- statistic_destroy (result->metrics[v].box_whisker);
- statistic_destroy (result->metrics[v].histogram);
+ statistic_destroy (&result->metrics[v].trimmed_mean->parent.parent);
+ statistic_destroy (&result->metrics[v].tukey_hinges->parent.parent);
+ statistic_destroy (&result->metrics[v].box_whisker->parent.parent);
+ statistic_destroy (&result->metrics[v].histogram->parent);
for (i = 0 ; i < result->metrics[v].n_ptiles; ++i)
- statistic_destroy ((struct statistic *) result->metrics[v].ptl[i]);
+ statistic_destroy (&result->metrics[v].ptl[i]->parent.parent);
free (result->metrics[v].ptl);
free (result->metrics[v].quartiles);
casereader_destroy (result->metrics[v].up_reader);
};
-/* Plot the normal and detrended normal plots for RESULT.
- Label the plots with LABEL */
-static void
-np_plot (struct np *np, const char *label)
-{
- double yfirst = 0, ylast = 0;
-
- double x_lower;
- double x_upper;
- double slack;
-
- /* Normal Plot */
- struct chart *np_chart;
-
- /* Detrended Normal Plot */
- struct chart *dnp_chart;
-
- /* The slope and intercept of the ideal normal probability line */
- const double slope = 1.0 / np->stddev;
- const double intercept = -np->mean / np->stddev;
-
- if ( np->n < 1.0 )
- {
- msg (MW, _("Not creating plot because data set is empty."));
- return ;
- }
-
- np_chart = chart_create ();
- dnp_chart = chart_create ();
-
- if ( !np_chart || ! dnp_chart )
- return ;
-
- chart_write_title (np_chart, _("Normal Q-Q Plot of %s"), label);
- chart_write_xlabel (np_chart, _("Observed Value"));
- chart_write_ylabel (np_chart, _("Expected Normal"));
-
- chart_write_title (dnp_chart, _("Detrended Normal Q-Q Plot of %s"),
- label);
- chart_write_xlabel (dnp_chart, _("Observed Value"));
- chart_write_ylabel (dnp_chart, _("Dev from Normal"));
-
- yfirst = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
- ylast = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
-
- /* Need to make sure that both the scatter plot and the ideal fit into the
- plot */
- x_lower = MIN (np->y_min, (yfirst - intercept) / slope) ;
- x_upper = MAX (np->y_max, (ylast - intercept) / slope) ;
- slack = (x_upper - x_lower) * 0.05 ;
-
- chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
- chart_write_xscale (dnp_chart, np->y_min, np->y_max, 5);
-
- chart_write_yscale (np_chart, yfirst, ylast, 5);
- chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5);
-
- {
- struct casereader *reader = casewriter_make_reader (np->writer);
- struct ccase *c;
- while ((c = casereader_read (reader)) != NULL)
- {
- chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f);
- chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f);
-
- case_unref (c);
- }
- casereader_destroy (reader);
- }
-
- chart_line (dnp_chart, 0, 0, np->y_min, np->y_max , CHART_DIM_X);
- chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
-
- chart_submit (np_chart);
- chart_submit (dnp_chart);
-}
static void
ll != ll_null (&fctr->result_list);
ll = ll_next (ll))
{
- struct string str;
+ struct string label;
const struct factor_result *result =
ll_data (ll, struct factor_result, ll);
-
- ds_init_empty (&str);
- ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
-
- factor_to_string (fctr, result, &str);
-
- np_plot ((struct np*) result->metrics[v].np, ds_cstr(&str));
-
- statistic_destroy ((struct statistic *)result->metrics[v].np);
-
- ds_destroy (&str);
+ struct chart *npp, *dnpp;
+ struct casereader *reader;
+ struct np *np;
+
+ ds_init_empty (&label);
+ ds_put_format (&label, "%s ", var_get_name (dependent_var[v]));
+ factor_to_string (fctr, result, &label);
+
+ np = result->metrics[v].np;
+ reader = casewriter_make_reader (np->writer);
+ npp = np_plot_create (np, reader, ds_cstr (&label));
+ dnpp = dnp_plot_create (np, reader, ds_cstr (&label));
+
+ ds_destroy (&label);
+
+ if (npp == NULL || dnpp == NULL)
+ {
+ msg (MW, _("Not creating NP plot because data set is empty."));
+ chart_unref (npp);
+ chart_unref (dnpp);
+ }
+ else
+ {
+ chart_submit (npp);
+ chart_submit (dnpp);
+ }
+
+ statistic_destroy (&np->parent.parent);
}
}
}
struct string str;
const struct factor_result *result =
ll_data (ll, struct factor_result, ll);
+ struct histogram *histogram;
+ double mean, var, n;
+
+ histogram = result->metrics[v].histogram;
+ if (histogram == NULL)
+ {
+ /* Probably all values are SYSMIS. */
+ continue;
+ }
ds_init_empty (&str);
ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
factor_to_string (fctr, result, &str);
- histogram_plot ((struct histogram *) result->metrics[v].histogram,
- ds_cstr (&str),
- (struct moments1 *) result->metrics[v].moments);
+ moments1_calculate (result->metrics[v].moments,
+ &n, &mean, &var, NULL, NULL);
+ chart_submit (histogram_chart_create (histogram, ds_cstr (&str),
+ n, mean, sqrt (var), false));
ds_destroy (&str);
}
for (v = 0; v < n_dep_var; ++v)
{
- struct ll *ll;
- int f = 0;
- struct chart *ch = chart_create ();
+ const struct factor_result *result;
+ struct boxplot *boxplot;
double y_min = DBL_MAX;
double y_max = -DBL_MAX;
+ char *title;
- for (ll = ll_head (&fctr->result_list);
- ll != ll_null (&fctr->result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
+ struct factor_metrics *metrics = &result->metrics[v];
+ const struct ll_list *max_list = extrema_list (metrics->maxima);
+ const struct ll_list *min_list = extrema_list (metrics->minima);
const struct extremum *max, *min;
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- const struct ll_list *max_list =
- extrema_list (result->metrics[v].maxima);
-
- const struct ll_list *min_list =
- extrema_list (result->metrics[v].minima);
if ( ll_is_empty (max_list))
{
continue;
}
- max = (const struct extremum *)
- ll_data (ll_head(max_list), struct extremum, ll);
-
- min = (const struct extremum *)
- ll_data (ll_head (min_list), struct extremum, ll);
+ max = ll_data (ll_head(max_list), struct extremum, ll);
+ min = ll_data (ll_head (min_list), struct extremum, ll);
y_max = MAX (y_max, max->value);
y_min = MIN (y_min, min->value);
}
- boxplot_draw_yscale (ch, y_max, y_min);
-
- if ( fctr->indep_var[0])
- chart_write_title (ch, _("Boxplot of %s vs. %s"),
+ if (fctr->indep_var[0])
+ title = xasprintf (_("Boxplot of %s vs. %s"),
var_to_string (dependent_var[v]),
- var_to_string (fctr->indep_var[0]) );
+ var_to_string (fctr->indep_var[0]));
else
- chart_write_title (ch, _("Boxplot of %s"),
- var_to_string (dependent_var[v]));
+ title = xasprintf (_("Boxplot of %s"),
+ var_to_string (dependent_var[v]));
+ boxplot = boxplot_create (y_min, y_max, title);
+ free (title);
- for (ll = ll_head (&fctr->result_list);
- ll != ll_null (&fctr->result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- struct string str;
- const double box_width = (ch->data_right - ch->data_left)
- / (ll_count (&fctr->result_list) * 2.0 ) ;
-
- const double box_centre = (f++ * 2 + 1) * box_width + ch->data_left;
-
- ds_init_empty (&str);
+ struct factor_metrics *metrics = &result->metrics[v];
+ struct string str = DS_EMPTY_INITIALIZER;
factor_to_string_concise (fctr, result, &str);
-
- boxplot_draw_boxplot (ch,
- box_centre, box_width,
- (const struct box_whisker *)
- result->metrics[v].box_whisker,
- ds_cstr (&str));
-
+ boxplot_add_box (boxplot, metrics->box_whisker, ds_cstr (&str));
+ metrics->box_whisker = NULL;
ds_destroy (&str);
}
- chart_submit (ch);
+ chart_submit (boxplot_get_chart (boxplot));
}
}
)
{
+ const struct factor_result *result;
int v;
- struct ll *ll;
- const struct ll_list *result_list = &fctr->result_list;
-
- for (ll = ll_head (result_list);
- ll != ll_null (result_list);
- ll = ll_next (ll))
+ ll_for_each (result, struct factor_result, ll, &fctr->result_list)
{
struct string title;
- struct chart *ch = chart_create ();
double y_min = DBL_MAX;
double y_max = -DBL_MAX;
-
- const struct factor_result *result =
- ll_data (ll, struct factor_result, ll);
-
- const double box_width = (ch->data_right - ch->data_left)
- / (n_dep_var * 2.0 ) ;
+ struct boxplot *boxplot;
for (v = 0; v < n_dep_var; ++v)
{
- const struct ll *max_ll =
- ll_head (extrema_list (result->metrics[v].maxima));
- const struct ll *min_ll =
- ll_head (extrema_list (result->metrics[v].minima));
-
- const struct extremum *max =
- (const struct extremum *) ll_data (max_ll, struct extremum, ll);
-
- const struct extremum *min =
- (const struct extremum *) ll_data (min_ll, struct extremum, ll);
+ const struct factor_metrics *metrics = &result->metrics[v];
+ const struct ll *max_ll = ll_head (extrema_list (metrics->maxima));
+ const struct ll *min_ll = ll_head (extrema_list (metrics->minima));
+ const struct extremum *max = ll_data (max_ll, struct extremum, ll);
+ const struct extremum *min = ll_data (min_ll, struct extremum, ll);
y_max = MAX (y_max, max->value);
y_min = MIN (y_min, min->value);
}
-
- boxplot_draw_yscale (ch, y_max, y_min);
-
ds_init_empty (&title);
factor_to_string (fctr, result, &title);
-
-#if 0
- ds_put_format (&title, "%s = ", var_get_name (fctr->indep_var[0]));
- var_append_value_name (fctr->indep_var[0], &result->value[0], &title);
-#endif
-
- chart_write_title (ch, ds_cstr (&title));
+ boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
ds_destroy (&title);
for (v = 0; v < n_dep_var; ++v)
{
- struct string str;
- const double box_centre = (v * 2 + 1) * box_width + ch->data_left;
-
- ds_init_empty (&str);
- ds_init_cstr (&str, var_get_name (dependent_var[v]));
-
- boxplot_draw_boxplot (ch,
- box_centre, box_width,
- (const struct box_whisker *) result->metrics[v].box_whisker,
- ds_cstr (&str));
-
- ds_destroy (&str);
+ struct factor_metrics *metrics = &result->metrics[v];
+ boxplot_add_box (boxplot, metrics->box_whisker,
+ var_get_name (dependent_var[v]));
+ metrics->box_whisker = NULL;
}
- chart_submit (ch);
+ chart_submit (boxplot_get_chart (boxplot));
}
}
if ( cmd.sbc_percentiles)
show_percentiles (dependent_vars, n_dependent_vars, factor);
- if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
- cmd.cmp == XMN_GROUPS)
- show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
-
-
- if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
- cmd.cmp == XMN_VARIABLES)
- show_boxplot_variables (dependent_vars, n_dependent_vars,
- factor);
-
+ if (cmd.a_plot[XMN_PLT_BOXPLOT])
+ {
+ if (cmd.cmp == XMN_GROUPS)
+ show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
+ else if (cmd.cmp == XMN_VARIABLES)
+ show_boxplot_variables (dependent_vars, n_dependent_vars, factor);
+ }
+
if (cmd.a_plot[XMN_PLT_HISTOGRAM])
show_histogram (dependent_vars, n_dependent_vars, factor);
metric->n_ptiles = percentile_list.n_data;
- metric->ptl = xcalloc (metric->n_ptiles,
- sizeof (struct percentile *));
+ metric->ptl = xcalloc (metric->n_ptiles, sizeof *metric->ptl);
metric->quartiles = xcalloc (3, sizeof (*metric->quartiles));
for (i = 0 ; i < metric->n_ptiles; ++i)
{
- metric->ptl[i] = (struct percentile *)
- percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
+ metric->ptl[i] = percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
if ( percentile_list.data[i] == 25)
metric->quartiles[0] = metric->ptl[i];
n_os ++;
}
- os = xcalloc (sizeof (struct order_stats *), n_os);
+ os = xcalloc (n_os, sizeof *os);
for (i = 0 ; i < metric->n_ptiles ; ++i )
{
- os[i] = (struct order_stats *) metric->ptl[i];
+ os[i] = &metric->ptl[i]->parent;
}
- os[i] = (struct order_stats *) metric->tukey_hinges;
- os[i+1] = (struct order_stats *) metric->trimmed_mean;
+ os[i] = &metric->tukey_hinges->parent;
+ os[i+1] = &metric->trimmed_mean->parent;
if (cmd->a_plot[XMN_PLT_NPPLOT])
- os[i+2] = metric->np;
+ os[i+2] = &metric->np->parent;
order_stats_accumulate (os, n_os,
casereader_clone (metric->up_reader),
{
struct factor_metrics *metric = &result->metrics[v];
if ( metric->histogram)
- histogram_add ((struct histogram *) metric->histogram,
+ histogram_add (metric->histogram,
case_data (c, dependent_vars[v])->f, weight);
}
case_unref (c);
struct factor_metrics *metric = &result->metrics[v];
int n_vals = caseproto_get_n_widths (casereader_get_proto (
metric->up_reader));
+ struct order_stats *os;
metric->box_whisker =
- box_whisker_create ((struct tukey_hinges *) metric->tukey_hinges,
- cmd->v_id, n_vals - 1);
+ box_whisker_create ( metric->tukey_hinges, cmd->v_id, n_vals - 1);
- order_stats_accumulate ((struct order_stats **) &metric->box_whisker,
- 1,
+ os = &metric->box_whisker->parent;
+ order_stats_accumulate ( &os, 1,
casereader_clone (metric->up_reader),
wv, dependent_vars[v], MV_ANY);
}
n_cols = heading_columns + 6;
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
/* Outline the box */
tab_box (tbl,
n_cols = heading_columns + 2;
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
/* Outline the box */
tab_box (tbl,
tab_double (tbl, n_cols - 2,
heading_rows + row_var_start + 3 + i * DESCRIPTIVE_ROWS,
TAB_CENTER,
- trimmed_mean_calculate ((struct trimmed_mean *) result->metrics[v].trimmed_mean),
+ trimmed_mean_calculate (result->metrics[v].trimmed_mean),
NULL);
n_cols = heading_columns + 2;
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
/* Outline the box */
tab_box (tbl,
n_cols = heading_columns + n_percentiles;
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
/* Outline the box */
tab_box (tbl,
tab_vline (tbl, TAL_1, n_cols - n_percentiles -1, heading_rows, n_rows - 1);
- tukey_hinges_calculate ((struct tukey_hinges *) result->metrics[v].tukey_hinges,
- hinges);
+ tukey_hinges_calculate (result->metrics[v].tukey_hinges, hinges);
for (j = 0; j < n_percentiles; ++j)
{
hist = freq_tab_to_hist (ft,v);
- histogram_plot_n (hist, var_to_string(v),
+ chart_submit (histogram_chart_create (
+ hist, var_to_string(v),
vf->tab.valid_cases,
d[frq_mean],
d[frq_stddev],
- normal);
+ normal));
- statistic_destroy ((struct statistic *)hist);
+ statistic_destroy (&hist->parent);
}
if ( chart == GFT_PIE)
\f
/* Frequency table display. */
+struct full_dim_aux
+ {
+ bool show_labels;
+ };
+
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-full_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+full_dim (struct tab_rendering *r, void *aux_)
{
- int i = 0;
- int columns = 5;
+ const struct outp_driver *d = r->driver;
+ const struct tab_table *t = r->table;
+ const struct full_dim_aux *aux = aux_;
+ int i;
- if (cmd.labels == FRQ_LABELS)
+ for (i = 0; i < tab_nc (t); i++)
{
- t->w[0] = MIN (tab_natural_width (t, d, 0), d->prop_em_width * 15);
- i = 1;
- columns ++;
+ r->w[i] = tab_natural_width (r, i);
+ if (aux->show_labels && i == 0)
+ r->w[i] = MIN (r->w[i], d->prop_em_width * 15);
+ else
+ r->w[i] = MAX (r->w[i], d->prop_em_width * 8);
}
- for (;i < columns; i++)
- t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = d->font_height;
+}
- for (i = 0; i < t->nr; i++)
- t->h[i] = d->font_height;
+static void
+full_dim_free (void *aux_)
+{
+ struct full_dim_aux *aux = aux_;
+ free (aux);
}
/* Displays a full frequency table for variable V. */
const bool lab = (cmd.labels == FRQ_LABELS);
+ struct full_dim_aux *aux;
+
vf = get_var_freqs (v);
ft = &vf->tab;
n_categories = ft->n_valid + ft->n_missing;
- t = tab_create (5 + lab, n_categories + 2, 0);
+ t = tab_create (5 + lab, n_categories + 2);
tab_headers (t, 0, 0, 1, 0);
- tab_dim (t, full_dim, NULL);
+
+ aux = xmalloc (sizeof *aux);
+ aux->show_labels = lab;
+ tab_dim (t, full_dim, full_dim_free, aux);
if (lab)
tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Value Label"));
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-condensed_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+condensed_dim (struct tab_rendering *r, void *aux UNUSED)
{
- int cum_w = MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
- MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
- outp_string_width (d, "000", OUTP_PROPORTIONAL)));
+ struct outp_driver *d = r->driver;
+ const struct tab_table *t = r->table;
+
+ int cum_width = outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL);
+ int zeros_width = outp_string_width (d, "000", OUTP_PROPORTIONAL);
+ int max_width = MAX (cum_width, zeros_width);
int i;
for (i = 0; i < 2; i++)
- t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
+ {
+ r->w[i] = tab_natural_width (r, i);
+ r->w[i] = MAX (r->w[i], d->prop_em_width * 8);
+ }
for (i = 2; i < 4; i++)
- t->w[i] = cum_w;
- for (i = 0; i < t->nr; i++)
- t->h[i] = d->font_height;
+ r->w[i] = max_width;
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = d->font_height;
}
/* Display condensed frequency table for variable V. */
vf = get_var_freqs (v);
ft = &vf->tab;
n_categories = ft->n_valid + ft->n_missing;
- t = tab_create (4, n_categories + 2, 0);
+ t = tab_create (4, n_categories + 2);
tab_headers (t, 0, 0, 2, 0);
tab_text (t, 0, 1, TAB_CENTER | TAT_TITLE, _("Value"));
tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Cum"));
tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
- tab_dim (t, condensed_dim, NULL);
+ tab_dim (t, condensed_dim, NULL, NULL);
r = 2;
for (f = ft->valid; f < ft->missing; f++)
0, 0, 3, r - 1);
tab_hline (t, TAL_2, 0, 3, 2);
tab_title (t, "%s", var_to_string (v));
- tab_columns (t, SOM_COL_DOWN, 1);
+ tab_columns (t, SOM_COL_DOWN);
tab_submit (t);
}
\f
}
calc_stats (v, stat_value);
- t = tab_create (3, n_stats + n_percentiles + 2, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ t = tab_create (3, n_stats + n_percentiles + 2);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ;
var_get_print_format (v));
}
- tab_columns (t, SOM_COL_DOWN, 1);
+ tab_columns (t, SOM_COL_DOWN);
if (show_varname)
tab_title (t, "%s", var_to_string (v));
else
double x_min = DBL_MAX;
double x_max = -DBL_MAX;
- struct statistic *hist;
+ struct histogram *hist;
const double bins = 11;
struct hsh_iterator hi;
for( i = 0 ; i < ft->n_valid ; ++i )
{
frq = &ft->valid[i];
- histogram_add ((struct histogram *)hist, frq->value.f, frq->count);
+ histogram_add (hist, frq->value.f, frq->count);
}
- return (struct histogram *)hist;
+ return hist;
}
ds_init_empty (&slices[i].label);
var_append_value_name (var, &frq->value, &slices[i].label);
- slices[i].magnetude = frq->count;
+ slices[i].magnitude = frq->count;
}
return slices;
slices = freq_tab_to_slice_array(frq_tab, var, &n_slices);
- piechart_plot(var_to_string(var), slices, n_slices);
+ chart_submit (piechart_create (var_to_string(var), slices, n_slices));
for (i = 0 ; i < n_slices ; ++i )
- {
- ds_destroy (&slices[i].label);
- }
+ ds_destroy (&slices[i].label);
- free(slices);
+ free (slices);
}
if ( desc ) columns += 5;
if ( quartiles ) columns += 3;
- table = tab_create (columns, 2 + n_vars, 0);
+ table = tab_create (columns, 2 + n_vars);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Descriptive Statistics"));
tab_headers (table, 1, 0, 1, 0);
tab_box (table, TAL_1, TAL_1, -1, TAL_1,
- 0, 0, table->nc - 1, tab_nr(table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr(table) - 1 );
tab_hline (table, TAL_2, 0, tab_nc (table) -1, 2);
tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
#include <language/stats/chisquare.h>
#include <language/stats/wilcoxon.h>
#include <language/stats/sign.h>
+#include <libpspp/cast.h>
#include <libpspp/hash.h>
#include <libpspp/pool.h>
#include <libpspp/taint.h>
struct npar_specs *specs = aux;
struct chisquare_test *cstp = pool_alloc(specs->pool, sizeof(*cstp));
- struct one_sample_test *tp = (struct one_sample_test *) cstp;
+ struct one_sample_test *tp = &cstp->parent;
+ struct npar_test *nt = &tp->parent;
- ((struct npar_test *)tp)->execute = chisquare_execute;
- ((struct npar_test *)tp)->insert_variables = one_sample_insert_variables;
+ nt->execute = chisquare_execute;
+ nt->insert_variables = one_sample_insert_variables;
if (!parse_variables_const_pool (lexer, specs->pool, dataset_dict (ds),
&tp->vars, &tp->n_vars,
specs->test,
sizeof(*specs->test) * specs->n_tests);
- specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+ specs->test[specs->n_tests - 1] = nt;
return 1;
}
{
struct npar_specs *specs = aux;
struct binomial_test *btp = pool_alloc(specs->pool, sizeof(*btp));
- struct one_sample_test *tp = (struct one_sample_test *) btp;
+ struct one_sample_test *tp = &btp->parent;
+ struct npar_test *nt = &tp->parent;
- ((struct npar_test *)tp)->execute = binomial_execute;
- ((struct npar_test *)tp)->insert_variables = one_sample_insert_variables;
+ nt->execute = binomial_execute;
+ nt->insert_variables = one_sample_insert_variables;
btp->category1 = btp->category2 = btp->cutpoint = SYSMIS;
specs->test,
sizeof(*specs->test) * specs->n_tests);
- specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+ specs->test[specs->n_tests - 1] = nt;
return 1;
}
const struct variable **vlist2;
size_t n_vlist2;
- ((struct npar_test *)test_parameters)->insert_variables = two_sample_insert_variables;
+ test_parameters->parent.insert_variables = two_sample_insert_variables;
if (!parse_variables_const_pool (lexer, pool,
dict,
struct npar_specs *specs = aux;
struct two_sample_test *tp = pool_alloc (specs->pool, sizeof(*tp));
- ((struct npar_test *)tp)->execute = wilcoxon_execute;
+ struct npar_test *nt = &tp->parent;
+ nt->execute = wilcoxon_execute;
if (!parse_two_sample_related_test (lexer, dataset_dict (ds), cmd,
tp, specs->pool) )
specs->test = pool_realloc (specs->pool,
specs->test,
sizeof(*specs->test) * specs->n_tests);
- specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+ specs->test[specs->n_tests - 1] = nt;
return 1;
}
struct npar_specs *specs = aux;
struct two_sample_test *tp = pool_alloc(specs->pool, sizeof(*tp));
- ((struct npar_test *)tp)->execute = NULL;
+ struct npar_test *nt = &tp->parent;
+ nt->execute = NULL;
if (!parse_two_sample_related_test (lexer, dataset_dict (ds),
specs->test = pool_realloc (specs->pool,
specs->test,
sizeof(*specs->test) * specs->n_tests);
- specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+ specs->test[specs->n_tests - 1] = nt;
return 1;
}
struct npar_specs *specs = aux;
struct two_sample_test *tp = pool_alloc(specs->pool, sizeof(*tp));
- ((struct npar_test *) tp)->execute = sign_execute;
+ struct npar_test *nt = &tp->parent;
+
+ nt->execute = sign_execute;
if (!parse_two_sample_related_test (lexer, dataset_dict (ds), cmd,
tp, specs->pool) )
specs->test = pool_realloc (specs->pool,
specs->test,
sizeof(*specs->test) * specs->n_tests);
- specs->test[specs->n_tests - 1] = (struct npar_test *) tp;
+ specs->test[specs->n_tests - 1] = nt;
return 1;
}
struct const_hsh_table *var_hash)
{
int i;
- struct one_sample_test *ost = (struct one_sample_test *) test;
+ struct one_sample_test *ost = UP_CAST (test, struct one_sample_test, parent);
for ( i = 0 ; i < ost->n_vars ; ++i )
const_hsh_insert (var_hash, ost->vars[i]);
struct tab_table *t;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t,
for ( v = 0; v < n_vars; ++v )
n_rows += group_proc_get (vars[v])->n_groups + 1;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 2, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
/* Put a frame around the entire box, and vertical lines inside */
struct tab_table *t;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 1, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
/* Put a frame around the entire box, and vertical lines inside */
tab_box (t,
struct tab_table *t;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 2, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
/* Put a frame around the entire box, and vertical lines inside */
tab_box (t,
struct tab_table *t;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 3, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
/* Put a frame around the entire box, and vertical lines inside */
tab_box (t,
rsq = c->ssm / c->sst;
adjrsq = 1.0 - (1.0 - rsq) * (c->n_obs - 1.0) / (c->n_obs - c->n_indeps);
std_error = sqrt (pspp_linreg_mse (c));
- t = tab_create (n_cols, n_rows, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ t = tab_create (n_cols, n_rows);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
tab_hline (t, TAL_2, 0, n_cols - 1, 1);
tab_vline (t, TAL_2, 2, 0, n_rows - 1);
assert (c != NULL);
n_rows = c->n_coeffs + 3;
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
tab_hline (t, TAL_2, 0, n_cols - 1, 1);
tab_vline (t, TAL_2, 2, 0, n_rows - 1);
struct tab_table *t;
assert (c != NULL);
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
assert (c != NULL);
n_cols = c->n_indeps + 1 + 2;
n_rows = 2 * (c->n_indeps + 1);
- t = tab_create (n_cols, n_rows, 0);
+ t = tab_create (n_cols, n_rows);
tab_headers (t, 2, 0, 1, 0);
- tab_dim (t, tab_natural_dimensions, NULL);
+ tab_dim (t, tab_natural_dimensions, NULL, NULL);
tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
tab_hline (t, TAL_2, 0, n_cols - 1, 1);
tab_vline (t, TAL_2, 2, 0, n_rows - 1);
{
- struct tab_table *tab = tab_create(1, 1, 0);
+ struct tab_table *tab = tab_create(1, 1);
- tab_dim (tab, tab_natural_dimensions, NULL);
+ tab_dim (tab, tab_natural_dimensions, NULL, NULL);
tab_flags (tab, SOMF_NO_TITLE );
tab_text_format (tab, 0, 0, 0, "Scale: %s", ds_cstr (&rel->scale_name));
int heading_columns = rol[rel->model].heading_cols;
int heading_rows = rol[rel->model].heading_rows;
- struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+ struct tab_table *tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_title (tbl, _("Reliability Statistics"));
const int heading_rows = 1;
const int n_rows = rel->sc[0].n_items + heading_rows ;
- struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+ struct tab_table *tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_title (tbl, _("Item-Total Statistics"));
int heading_columns = 2;
int heading_rows = 1;
struct tab_table *tbl;
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
tab_headers (tbl, heading_columns, 0, heading_rows, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_title (tbl, _("Case Processing Summary"));
#include <config.h>
+#include <language/stats/roc.h>
+
#include <data/procedure.h>
#include <language/lexer/variable-parser.h>
#include <language/lexer/value-parser.h>
#include <gsl/gsl_cdf.h>
#include <output/table.h>
-#include <output/charts/plot-chart.h>
-#include <output/charts/cartesian.h>
+#include <output/chart.h>
+#include <output/charts/roc-chart.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
double max;
};
-#define CUTPOINT 0
-#define TP 1
-#define FN 2
-#define TN 3
-#define FP 4
-
-
/*
Return a new casereader based upon CUTPOINT_RDR.
The number of "positive" cases are placed into
for ( ; (cpc = casereader_read (r) ); case_unref (cpc))
{
struct ccase *new_case;
- const double cp = case_data_idx (cpc, CUTPOINT)->f;
+ const double cp = case_data_idx (cpc, ROC_CUTPOINT)->f;
assert (cp != SYSMIS);
return process_group (var, reader, gt, dict, &rs->n1,
&rs->cutpoint_rdr,
ge,
- TP, FN);
+ ROC_TP, ROC_FN);
}
/*
return process_group (var, reader, lt, dict, &rs->n2,
&rs->cutpoint_rdr,
lt,
- TN, FP);
+ ROC_TN, ROC_FP);
}
{
struct ccase *cc = case_create (casewriter_get_proto (writer));
- case_data_rw_idx (cc, CUTPOINT)->f = cutpoint;
- case_data_rw_idx (cc, TP)->f = 0;
- case_data_rw_idx (cc, FN)->f = 0;
- case_data_rw_idx (cc, TN)->f = 0;
- case_data_rw_idx (cc, FP)->f = 0;
+ case_data_rw_idx (cc, ROC_CUTPOINT)->f = cutpoint;
+ case_data_rw_idx (cc, ROC_TP)->f = 0;
+ case_data_rw_idx (cc, ROC_FN)->f = 0;
+ case_data_rw_idx (cc, ROC_TN)->f = 0;
+ case_data_rw_idx (cc, ROC_FP)->f = 0;
casewriter_write (writer, cc);
}
/*
Create and initialise the rs[x].cutpoint_rdr casereaders. That is, the readers will
- be created with width 5, ready to take the values (cutpoint, TP, FN, TN, FP), and the
+ be created with width 5, ready to take the values (cutpoint, ROC_TP, ROC_FN, ROC_TN, ROC_FP), and the
reader will be populated with its final number of cases.
- However on exit from this function, only CUTPOINT entries will be set to their final
+ However on exit from this function, only ROC_CUTPOINT entries will be set to their final
value. The other entries will be initialised to zero.
*/
static void
struct caseproto *proto = caseproto_create ();
struct subcase ordering;
- subcase_init (&ordering, CUTPOINT, 0, SC_ASCEND);
+ subcase_init (&ordering, ROC_CUTPOINT, 0, SC_ASCEND);
proto = caseproto_add_width (proto, 0); /* cutpoint */
- proto = caseproto_add_width (proto, 0); /* TP */
- proto = caseproto_add_width (proto, 0); /* FN */
- proto = caseproto_add_width (proto, 0); /* TN */
- proto = caseproto_add_width (proto, 0); /* FP */
+ proto = caseproto_add_width (proto, 0); /* ROC_TP */
+ proto = caseproto_add_width (proto, 0); /* ROC_FN */
+ proto = caseproto_add_width (proto, 0); /* ROC_TN */
+ proto = caseproto_add_width (proto, 0); /* ROC_FP */
for (i = 0 ; i < roc->n_vars; ++i)
{
const int n_fields = roc->print_se ? 5 : 1;
const int n_cols = roc->n_vars > 1 ? n_fields + 1: n_fields;
const int n_rows = 2 + roc->n_vars;
- struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+ struct tab_table *tbl = tab_create (n_cols, n_rows);
if ( roc->n_vars > 1)
tab_title (tbl, _("Area Under the Curve"));
tab_headers (tbl, n_cols - n_fields, 0, 1, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_text (tbl, n_cols - n_fields, 1, TAT_TITLE, _("Area"));
{
const int n_cols = 3;
const int n_rows = 4;
- struct tab_table *tbl = tab_create (n_cols, n_rows, 0);
+ struct tab_table *tbl = tab_create (n_cols, n_rows);
tab_title (tbl, _("Case Summary"));
tab_headers (tbl, 1, 0, 2, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_box (tbl,
TAL_2, TAL_2,
for (i = 0; i < roc->n_vars; ++i)
n_rows += casereader_count_cases (rs[i].cutpoint_rdr);
- tbl = tab_create (n_cols, n_rows, 0);
+ tbl = tab_create (n_cols, n_rows);
if ( roc->n_vars > 1)
tab_title (tbl, _("Coordinates of the Curve"));
tab_headers (tbl, 1, 0, 1, 0);
- tab_dim (tbl, tab_natural_dimensions, NULL);
+ tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
tab_hline (tbl, TAL_2, 0, n_cols - 1, 1);
for (; (cc = casereader_read (r)) != NULL;
case_unref (cc), x++)
{
- const double se = case_data_idx (cc, TP)->f /
+ const double se = case_data_idx (cc, ROC_TP)->f /
(
- case_data_idx (cc, TP)->f
+ case_data_idx (cc, ROC_TP)->f
+
- case_data_idx (cc, FN)->f
+ case_data_idx (cc, ROC_FN)->f
);
- const double sp = case_data_idx (cc, TN)->f /
+ const double sp = case_data_idx (cc, ROC_TN)->f /
(
- case_data_idx (cc, TN)->f
+ case_data_idx (cc, ROC_TN)->f
+
- case_data_idx (cc, FP)->f
+ case_data_idx (cc, ROC_FP)->f
);
- tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, CUTPOINT)->f,
+ tab_double (tbl, n_cols - 3, x, 0, case_data_idx (cc, ROC_CUTPOINT)->f,
var_get_print_format (roc->vars[i]));
tab_double (tbl, n_cols - 2, x, 0, se, NULL);
}
-static void
-draw_roc (struct roc_state *rs, const struct cmd_roc *roc)
-{
- int i;
-
- struct chart *roc_chart = chart_create ();
-
- chart_write_title (roc_chart, _("ROC Curve"));
- chart_write_xlabel (roc_chart, _("1 - Specificity"));
- chart_write_ylabel (roc_chart, _("Sensitivity"));
-
- chart_write_xscale (roc_chart, 0, 1, 5);
- chart_write_yscale (roc_chart, 0, 1, 5);
-
- if ( roc->reference )
- {
- chart_line (roc_chart, 1.0, 0,
- 0.0, 1.0,
- CHART_DIM_X);
- }
-
- for (i = 0; i < roc->n_vars; ++i)
- {
- struct ccase *cc;
- struct casereader *r = casereader_clone (rs[i].cutpoint_rdr);
-
- chart_vector_start (roc_chart, var_get_name (roc->vars[i]));
- for (; (cc = casereader_read (r)) != NULL;
- case_unref (cc))
- {
- double se = case_data_idx (cc, TP)->f;
- double sp = case_data_idx (cc, TN)->f;
-
- se /= case_data_idx (cc, FN)->f +
- case_data_idx (cc, TP)->f ;
-
- sp /= case_data_idx (cc, TN)->f +
- case_data_idx (cc, FP)->f ;
-
- chart_vector (roc_chart, 1 - sp, se);
- }
- chart_vector_end (roc_chart);
- casereader_destroy (r);
- }
-
- chart_write_legend (roc_chart);
-
- chart_submit (roc_chart);
-}
-
-
static void
output_roc (struct roc_state *rs, const struct cmd_roc *roc)
{
show_summary (roc);
if ( roc->curve )
- draw_roc (rs, roc);
+ {
+ struct roc_chart *rc;
+ size_t i;
+
+ rc = roc_chart_create (roc->reference);
+ for (i = 0; i < roc->n_vars; i++)
+ roc_chart_add_var (rc, var_get_name (roc->vars[i]),
+ rs[i].cutpoint_rdr);
+ chart_submit (roc_chart_get_chart (rc));
+ }
show_auc (rs, roc);
-
if ( roc->print_coords )
show_coords (rs, roc);
}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LANGUAGE_STATS_ROC_H
+#define LANGUAGE_STATS_ROC_H 1
+
+/* These are case indexes into the cutpoint case readers for ROC
+ output, used by roc.c and roc-chart.c. */
+#define ROC_CUTPOINT 0
+#define ROC_TP 1
+#define ROC_FN 2
+#define ROC_TN 3
+#define ROC_FP 4
+
+#endif /* language/stats/roc.h */
const struct dictionary *dict)
{
int i;
- struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs, 0);
+ struct tab_table *table = tab_create (3, 1 + 4 * t2s->n_pairs);
const struct variable *wv = dict_get_weight (dict);
const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Frequencies"));
/* Vertical lines inside the box */
tab_box (table, 0, 0, -1, TAL_1,
- 1, 0, table->nc - 1, tab_nr (table) - 1 );
+ 1, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
/* Box around entire table */
tab_box (table, TAL_2, TAL_2, -1, -1,
- 0, 0, table->nc - 1, tab_nr (table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
tab_text (table, 2, 0, TAB_CENTER, _("N"));
ds_destroy (&pair_name);
- tab_hline (table, TAL_1, 0, table->nc - 1, 1 + i * 4);
+ tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4);
tab_text (table, 1, 1 + i * 4, TAB_LEFT, _("Negative Differences"));
tab_text (table, 1, 2 + i * 4, TAB_LEFT, _("Positive Differences"));
const struct sign_test_params *param)
{
int i;
- struct tab_table *table = tab_create (1 + t2s->n_pairs, 4, 0);
+ struct tab_table *table = tab_create (1 + t2s->n_pairs, 4);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Test Statistics"));
tab_headers (table, 0, 1, 0, 1);
- tab_hline (table, TAL_2, 0, table->nc - 1, 1);
- tab_vline (table, TAL_2, 1, 0, table->nr - 1);
+ tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
+ tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
/* Vertical lines inside the box */
tab_box (table, -1, -1, -1, TAL_1,
0, 0,
- table->nc - 1, tab_nr (table) - 1);
+ tab_nc (table) - 1, tab_nr (table) - 1);
/* Box around entire table */
tab_box (table, TAL_2, TAL_2, -1, -1,
- 0, 0, table->nc - 1,
+ 0, 0, tab_nc (table) - 1,
tab_nr (table) - 1);
tab_text (table, 0, 1, TAT_TITLE | TAB_LEFT,
ssbox_base_init (struct ssbox *this, int cols, int rows)
{
this->finalize = ssbox_base_finalize;
- this->t = tab_create (cols, rows, 0);
+ this->t = tab_create (cols, rows);
- tab_columns (this->t, SOM_COL_DOWN, 1);
+ tab_columns (this->t, SOM_COL_DOWN);
tab_headers (this->t, 0, 0, 1, 0);
tab_box (this->t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
tab_hline (this->t, TAL_2, 0, cols- 1, 1);
- tab_dim (this->t, tab_natural_dimensions, NULL);
+ tab_dim (this->t, tab_natural_dimensions, NULL, NULL);
}
\f
/* ssbox implementations. */
const size_t rows = 3 + data_rows;
self->finalize = trbox_base_finalize;
- self->t = tab_create (cols, rows, 0);
+ self->t = tab_create (cols, rows);
tab_headers (self->t, 0, 0, 3, 0);
tab_box (self->t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
tab_hline (self->t, TAL_2, 0, cols- 1, 3);
- tab_dim (self->t, tab_natural_dimensions, NULL);
+ tab_dim (self->t, tab_natural_dimensions, NULL, NULL);
}
/* Base finalizer for the trbox */
struct tab_table *table;
- table = tab_create (cols, rows, 0);
+ table = tab_create (cols, rows);
- tab_columns (table, SOM_COL_DOWN, 1);
+ tab_columns (table, SOM_COL_DOWN);
tab_headers (table, 0, 0, 1, 0);
tab_box (table, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
tab_hline (table, TAL_2, 0, cols - 1, 1);
tab_vline (table, TAL_2, 2, 0, rows - 1);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Paired Samples Correlations"));
/* column headings */
const struct variable *wv = dict_get_weight (dict);
const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
- struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs, 0);
+ struct tab_table *table = tab_create (5, 1 + 4 * t2s->n_pairs);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Ranks"));
/* Vertical lines inside the box */
tab_box (table, 0, 0, -1, TAL_1,
- 1, 0, table->nc - 1, tab_nr (table) - 1 );
+ 1, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
/* Box around entire table */
tab_box (table, TAL_2, TAL_2, -1, -1,
- 0, 0, table->nc - 1, tab_nr (table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
tab_text (table, 2, 0, TAB_CENTER, _("N"));
tab_text (table, 1, 3 + i * 4, TAB_LEFT, _("Ties"));
tab_text (table, 1, 4 + i * 4, TAB_LEFT, _("Total"));
- tab_hline (table, TAL_1, 0, table->nc - 1, 1 + i * 4);
+ tab_hline (table, TAL_1, 0, tab_nc (table) - 1, 1 + i * 4);
tab_text (table, 0, 1 + i * 4, TAB_LEFT, ds_cstr (&pair_name));
}
- tab_hline (table, TAL_2, 0, table->nc - 1, 1);
- tab_vline (table, TAL_2, 2, 0, table->nr - 1);
+ tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
+ tab_vline (table, TAL_2, 2, 0, tab_nr (table) - 1);
tab_submit (table);
)
{
size_t i;
- struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3, 0);
+ struct tab_table *table = tab_create (1 + t2s->n_pairs, exact ? 5 : 3);
- tab_dim (table, tab_natural_dimensions, NULL);
+ tab_dim (table, tab_natural_dimensions, NULL, NULL);
tab_title (table, _("Test Statistics"));
/* Vertical lines inside the box */
tab_box (table, 0, 0, -1, TAL_1,
- 0, 0, table->nc - 1, tab_nr (table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
/* Box around entire table */
tab_box (table, TAL_2, TAL_2, -1, -1,
- 0, 0, table->nc - 1, tab_nr (table) - 1 );
+ 0, 0, tab_nc (table) - 1, tab_nr (table) - 1 );
tab_text (table, 0, 1, TAB_LEFT, _("Z"));
}
}
- tab_hline (table, TAL_2, 0, table->nc - 1, 1);
- tab_vline (table, TAL_2, 1, 0, table->nr - 1);
+ tab_hline (table, TAL_2, 0, tab_nc (table) - 1, 1);
+ tab_vline (table, TAL_2, 1, 0, tab_nr (table) - 1);
tab_submit (table);
#include <language/command.h>
#include <language/lexer/lexer.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <libpspp/message.h>
#include <libpspp/message.h>
#include <libpspp/str.h>
static const char *
name (const struct getl_interface *s)
{
- const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+ const struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+ parent);
return sfs->fn;
}
static int
line_number (const struct getl_interface *s)
{
- const struct syntax_file_source *sfs = (const struct syntax_file_source *) s;
+ const struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+ parent);
return sfs->ln;
}
read_syntax_file (struct getl_interface *s,
struct string *line)
{
- struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+ struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+ parent);
/* Open file, if not yet opened. */
if (sfs->syntax_file == NULL)
static void
syntax_close (struct getl_interface *s)
{
- struct syntax_file_source *sfs = (struct syntax_file_source *) s;
+ struct syntax_file_source *sfs = UP_CAST (s, struct syntax_file_source,
+ parent);
if (sfs->syntax_file && EOF == fn_close (sfs->fn, sfs->syntax_file))
msg (MW, _("Closing `%s': %s."), sfs->fn, strerror (errno));
ss->parent.name = name ;
ss->parent.location = line_number;
- return (struct getl_interface *) ss;
+ return &ss->parent;
}
/* PSPPIRE - a graphical interface for PSPP.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <config.h>
+#include <libpspp/cast.h>
#include <libpspp/getl.h>
#include <libpspp/compiler.h>
#include <libpspp/str.h>
static void
do_close (struct getl_interface *i )
{
- struct syntax_string_source *sss = (struct syntax_string_source *) i;
+ struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
+ parent);
ds_destroy (&sss->buffer);
read_single_line (struct getl_interface *i,
struct string *line)
{
- struct syntax_string_source *sss = (struct syntax_string_source *) i;
+ struct syntax_string_source *sss = UP_CAST (i, struct syntax_string_source,
+ parent);
size_t next;
sss->parent.location = location;
- return (struct getl_interface *) sss;
+ return &sss->parent;
}
/* Return the syntax currently contained in S.
if (lex_token (lexer) != T_STRING)
return CMD_FAILURE;
- tab = tab_create(1, 1, 0);
+ tab = tab_create(1, 1);
- tab_dim (tab, tab_natural_dimensions, NULL);
+ tab_dim (tab, tab_natural_dimensions, NULL, NULL);
tab_flags (tab, SOMF_NO_TITLE );
tab_text(tab, 0, 0, 0, ds_cstr (lex_tokstr (lexer)));
static bool
count_trns_free (void *trns_)
{
- struct count_trns *trns = (struct count_trns *) trns_;
+ struct count_trns *trns = trns_;
pool_destroy (trns->pool);
return true;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#endif
#include <libpspp/abt.h>
+#include <libpspp/cast.h>
#include <stdbool.h>
p = p->down[dir];
dir = !after;
}
- ((struct abt_node *) p)->down[dir] = node;
- node->up = (struct abt_node *) p;
+ CONST_CAST (struct abt_node *, p)->down[dir] = node;
+ node->up = CONST_CAST (struct abt_node *, p);
abt_reaugmented (abt, node);
}
{
cmp = abt->compare (target, p, abt->aux);
if (cmp == 0)
- return (struct abt_node *) p;
+ return CONST_CAST (struct abt_node *, p);
}
return NULL;
p = p->down[1];
while (p->down[0] != NULL)
p = p->down[0];
- return (struct abt_node *) p;
+ return CONST_CAST (struct abt_node *, p);
}
}
p = p->down[0];
while (p->down[1] != NULL)
p = p->down[1];
- return (struct abt_node *) p;
+ return CONST_CAST (struct abt_node *, p);
}
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
tree paper. */
#include <stddef.h>
+#include <libpspp/cast.h>
/* Returns the data structure corresponding to the given NODE,
assuming that NODE is embedded as the given MEMBER name in
data type STRUCT. */
-#define abt_data(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define abt_data(NODE, STRUCT, MEMBER) \
+ (CHECK_POINTER_HAS_TYPE (NODE, struct abt_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* Node in an augmented binary tree. */
struct abt_node
src/libpspp/sparse-xarray.h \
src/libpspp/start-date.c \
src/libpspp/start-date.h \
+ src/libpspp/string-map.c \
+ src/libpspp/string-map.h \
+ src/libpspp/string-set.c \
+ src/libpspp/string-set.h \
src/libpspp/str.c \
src/libpspp/str.h \
src/libpspp/taint.c \
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <stdbool.h>
#include <stdint.h>
+#include <libpspp/cast.h>
+
static void rebalance_subtree (struct bt *, struct bt_node *, size_t);
static struct bt_node **down_link (struct bt *, struct bt_node *);
{
cmp = bt->compare (target, p, bt->aux);
if (cmp == 0)
- return (struct bt_node *) p;
+ return CONST_CAST (struct bt_node *, p);
}
return NULL;
break;
}
}
- return (struct bt_node *) q;
+ return CONST_CAST (struct bt_node *, q);
}
/* Searches BT for, and returns, the last node in in-order whose
break;
}
}
- return (struct bt_node *) q;
+ return CONST_CAST (struct bt_node *, q);
}
/* Returns the node in BT following P in in-order.
p = p->down[1];
while (p->down[0] != NULL)
p = p->down[0];
- return (struct bt_node *) p;
+ return CONST_CAST (struct bt_node *, p);
}
}
p = p->down[0];
while (p->down[1] != NULL)
p = p->down[1];
- return (struct bt_node *) p;
+ return CONST_CAST (struct bt_node *, p);
}
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
fully encapsulated. */
#include <stddef.h>
+#include <libpspp/cast.h>
/* Returns the data structure corresponding to the given NODE,
assuming that NODE is embedded as the given MEMBER name in
data type STRUCT. */
-#define bt_data(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define bt_data(NODE, STRUCT, MEMBER) \
+ (CHECK_POINTER_HAS_TYPE (NODE, struct bt_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* Node in a balanced binary tree. */
struct bt_node
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_CAST_H
+#define LIBPSPP_CAST_H 1
+
+#include <stddef.h>
+
+/* Expands to a void expression that checks that POINTER is an
+ expression whose type is a qualified or unqualified version of
+ a type compatible with TYPE (a pointer type) and, if not,
+ causes a compiler warning to be issued (on typical compilers).
+
+ Examples:
+
+ int *ip;
+ const int *cip;
+ const int **cipp;
+ int ***ippp;
+ double *dp;
+
+ // None of these causes a warning:
+ CHECK_POINTER_HAS_TYPE (ip, int *);
+ CHECK_POINTER_HAS_TYPE (ip, const int *);
+ CHECK_POINTER_HAS_TYPE (cip, int *);
+ CHECK_POINTER_HAS_TYPE (cip, const int *);
+ CHECK_POINTER_HAS_TYPE (dp, double *);
+ CHECK_POINTER_HAS_TYPE (dp, const double *);
+ CHECK_POINTER_HAS_TYPE (cipp, const int **);
+ CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
+ CHECK_POINTER_HAS_TYPE (ippp, int ***);
+ CHECK_POINTER_HAS_TYPE (ippp, int **const *);
+
+ // None of these causes a warning either, although it is unusual to
+ // const-qualify a pointer like this (it's like declaring a "const int",
+ // for example).
+ CHECK_POINTER_HAS_TYPE (ip, int *const);
+ CHECK_POINTER_HAS_TYPE (ip, const int *const);
+ CHECK_POINTER_HAS_TYPE (cip, int *const);
+ CHECK_POINTER_HAS_TYPE (cip, const int *const);
+ CHECK_POINTER_HAS_TYPE (cipp, const int **const);
+ CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
+ CHECK_POINTER_HAS_TYPE (ippp, int ***const);
+ CHECK_POINTER_HAS_TYPE (ippp, int **const *const);
+
+ // Provokes a warning because "int" is not compatible with "double":
+ CHECK_POINTER_HAS_TYPE (dp, int *);
+
+ // Provoke warnings because C's type compatibility rules only allow
+ // adding a "const" qualifier to the outermost pointer:
+ CHECK_POINTER_HAS_TYPE (ippp, const int ***);
+ CHECK_POINTER_HAS_TYPE (ippp, int *const**);
+*/
+#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE) \
+ ((void) sizeof ((TYPE) (POINTER) == (POINTER)))
+
+/* Given expressions A and B, both of which have pointer type,
+ expands to a void expression that causes a compiler warning if
+ A and B are not pointers to qualified or unqualified versions
+ of compatible types.
+
+ Examples similar to those given for CHECK_POINTER_HAS_TYPE,
+ above, can easily be devised. */
+#define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))
+
+/* Equivalent to casting POINTER to TYPE, but also issues a
+ warning if the cast changes anything other than an outermost
+ "const" or "volatile" qualifier. */
+#define CONST_CAST(TYPE, POINTER) \
+ (CHECK_POINTER_HAS_TYPE (POINTER, TYPE), \
+ (TYPE) (POINTER))
+
+/* Given POINTER, a pointer to the given MEMBER within structure
+ STRUCT, returns the address of the STRUCT. */
+#define UP_CAST(POINTER, STRUCT, MEMBER) \
+ (CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \
+ (STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER)))
+
+#endif /* libpspp/cast.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#ifndef LIBPSPP_HEAP_H
#define LIBPSPP_HEAP_H 1
+#include <libpspp/cast.h>
#include <stdbool.h>
#include <stddef.h>
/* Returns the data structure corresponding to the given heap
NODE, assuming that NODE is embedded as the given MEMBER name
in data type STRUCT. */
-#define heap_data(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define heap_data(NODE, STRUCT, MEMBER) \
+ (CHECK_POINTER_HAS_TYPE (NODE, struct heap_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* A node in a heap. Opaque.
One of these structures must be embedded in your heap node. */
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
*/
+#include <stdbool.h>
#include <stddef.h>
+#include <libpspp/cast.h>
/* Returns the data structure corresponding to the given NODE,
assuming that NODE is embedded as the given MEMBER name in
data type STRUCT. NODE must not be a null pointer. */
#define HMAP_DATA(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+ (CHECK_POINTER_HAS_TYPE (NODE, struct hmap_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* Like HMAP_DATA, except that a null NODE yields a null pointer
result. */
const struct hmap_node *);
/* Counting. */
+static bool hmap_is_empty (const struct hmap *);
static inline size_t hmap_count (const struct hmap *);
static inline size_t hmap_capacity (const struct hmap *);
: hmap_first_nonempty_bucket__ (map, (node->hash & map->mask) + 1));
}
+/* Returns true if MAP currently contains no data items, false
+ otherwise. */
+static inline bool
+hmap_is_empty (const struct hmap *map)
+{
+ return map->count == 0;
+}
+
/* Returns the number of data items currently in MAP. */
static inline size_t
hmap_count (const struct hmap *map)
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
{
if (map != NULL)
{
- if (hmapx_count (map) > 0)
+ if (!(hmapx_is_empty (map)))
{
struct hmapx_node *node, *next;
for (node = hmapx_first (map); node != NULL; node = next)
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
const struct hmapx_node *);
/* Counting. */
+static inline bool hmapx_is_empty (const struct hmapx *);
static inline size_t hmapx_count (const struct hmapx *);
static inline size_t hmapx_capacity (const struct hmapx *);
return HMAP_NEXT (node, struct hmapx_node, hmap_node, &map->hmap);
}
+/* Returns true if MAP currently contains no data items, false
+ otherwise. */
+static inline bool
+hmapx_is_empty (const struct hmapx *map)
+{
+ return hmap_is_empty (&map->hmap);
+}
+
/* Returns the number of data items currently in MAP. */
static inline size_t
hmapx_count (const struct hmapx *map)
/* PSPP - a program for statistical analysis.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
for (x = r0; x != r1; x = ll_next (x))
if (compare (x, target, aux) == 0)
break;
- return (struct ll *) x;
+ return CONST_CAST (struct ll *, x);
}
/* Returns the first node in R0...R1 for which PREDICATE returns
for (x = r0; x != r1; x = ll_next (x))
if (predicate (x, aux))
break;
- return (struct ll *) x;
+ return CONST_CAST (struct ll *, x);
}
/* Compares each pair of adjacent nodes in R0...R1
for (x = r0, y = ll_next (x); y != r1; x = y, y = ll_next (y))
if (compare (x, y, aux) == 0)
- return (struct ll *) x;
+ return CONST_CAST (struct ll *, x);
}
- return (struct ll *) r1;
+ return CONST_CAST (struct ll *, r1);
}
/* Returns the number of nodes in R0...R1.
if (compare (x, max, aux) > 0)
max = x;
}
- return (struct ll *) max;
+ return CONST_CAST (struct ll *, max);
}
/* Returns the least node in R0...R1 according to COMPARE given
if (compare (x, min, aux) < 0)
min = x;
}
- return (struct ll *) min;
+ return CONST_CAST (struct ll *, min);
}
/* Lexicographically compares A0...A1 to B0...B1.
while (r0 != r1 && compare (ll_prev (r0), r0, aux) <= 0);
}
- return (struct ll *) r0;
+ return CONST_CAST (struct ll *, r0);
}
/* Merges B0...B1 into A0...A1 according to COMPARE given
if (predicate (x, aux))
return NULL;
- return (struct ll *) partition;
+ return CONST_CAST (struct ll *, partition);
}
\f
/* PSPP - a program for statistical analysis.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
+#include <libpspp/cast.h>
+
+#include <libpspp/cast.h>
/* Embedded, circular doubly linked list.
/* Returns the data structure corresponding to the given node LL,
assuming that LL is embedded as the given MEMBER name in data
type STRUCT. */
-#define ll_data(LL, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (LL) - offsetof (STRUCT, MEMBER)))
+#define ll_data(LL, STRUCT, MEMBER) \
+ (CHECK_POINTER_HAS_TYPE(LL, struct ll *), \
+ UP_CAST(LL, STRUCT, MEMBER))
/* Linked list node. */
struct ll
static inline struct ll *
ll_null (const struct ll_list *list)
{
- return (struct ll *) &list->null;
+ return CONST_CAST (struct ll *, &list->null);
}
/* Returns the node following LL in its list,
/* PSPP - a program for statistical analysis.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
for (x = r0; x != r1; x = llx_next (x))
if (compare (llx_data (x), target, aux) == 0)
break;
- return (struct llx *) x;
+ return CONST_CAST (struct llx *, x);
}
/* Returns the first node in R0...R1 for which PREDICATE returns
for (x = r0; x != r1; x = llx_next (x))
if (predicate (llx_data (x), aux))
break;
- return (struct llx *) x;
+ return CONST_CAST (struct llx *, x);
}
/* Compares each pair of adjacent nodes in R0...R1
for (x = r0, y = llx_next (x); y != r1; x = y, y = llx_next (y))
if (compare (llx_data (x), llx_data (y), aux) == 0)
- return (struct llx *) x;
+ return CONST_CAST (struct llx *, x);
}
- return (struct llx *) r1;
+ return CONST_CAST (struct llx *, r1);
}
/* Returns the number of nodes in R0...R1.
if (compare (llx_data (x), llx_data (max), aux) > 0)
max = x;
}
- return (struct llx *) max;
+ return CONST_CAST (struct llx *, max);
}
/* Returns the least node in R0...R1 according to COMPARE given
if (compare (llx_data (x), llx_data (min), aux) < 0)
min = x;
}
- return (struct llx *) min;
+ return CONST_CAST (struct llx *, min);
}
/* Lexicographically compares A0...A1 to B0...B1.
llx_data (r0), aux) <= 0);
}
- return (struct llx *) r0;
+ return CONST_CAST (struct llx *, r0);
}
/* Merges B0...B1 into A0...A1 according to COMPARE given
if (predicate (llx_data (x), aux))
return NULL;
- return (struct llx *) partition;
+ return CONST_CAST (struct llx *, partition);
}
\f
/* Allocates and returns a node using malloc. */
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <stdbool.h>
#include <libpspp/bt.h>
+#include <libpspp/cast.h>
/* Returns the data structure corresponding to the given NODE,
assuming that NODE is embedded as the given MEMBER name in
data type STRUCT. */
#define range_map_data(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+ (CHECK_POINTER_HAS_TYPE (NODE, struct range_map_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* A range map node, to be embedded in the data value. */
struct range_map_node
bool
range_set_contains (const struct range_set *rs_, unsigned long int position)
{
- struct range_set *rs = (struct range_set *) rs_;
+ struct range_set *rs = CONST_CAST (struct range_set *, rs_);
if (position < rs->cache_end && position >= rs->cache_start)
return rs->cache_value;
else
unsigned long int
range_set_scan (const struct range_set *rs_, unsigned long int start)
{
- struct range_set *rs = (struct range_set *) rs_;
+ struct range_set *rs = CONST_CAST (struct range_set *, rs_);
unsigned long int retval = ULONG_MAX;
struct bt_node *bt_node;
#include <stdbool.h>
#include <libpspp/bt.h>
+#include <libpspp/cast.h>
/* A set of ranges. */
struct range_set
range_set_next (const struct range_set *rs, const struct range_set_node *node)
{
return (node != NULL
- ? range_set_next__ (rs, (struct range_set_node *) node)
+ ? range_set_next__ (rs, CONST_CAST (struct range_set_node *, node))
: range_set_first__ (rs));
}
range_set_prev (const struct range_set *rs, const struct range_set_node *node)
{
return (node != NULL
- ? range_set_prev__ (rs, (struct range_set_node *) node)
+ ? range_set_prev__ (rs, CONST_CAST (struct range_set_node *, node))
: range_set_last__ (rs));
}
#include <string.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
static struct leaf_node *
find_leaf_node (const struct sparse_array *spar_, unsigned long int key)
{
- struct sparse_array *spar = (struct sparse_array *) spar_;
+ struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
const union pointer *p;
int level;
scan_forward (const struct sparse_array *spar_, unsigned long int start,
unsigned long int *found)
{
- struct sparse_array *spar = (struct sparse_array *) spar_;
+ struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
/* Check the cache. */
if (start >> BITS_PER_LEVEL == spar->cache_ofs)
scan_reverse (const struct sparse_array *spar_, unsigned long int start,
unsigned long int *found)
{
- struct sparse_array *spar = (struct sparse_array *) spar_;
+ struct sparse_array *spar = CONST_CAST (struct sparse_array *, spar_);
/* Check the cache. */
if (start >> BITS_PER_LEVEL == spar->cache_ofs)
#include <stdint.h>
#include <stdlib.h>
+#include <libpspp/cast.h>
#include <libpspp/message.h>
#include <libpspp/pool.h>
char *
ds_cstr (const struct string *st_)
{
- struct string *st = (struct string *) st_;
+ struct string *st = CONST_CAST (struct string *, st_);
if (st->ss.string == NULL)
ds_extend (st, 1);
st->ss.string[st->ss.length] = '\0';
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <libpspp/string-map.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+#include <libpspp/string-set.h>
+
+#include "gl/xalloc.h"
+
+static struct string_map_node *string_map_find_node__ (
+ const struct string_map *, const char *key, unsigned int hash);
+static bool string_map_delete__ (struct string_map *, const char *key,
+ unsigned int hash);
+static struct string_map_node *string_map_insert__ (struct string_map *,
+ char *key, char *value,
+ unsigned int hash);
+
+/* Sets NODE's value to a copy of NEW_VALUE and returns the node's previous
+ value. The caller is responsible for freeing the returned string (with
+ free()). */
+char *
+string_map_node_swap_value (struct string_map_node *node,
+ const char *new_value)
+{
+ return string_map_node_swap_value_nocopy (node, xstrdup (new_value));
+}
+
+/* Sets NODE's value to NEW_VALUE, which must be a malloc()'d string,
+ transferring ownership of NEW_VALUE to the node. Returns the node's
+ previous value, which the caller is responsible for freeing (with
+ free()). */
+char *
+string_map_node_swap_value_nocopy (struct string_map_node *node,
+ char *new_value)
+{
+ char *old_value = node->value;
+ node->value = new_value;
+ return old_value;
+}
+
+/* Replaces NODE's value by a copy of VALUE. */
+void
+string_map_node_set_value (struct string_map_node *node, const char *value)
+{
+ string_map_node_set_value_nocopy (node, xstrdup (value));
+}
+
+/* Replaces NODE's value by VALUE, which must be a malloc()'d string,
+ transferring ownership of VALUE to the node.. */
+void
+string_map_node_set_value_nocopy (struct string_map_node *node, char *value)
+{
+ free (node->value);
+ node->value = value;
+}
+
+/* Frees NODE and and its key and value. Ordinarily nodes are owned by
+ string_maps, but this function should only be used by a caller that owns
+ NODE, such as one that has called string_map_delete_nofree() for the
+ node. */
+void
+string_map_node_destroy (struct string_map_node *node)
+{
+ free (node->key);
+ free (node->value);
+ free (node);
+}
+\f
+/* Initializes MAP as an initially empty string map. */
+void
+string_map_init (struct string_map *map)
+{
+ hmap_init (&map->hmap);
+}
+
+/* Initializes MAP as a new string map that initially contains the same pairs
+ as OLD. */
+void
+string_map_clone (struct string_map *map, const struct string_map *old)
+{
+ const struct string_map_node *node;
+ const char *key, *value;
+
+ string_map_init (map);
+ hmap_reserve (&map->hmap, string_map_count (old));
+ STRING_MAP_FOR_EACH_KEY_VALUE (key, value, node, old)
+ string_map_insert__ (map, xstrdup (key), xstrdup (value),
+ node->hmap_node.hash);
+}
+
+/* Exchanges the contents of string maps A and B. */
+void
+string_map_swap (struct string_map *a, struct string_map *b)
+{
+ hmap_swap (&a->hmap, &b->hmap);
+}
+
+/* Frees MAP and its nodes and key-value pairs. */
+void
+string_map_destroy (struct string_map *map)
+{
+ if (map != NULL)
+ {
+ string_map_clear (map);
+ hmap_destroy (&map->hmap);
+ }
+}
+
+/* Returns true if MAP contains KEY as a key, otherwise false. */
+bool
+string_map_contains (const struct string_map *map, const char *key)
+{
+ return string_map_find_node (map, key) != NULL;
+}
+
+/* If MAP contains KEY as a key, returns the corresponding value. Otherwise,
+ returns a null pointer. */
+const char *
+string_map_find (const struct string_map *map, const char *key)
+{
+ const struct string_map_node *node = string_map_find_node (map, key);
+ return node != NULL ? node->value : NULL;
+}
+
+/* If MAP contains KEY as a key, returns the corresponding node. Otherwise,
+ returns a null pointer. */
+struct string_map_node *
+string_map_find_node (const struct string_map *map, const char *key)
+{
+ return string_map_find_node__ (map, key, hash_string (key, 0));
+}
+
+/* If MAP contains KEY as a key, deletes that key's node and returns its value,
+ which the caller is responsible for freeing (using free()). Otherwise,
+ returns a null pointer. */
+char *
+string_map_find_and_delete (struct string_map *map, const char *key)
+{
+ struct string_map_node *node = string_map_find_node (map, key);
+ char *value = NULL;
+ if (node != NULL)
+ {
+ value = node->value;
+ node->value = NULL;
+ string_map_delete_node (map, node);
+ }
+ return value;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing copies
+ of KEY and VALUE and returns the new node. Otherwise, returns the existing
+ node that contains KEY. */
+struct string_map_node *
+string_map_insert (struct string_map *map, const char *key, const char *value)
+{
+ unsigned int hash = hash_string (key, 0);
+ struct string_map_node *node = string_map_find_node__ (map, key, hash);
+ if (node == NULL)
+ node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+ return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing KEY and
+ VALUE and returns the new node. Otherwise, returns the existing node that
+ contains KEY. Either way, ownership of KEY and VALUE is transferred to
+ MAP. */
+struct string_map_node *
+string_map_insert_nocopy (struct string_map *map, char *key, char *value)
+{
+ unsigned int hash = hash_string (key, 0);
+ struct string_map_node *node = string_map_find_node__ (map, key, hash);
+ if (node == NULL)
+ node = string_map_insert__ (map, key, value, hash);
+ else
+ {
+ free (key);
+ free (value);
+ }
+ return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing copies
+ of KEY and VALUE. Otherwise, replaces the existing node's value by a copy
+ of VALUE. Returns the node. */
+struct string_map_node *
+string_map_replace (struct string_map *map, const char *key, const char *value)
+{
+ unsigned int hash = hash_string (key, 0);
+ struct string_map_node *node = string_map_find_node__ (map, key, hash);
+ if (node == NULL)
+ node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
+ else
+ string_map_node_set_value (node, value);
+ return node;
+}
+
+/* If MAP does not contain KEY as a key, inserts a new node containing KEY and
+ VALUE. Otherwise, replaces the existing node's value by VALUE. Either way,
+ ownership of KEY and VALUE is transferred to MAP. Returns the node. */
+struct string_map_node *
+string_map_replace_nocopy (struct string_map *map, char *key, char *value)
+{
+ unsigned int hash = hash_string (key, 0);
+ struct string_map_node *node = string_map_find_node__ (map, key, hash);
+ if (node == NULL)
+ node = string_map_insert__ (map, key, value, hash);
+ else
+ {
+ free (key);
+ string_map_node_set_value_nocopy (node, value);
+ }
+ return node;
+}
+
+/* Searches MAP for a node with KEY as its key. If found, deletes the node
+ and its key and value and returns true. Otherwise, returns false without
+ modifying MAP. */
+bool
+string_map_delete (struct string_map *map, const char *key)
+{
+ return string_map_delete__ (map, key, hash_string (key, 0));
+}
+
+/* Deletes NODE from MAP and destroys the node and its key and value. */
+void
+string_map_delete_node (struct string_map *map, struct string_map_node *node)
+{
+ string_map_delete_nofree (map, node);
+ string_map_node_destroy (node);
+}
+
+/* Deletes NODE from MAP. Transfers ownership of NODE to the caller, which
+ becomes responsible for destroying it. */
+void
+string_map_delete_nofree (struct string_map *map, struct string_map_node *node)
+{
+ hmap_delete (&map->hmap, &node->hmap_node);
+}
+
+/* Removes all nodes from MAP and frees them and their keys and values. */
+void
+string_map_clear (struct string_map *map)
+{
+ struct string_map_node *node, *next;
+
+ STRING_MAP_FOR_EACH_NODE_SAFE (node, next, map)
+ string_map_delete_node (map, node);
+}
+
+/* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
+ have a particular key, the value in DST's node is left unchanged. */
+void
+string_map_insert_map (struct string_map *dst, const struct string_map *src)
+{
+ const struct string_map_node *node;
+
+ STRING_MAP_FOR_EACH_NODE (node, src)
+ {
+ if (!string_map_find_node__ (dst, node->key, node->hmap_node.hash))
+ string_map_insert__ (dst, xstrdup (node->key), xstrdup (node->value),
+ node->hmap_node.hash);
+ }
+}
+
+/* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
+ have a particular key, the value in DST's node is replaced by a copy of the
+ value in SRC's node. */
+void
+string_map_replace_map (struct string_map *dst, const struct string_map *src)
+{
+ const struct string_map_node *snode;
+
+ STRING_MAP_FOR_EACH_NODE (snode, src)
+ {
+ struct string_map_node *dnode;
+ dnode = string_map_find_node__ (dst, snode->key, snode->hmap_node.hash);
+ if (dnode != NULL)
+ string_map_node_set_value (dnode, snode->value);
+ else
+ string_map_insert__ (dst, xstrdup (snode->key), xstrdup (snode->value),
+ snode->hmap_node.hash);
+ }
+}
+
+/* Inserts each of the keys in MAP into KEYS. KEYS must already have been
+ initialized (using string_set_init()). */
+void
+string_map_get_keys (const struct string_map *map, struct string_set *keys)
+{
+ const struct string_map_node *node;
+ const char *key;
+
+ STRING_MAP_FOR_EACH_KEY (key, node, map)
+ string_set_insert (keys, key);
+}
+
+/* Inserts each of the values in MAP into VALUES. VALUES must already have
+ been initialized (using string_set_init()). */
+void
+string_map_get_values (const struct string_map *map, struct string_set *values)
+{
+ const struct string_map_node *node;
+ const char *value;
+
+ STRING_MAP_FOR_EACH_VALUE (value, node, map)
+ string_set_insert (values, value);
+}
+\f
+static struct string_map_node *
+string_map_find_node__ (const struct string_map *map, const char *key,
+ unsigned int hash)
+{
+ struct string_map_node *node;
+
+ HMAP_FOR_EACH_WITH_HASH (node, struct string_map_node, hmap_node,
+ hash, &map->hmap)
+ if (!strcmp (key, node->key))
+ return node;
+
+ return NULL;
+}
+
+static bool
+string_map_delete__ (struct string_map *map, const char *key,
+ unsigned int hash)
+{
+ struct string_map_node *node = string_map_find_node__ (map, key, hash);
+ if (node != NULL)
+ {
+ string_map_delete_node (map, node);
+ return true;
+ }
+ else
+ return false;
+}
+
+static struct string_map_node *
+string_map_insert__ (struct string_map *map, char *key, char *value,
+ unsigned int hash)
+{
+ struct string_map_node *node = xmalloc (sizeof *node);
+ node->key = key;
+ node->value = value;
+ hmap_insert (&map->hmap, &node->hmap_node, hash);
+ return node;
+}
+
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_STRING_MAP_H
+#define LIBPSPP_STRING_MAP_H
+
+/* Map from a unique string key to a string value.
+
+ This is a convenient wrapper around a "struct hmap" for storing string
+ key-value pairs. */
+
+#include <stdbool.h>
+#include <libpspp/hmap.h>
+
+struct string_set;
+
+/* A node within a string map. */
+struct string_map_node
+ {
+ struct hmap_node hmap_node;
+ char *key;
+ char *value;
+ };
+
+/* Returns the string key within NODE. The caller must not modify or free the
+ returned string. */
+static inline const char *
+string_map_node_get_key (const struct string_map_node *node)
+{
+ return node->key;
+}
+
+/* Returns the string key within NODE. The caller must not free the returned
+ string. */
+static inline const char *
+string_map_node_get_value (const struct string_map_node *node)
+{
+ return node->value;
+}
+
+/* Returns the string key within NODE. The caller must not free the returned
+ string. */
+static inline char *
+string_map_node_get_value_rw (struct string_map_node *node)
+{
+ return node->value;
+}
+
+char *string_map_node_swap_value (struct string_map_node *,
+ const char *new_value);
+char *string_map_node_swap_value_nocopy (struct string_map_node *,
+ char *new_value);
+void string_map_node_set_value (struct string_map_node *, const char *value);
+void string_map_node_set_value_nocopy (struct string_map_node *, char *value);
+void string_map_node_destroy (struct string_map_node *);
+\f
+/* Unordered map from unique string keys to string values. */
+struct string_map
+ {
+ struct hmap hmap;
+ };
+
+/* Suitable for use as the initializer for a string_map named MAP. Typical
+ usage:
+ struct string_map map = STRING_MAP_INITIALIZER (map);
+ STRING_MAP_INITIALIZER is an alternative to calling string_map_init. */
+#define STRING_MAP_INITIALIZER(MAP) { HMAP_INITIALIZER ((MAP).hmap) }
+
+void string_map_init (struct string_map *);
+void string_map_clone (struct string_map *, const struct string_map *);
+void string_map_swap (struct string_map *, struct string_map *);
+void string_map_destroy (struct string_map *);
+
+static inline size_t string_map_count (const struct string_map *);
+static inline bool string_map_is_empty (const struct string_map *);
+
+bool string_map_contains (const struct string_map *, const char *);
+const char *string_map_find (const struct string_map *, const char *);
+struct string_map_node *string_map_find_node (const struct string_map *,
+ const char *);
+char *string_map_find_and_delete (struct string_map *, const char *key);
+
+struct string_map_node *string_map_insert (struct string_map *,
+ const char *key, const char *value);
+struct string_map_node *string_map_insert_nocopy (struct string_map *,
+ char *key, char *value);
+struct string_map_node *string_map_replace (struct string_map *,
+ const char *key, const char *value);
+struct string_map_node *string_map_replace_nocopy (struct string_map *,
+ char *key, char *value);
+bool string_map_delete (struct string_map *, const char *);
+void string_map_delete_node (struct string_map *, struct string_map_node *);
+void string_map_delete_nofree (struct string_map *, struct string_map_node *);
+
+void string_map_clear (struct string_map *);
+void string_map_insert_map (struct string_map *, const struct string_map *);
+void string_map_replace_map (struct string_map *, const struct string_map *);
+
+void string_map_get_keys (const struct string_map *, struct string_set *);
+void string_map_get_values (const struct string_map *, struct string_set *);
+
+static inline struct string_map_node *string_map_first (
+ const struct string_map *);
+static inline struct string_map_node *string_map_next (
+ const struct string_map *, const struct string_map_node *);
+
+/* Macros for conveniently iterating through a string_map, e.g. to print all of
+ the key-value pairs in "my_map":
+
+ struct string_map_node *node;
+ const char *key, *value;
+
+ STRING_MAP_FOR_EACH_KEY_VALUE (key, value, node, &my_map)
+ printf ("%s=%s\n", key, value);
+ */
+#define STRING_MAP_FOR_EACH_NODE(NODE, MAP) \
+ for ((NODE) = string_map_first (MAP); (NODE) != NULL; \
+ (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_NODE_SAFE(NODE, NEXT, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((NEXT) = string_map_next (MAP, NODE), 1)); \
+ (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_KEY(KEY, NODE, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((KEY) = string_map_node_get_key (NODE), 1)); \
+ (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_KEY_SAFE(KEY, NODE, NEXT, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((KEY) = string_map_node_get_key (NODE), 1) \
+ && ((NEXT) = string_map_next (MAP, NODE), 1)); \
+ (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_VALUE(VALUE, NODE, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((VALUE) = (NODE)->value, 1)); \
+ (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_VALUE_SAFE(VALUE, NODE, NEXT, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((VALUE) = (NODE)->value, 1) \
+ && ((NEXT) = string_map_next (MAP, NODE), 1)); \
+ (NODE) = (NEXT))
+#define STRING_MAP_FOR_EACH_KEY_VALUE(KEY, VALUE, NODE, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((KEY) = string_map_node_get_key (NODE), 1) \
+ && ((VALUE) = (NODE)->value, 1)); \
+ (NODE) = string_map_next (MAP, NODE))
+#define STRING_MAP_FOR_EACH_KEY_VALUE_SAFE(KEY, VALUE, NODE, NEXT, MAP) \
+ for ((NODE) = string_map_first (MAP); \
+ ((NODE) != NULL \
+ && ((KEY) = string_map_node_get_key (NODE), 1) \
+ && ((VALUE) = (NODE)->value, 1) \
+ && ((NEXT) = string_map_next (MAP, NODE), 1)); \
+ (NODE) = (NEXT))
+\f
+/* Returns the number of key-value pairs currently in MAP. */
+static inline size_t
+string_map_count (const struct string_map *map)
+{
+ return hmap_count (&map->hmap);
+}
+
+/* Returns true if MAP currently contains no key-value pairs, false
+ otherwise. */
+static inline bool
+string_map_is_empty (const struct string_map *map)
+{
+ return hmap_is_empty (&map->hmap);
+}
+
+/* Returns the first node in MAP, or a null pointer if MAP is empty. See the
+ hmap_first function for information about complexity (O(1) amortized) and
+ ordering (arbitrary).
+
+ The STRING_MAP_FOR_EACH family of macros provide convenient ways to iterate
+ over all the nodes in a string map. */
+static inline struct string_map_node *
+string_map_first (const struct string_map *map)
+{
+ return HMAP_FIRST (struct string_map_node, hmap_node, &map->hmap);
+}
+
+/* Returns the next node in MAP following NODE, or a null pointer if NODE is
+ the last node in MAP. See the hmap_next function for information about
+ complexity (O(1) amortized) and ordering (arbitrary).
+
+ The STRING_MAP_FOR_EACH family of macros provide convenient ways to iterate
+ over all the nodes in a string map. */
+static inline struct string_map_node *
+string_map_next (const struct string_map *map,
+ const struct string_map_node *node)
+{
+ return HMAP_NEXT (node, struct string_map_node, hmap_node, &map->hmap);
+}
+
+#endif /* libpspp/string-map.h */
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* If you add routines in this file, please add a corresponding test to
+ string-set-test.c. */
+
+#include <config.h>
+
+#include <libpspp/string-set.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+
+#include "gl/xalloc.h"
+
+static struct string_set_node *string_set_find_node__ (
+ const struct string_set *, const char *, unsigned int hash);
+static void string_set_insert__ (struct string_set *, char *,
+ unsigned int hash);
+static bool string_set_delete__ (struct string_set *, const char *,
+ unsigned int hash);
+
+/* Initializes SET as a new string set that is initially empty. */
+void
+string_set_init (struct string_set *set)
+{
+ hmap_init (&set->hmap);
+}
+
+/* Initializes SET as a new string set that initially contains the same strings
+ as OLD. */
+void
+string_set_clone (struct string_set *set, const struct string_set *old)
+{
+ const struct string_set_node *node;
+ const char *s;
+
+ string_set_init (set);
+ hmap_reserve (&set->hmap, string_set_count (old));
+ STRING_SET_FOR_EACH (s, node, old)
+ string_set_insert__ (set, xstrdup (s), node->hmap_node.hash);
+}
+
+/* Exchanges the contents of string sets A and B. */
+void
+string_set_swap (struct string_set *a, struct string_set *b)
+{
+ hmap_swap (&a->hmap, &b->hmap);
+}
+
+/* Frees SET and its nodes and strings. */
+void
+string_set_destroy (struct string_set *set)
+{
+ if (set != NULL)
+ {
+ string_set_clear (set);
+ hmap_destroy (&set->hmap);
+ }
+}
+
+/* Returns true if SET contains S, false otherwise. */
+bool
+string_set_contains (const struct string_set *set, const char *s)
+{
+ return string_set_find_node (set, s) != NULL;
+}
+
+/* Returns the node in SET that contains S, or a null pointer if SET does not
+ contain S. */
+struct string_set_node *
+string_set_find_node (const struct string_set *set, const char *s)
+{
+ return string_set_find_node__ (set, s, hash_string (s, 0));
+}
+
+/* Inserts a copy of S into SET. Returns true if successful, false if SET
+ is unchanged because it already contained S. */
+bool
+string_set_insert (struct string_set *set, const char *s)
+{
+ unsigned int hash = hash_string (s, 0);
+ if (!string_set_find_node__ (set, s, hash))
+ {
+ string_set_insert__ (set, xstrdup (s), hash);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Inserts S, which must be a malloc'd string, into SET, transferring ownership
+ of S to SET. Returns true if successful, false if SET is unchanged because
+ it already contained a copy of S. (In the latter case, S is freed.) */
+bool
+string_set_insert_nocopy (struct string_set *set, char *s)
+{
+ unsigned int hash = hash_string (s, 0);
+ if (!string_set_find_node__ (set, s, hash))
+ {
+ string_set_insert__ (set, s, hash);
+ return true;
+ }
+ else
+ {
+ free (s);
+ return false;
+ }
+}
+
+/* Deletes S from SET. Returns true if successful, false if SET is unchanged
+ because it did not contain a copy of S. */
+bool
+string_set_delete (struct string_set *set, const char *s)
+{
+ return string_set_delete__ (set, s, hash_string (s, 0));
+}
+
+/* Deletes NODE from SET, and frees NODE and its string. */
+void
+string_set_delete_node (struct string_set *set, struct string_set_node *node)
+{
+ free (string_set_delete_nofree (set, node));
+}
+
+/* Deletes NODE from SET and frees NODE. Returns the string that NODE
+ contained, transferring ownership to the caller. */
+char *
+string_set_delete_nofree (struct string_set *set, struct string_set_node *node)
+{
+ char *string = node->string;
+ hmap_delete (&set->hmap, &node->hmap_node);
+ free (node);
+ return string;
+}
+
+/* Removes all nodes from SET. */
+void
+string_set_clear (struct string_set *set)
+{
+ struct string_set_node *node, *next;
+
+ HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+ &set->hmap)
+ string_set_delete_node (set, node);
+}
+
+/* Calculates A = union(A, B).
+
+ If B may be modified, string_set_union_and_intersection() is
+ faster than this function. */
+void
+string_set_union (struct string_set *a, const struct string_set *b)
+{
+ struct string_set_node *node;
+ HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
+ if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
+ string_set_insert__ (a, xstrdup (node->string), node->hmap_node.hash);
+}
+
+/* Calculates A = union(A, B) and B = intersect(A, B).
+
+ If only the intersection is needed, string_set_intersect() is
+ faster. */
+void
+string_set_union_and_intersection (struct string_set *a, struct string_set *b)
+{
+ struct string_set_node *node, *next;
+
+ HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+ &b->hmap)
+ if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
+ {
+ hmap_delete (&b->hmap, &node->hmap_node);
+ hmap_insert (&a->hmap, &node->hmap_node, node->hmap_node.hash);
+ }
+}
+
+/* Calculates A = intersect(A, B). */
+void
+string_set_intersect (struct string_set *a, const struct string_set *b)
+{
+ struct string_set_node *node, *next;
+
+ HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+ &a->hmap)
+ if (!string_set_find_node__ (b, node->string, node->hmap_node.hash))
+ string_set_delete_node (a, node);
+}
+
+/* Removes from A all of the strings in B. */
+void
+string_set_subtract (struct string_set *a, const struct string_set *b)
+{
+ struct string_set_node *node, *next;
+
+ if (string_set_count (a) < string_set_count (b))
+ {
+ HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
+ &a->hmap)
+ if (string_set_find_node__ (b, node->string, node->hmap_node.hash))
+ string_set_delete_node (a, node);
+ }
+ else
+ {
+ HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
+ string_set_delete__ (a, node->string, node->hmap_node.hash);
+ }
+}
+\f
+/* Internal functions. */
+
+static struct string_set_node *
+string_set_find_node__ (const struct string_set *set, const char *s,
+ unsigned int hash)
+{
+ struct string_set_node *node;
+
+ HMAP_FOR_EACH_WITH_HASH (node, struct string_set_node, hmap_node,
+ hash, &set->hmap)
+ if (!strcmp (s, node->string))
+ return node;
+
+ return NULL;
+}
+
+static void
+string_set_insert__ (struct string_set *set, char *s, unsigned int hash)
+{
+ struct string_set_node *node = xmalloc (sizeof *node);
+ node->string = s;
+ hmap_insert (&set->hmap, &node->hmap_node, hash);
+}
+
+static bool
+string_set_delete__ (struct string_set *set, const char *s, unsigned int hash)
+{
+ struct string_set_node *node = string_set_find_node__ (set, s, hash);
+ if (node != NULL)
+ {
+ string_set_delete_node (set, node);
+ return true;
+ }
+ else
+ return false;
+}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LIBPSPP_STRING_SET_H
+#define LIBPSPP_STRING_SET_H
+
+/* Set of unique strings.
+
+ This is a convenient wrapper around a "struct hmap" for storing strings. */
+
+#include <stdbool.h>
+#include <libpspp/hmap.h>
+
+/* A node in the string set. */
+struct string_set_node
+ {
+ struct hmap_node hmap_node;
+ char *string;
+ };
+
+/* Returns the string within NODE. The caller must not modify or free the
+ returned string. */
+static inline const char *
+string_set_node_get_string (const struct string_set_node *node)
+{
+ return node->string;
+}
+\f
+/* An unordered set of unique strings. */
+struct string_set
+ {
+ struct hmap hmap;
+ };
+
+/* Suitable for use as the initializer for a string_set named SET. Typical
+ usage:
+ struct string_set set = STRING_SET_INITIALIZER (set);
+ STRING_SET_INITIALIZER is an alternative to calling string_set_init. */
+#define STRING_SET_INITIALIZER(SET) { HMAP_INITIALIZER ((SET).hmap) }
+
+void string_set_init (struct string_set *);
+void string_set_clone (struct string_set *, const struct string_set *);
+void string_set_swap (struct string_set *, struct string_set *);
+void string_set_destroy (struct string_set *);
+
+static inline size_t string_set_count (const struct string_set *);
+static inline bool string_set_is_empty (const struct string_set *);
+
+bool string_set_contains (const struct string_set *, const char *);
+struct string_set_node *string_set_find_node (const struct string_set *,
+ const char *);
+
+bool string_set_insert (struct string_set *, const char *);
+bool string_set_insert_nocopy (struct string_set *, char *);
+bool string_set_delete (struct string_set *, const char *);
+void string_set_delete_node (struct string_set *, struct string_set_node *);
+char *string_set_delete_nofree (struct string_set *, struct string_set_node *);
+
+void string_set_clear (struct string_set *);
+void string_set_union (struct string_set *, const struct string_set *);
+void string_set_union_and_intersection (struct string_set *,
+ struct string_set *);
+void string_set_intersect (struct string_set *, const struct string_set *);
+void string_set_subtract (struct string_set *, const struct string_set *);
+
+static inline const struct string_set_node *string_set_first (
+ const struct string_set *);
+static inline const struct string_set_node *string_set_next (
+ const struct string_set *, const struct string_set_node *);
+
+/* Macros for conveniently iterating through a string_set, e.g. to print all of
+ the strings in "my_set":
+
+ struct string_set_node *node;
+ const char *string;
+
+ STRING_SET_FOR_EACH (string, node, &my_set)
+ puts (string);
+ */
+#define STRING_SET_FOR_EACH(STRING, NODE, SET) \
+ for ((NODE) = string_set_first (SET); \
+ ((NODE) != NULL \
+ ? ((STRING) = string_set_node_get_string (NODE), \
+ 1) \
+ : 0); \
+ (NODE) = string_set_next (SET, NODE))
+#define STRING_SET_FOR_EACH_SAFE(STRING, NODE, NEXT, SET) \
+ for ((NODE) = string_set_first (SET); \
+ ((NODE) != NULL \
+ ? ((STRING) = string_set_node_get_string (NODE), \
+ (NEXT) = string_set_next (SET, NODE), \
+ 1) \
+ : 0); \
+ (NODE) = (NEXT))
+\f
+/* Returns the number of strings currently in SET. */
+static inline size_t
+string_set_count (const struct string_set *set)
+{
+ return hmap_count (&set->hmap);
+}
+
+/* Returns true if SET currently contains no strings, false otherwise. */
+static inline bool
+string_set_is_empty (const struct string_set *set)
+{
+ return hmap_is_empty (&set->hmap);
+}
+
+/* Returns the first node in SET, or a null pointer if SET is empty. See the
+ hmap_first function for information about complexity (O(1) amortized) and
+ ordering (arbitrary).
+
+ The STRING_SET_FOR_EACH and STRING_SET_FOR_EACH_SAFE macros provide
+ convenient ways to iterate over all the nodes in a string set. */
+static inline const struct string_set_node *
+string_set_first (const struct string_set *set)
+{
+ return HMAP_FIRST (struct string_set_node, hmap_node, &set->hmap);
+}
+
+/* Returns the next node in SET following NODE, or a null pointer if NODE is
+ the last node in SET. See the hmap_next function for information about
+ complexity (O(1) amortized) and ordering (arbitrary).
+
+ The STRING_SET_FOR_EACH and STRING_SET_FOR_EACH_SAFE macros provide
+ convenient ways to iterate over all the nodes in a string set. */
+static inline const struct string_set_node *
+string_set_next (const struct string_set *set,
+ const struct string_set_node *node)
+{
+ return HMAP_NEXT (node, struct string_set_node, hmap_node, &set->hmap);
+}
+
+#endif /* libpspp/string-set.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <libpspp/array.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include "xalloc.h"
struct taint *
taint_clone (const struct taint *taint_)
{
- struct taint *taint = (struct taint *) taint_;
+ struct taint *taint = CONST_CAST (struct taint *, taint_);
assert (taint->ref_cnt > 0);
taint->ref_cnt++;
void
taint_propagate (const struct taint *from_, const struct taint *to_)
{
- struct taint *from = (struct taint *) from_;
- struct taint *to = (struct taint *) to_;
+ struct taint *from = CONST_CAST (struct taint *, from_);
+ struct taint *to = CONST_CAST (struct taint *, to_);
if (from != to)
{
void
taint_set_taint (const struct taint *taint_)
{
- struct taint *taint = (struct taint *) taint_;
+ struct taint *taint = CONST_CAST (struct taint *, taint_);
if (!taint->tainted)
recursively_set_taint (taint);
}
void
taint_reset_successor_taint (const struct taint *taint_)
{
- struct taint *taint = (struct taint *) taint_;
+ struct taint *taint = CONST_CAST (struct taint *, taint_);
if (taint->tainted_successor)
{
#include <stdlib.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include "error.h"
#include "xalloc.h"
static bool
do_seek (const struct tmpfile *tf_, off_t offset)
{
- struct tmpfile *tf = (struct tmpfile *) tf_;
+ struct tmpfile *tf = CONST_CAST (struct tmpfile *, tf_);
if (!tmpfile_error (tf))
{
static bool
do_read (const struct tmpfile *tf_, void *buffer, size_t bytes)
{
- struct tmpfile *tf = (struct tmpfile *) tf_;
+ struct tmpfile *tf = CONST_CAST (struct tmpfile *, tf_);
assert (!tmpfile_error (tf));
if (bytes > 0 && fread (buffer, bytes, 1, tf->file) != 1)
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <limits.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <libpspp/compiler.h>
static struct tower_node *abt_to_tower_node (const struct abt_node *);
unsigned long height,
unsigned long *node_start)
{
- struct tower *t = (struct tower *) t_;
+ struct tower *t = CONST_CAST (struct tower *, t_);
struct abt_node *p;
assert (height < tower_height (t));
struct tower_node *
tower_get (const struct tower *t_, unsigned long int index)
{
- struct tower *t = (struct tower *) t_;
+ struct tower *t = CONST_CAST (struct tower *, t_);
struct abt_node *p;
assert (index < tower_count (t));
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <stdbool.h>
#include <libpspp/abt.h>
+#include <libpspp/cast.h>
/* Returns the data structure corresponding to the given NODE,
assuming that NODE is embedded as the given MEMBER name in
data type STRUCT. */
-#define tower_data(NODE, STRUCT, MEMBER) \
- ((STRUCT *) ((char *) (NODE) - offsetof (STRUCT, MEMBER)))
+#define tower_data(NODE, STRUCT, MEMBER) \
+ (CHECK_POINTER_HAS_TYPE (NODE, struct tower_node *), \
+ UP_CAST (NODE, STRUCT, MEMBER))
/* A node within a tower. */
struct tower_node
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "tukey-hinges.h"
#include <gl/xalloc.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <math.h>
#include <float.h>
#include <data/val-type.h>
static void
destroy (struct statistic *s)
{
- struct order_stats *os = (struct order_stats *) s;
- struct box_whisker *bw = (struct box_whisker *) s;
+ struct box_whisker *bw = UP_CAST (s, struct box_whisker, parent.parent);
+ struct order_stats *os = &bw->parent;
struct ll *ll;
for (ll = ll_head (&bw->outliers); ll != ll_null (&bw->outliers); )
acc (struct statistic *s, const struct ccase *cx,
double c UNUSED, double cc UNUSED, double y)
{
- struct box_whisker *bw = (struct box_whisker *) s;
+ struct box_whisker *bw = UP_CAST (s, struct box_whisker, parent.parent);
bool extreme;
struct outlier *o;
return &bw->outliers;
}
-struct statistic *
+struct box_whisker *
box_whisker_create (const struct tukey_hinges *th,
const struct variable *id_var, size_t casenumber_idx)
{
struct box_whisker *w = xzalloc (sizeof (*w));
- struct order_stats *os = (struct order_stats *) w;
- struct statistic *stat = (struct statistic *) w;
+ struct order_stats *os = &w->parent;
+ struct statistic *stat = &os->parent;
os->n_k = 0;
ll_init (&w->outliers);
- return stat;
+ return w;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
const struct variable *id_var;
};
-struct statistic * box_whisker_create (const struct tukey_hinges *,
+struct box_whisker * box_whisker_create (const struct tukey_hinges *,
const struct variable *, size_t);
void box_whisker_whiskers (const struct box_whisker *bw, double whiskers[2]);
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <gl/xalloc.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <gsl/gsl_histogram.h>
#include "chart-geometry.h"
void
histogram_add (struct histogram *h, double y, double c)
{
- ((struct statistic *)h)->accumulate ((struct statistic *) h, NULL, c, 0, y);
+ struct statistic *stat = &h->parent;
+ stat->accumulate (stat, NULL, c, 0, y);
}
static void
acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc UNUSED, double y)
{
- struct histogram *hist = (struct histogram *) s;
+ struct histogram *hist = UP_CAST (s, struct histogram, parent);
gsl_histogram_accumulate (hist->gsl_hist, y, c);
}
static void
destroy (struct statistic *s)
{
- struct histogram *h = (struct histogram *) s;
+ struct histogram *h = UP_CAST (s, struct histogram, parent);
gsl_histogram_free (h->gsl_hist);
free (s);
}
-struct statistic *
+struct histogram *
histogram_create (int bins, double min, double max)
{
struct histogram *h = xmalloc (sizeof *h);
- struct statistic *stat = (struct statistic *) h;
+ struct statistic *stat = &h->parent;
double upper_limit, lower_limit;
double bin_width = chart_rounded_tick ((max - min) / (double) bins);
stat->accumulate = acc;
stat->destroy = destroy;
- return stat;
+ return h;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
gsl_histogram *gsl_hist;
};
-struct statistic * histogram_create (int bins, double max, double min);
+struct histogram * histogram_create (int bins, double max, double min);
void histogram_add (struct histogram *h, double y, double c);
struct hsh_table *hash = group_proc_get (var)->group_hash;
- for(g = (struct group_statistics *) hsh_first(hash,&hi);
- g != 0 ;
- g = (struct group_statistics *) hsh_next(hash,&hi) )
+ for (g = hsh_first(hash,&hi); g != 0; g = hsh_next(hash, &hi))
{
g->lz_mean = g->lz_total / g->n ;
}
struct group_proc *gp = group_proc_get (var);
struct hsh_table *hash = gp->group_hash;
- for(g = (struct group_statistics *) hsh_first(hash,&hi);
- g != 0 ;
- g = (struct group_statistics *) hsh_next(hash,&hi) )
+ for (g = hsh_first(hash, &hi); g != 0; g = hsh_next(hash, &hi))
{
lz_numerator += g->n * pow2(g->lz_mean - l->lz[v].grand_mean );
}
#include <data/case.h>
#include <data/casewriter.h>
#include <libpspp/compiler.h>
+#include <libpspp/cast.h>
#include <libpspp/misc.h>
#include <math/moments.h>
static void
destroy (struct statistic *stat)
{
- struct order_stats *os = (struct order_stats *) stat;
- free (os);
+ struct np *np = UP_CAST (stat, struct np, parent.parent);
+ free (np);
}
double c, double cc, double y)
{
struct ccase *cp;
- struct np *np = (struct np *) s;
+ struct np *np = UP_CAST (s, struct np, parent.parent);
double rank = np->prev_cc + (c + 1) / 2.0;
double ns = gsl_cdf_ugaussian_Pinv (rank / ( np->n + 1 ));
np->prev_cc = cc;
}
-struct order_stats *
+struct np *
np_create (const struct moments1 *m)
{
double variance;
struct np *np = xzalloc (sizeof (*np));
- struct statistic *stat = (struct statistic *) np;
- struct order_stats *os = (struct order_stats *) np;
+ struct order_stats *os = &np->parent;
+ struct statistic *stat = &os->parent;
struct caseproto *proto;
int i;
stat->destroy = destroy;
stat->accumulate = acc;
- return os;
+ return np;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
};
-struct order_stats * np_create (const struct moments1 *);
+struct np * np_create (const struct moments1 *);
#endif
{
int k;
struct order_stats *tos = os[j];
- struct statistic *stat = (struct statistic *) tos;
+ struct statistic *stat = &tos->parent;
for (k = 0 ; k < tos->n_k; ++k)
{
struct k *myk = &tos->k[k];
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#define N_(msgid) msgid
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <data/val-type.h>
#include <gl/xalloc.h>
#include <data/variable.h>
double
percentile_calculate (const struct percentile *ptl, enum pc_alg alg)
{
- struct percentile *mutable = (struct percentile *) ptl;
+ struct percentile *mutable = CONST_CAST (struct percentile *, ptl);
const struct order_stats *os = &ptl->parent;
assert (os->cc == ptl->w);
static void
destroy (struct statistic *stat)
{
- struct order_stats *os = (struct order_stats *) stat;
+ struct percentile *ptl = UP_CAST (stat, struct percentile, parent.parent);
+ struct order_stats *os = &ptl->parent;
free (os->k);
- free (os);
+ free (ptl);
}
-struct order_stats *
+struct percentile *
percentile_create (double p, double W)
{
struct percentile *ptl = xzalloc (sizeof (*ptl));
- struct order_stats *os = (struct order_stats *) ptl;
- struct statistic *stat = (struct statistic *) ptl;
+ struct order_stats *os = &ptl->parent;
+ struct statistic *stat = &os->parent;
assert (p >= 0);
assert (p <= 1.0);
stat->destroy = destroy;
- return os;
+ return ptl;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/* Create the Pth percentile.
W is the total sum of weights in the data set
*/
-struct order_stats *percentile_create (double p, double W);
+struct percentile *percentile_create (double p, double W);
/* Return the value of the percentile */
double percentile_calculate (const struct percentile *ptl, enum pc_alg alg);
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <gl/xalloc.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <math.h>
#include <data/val-type.h>
static void
acc (struct statistic *s, const struct ccase *cx UNUSED, double c, double cc, double y)
{
- struct trimmed_mean *tm = (struct trimmed_mean *) s;
- struct order_stats *os = (struct order_stats *) s;
+ struct trimmed_mean *tm = UP_CAST (s, struct trimmed_mean, parent.parent);
+ struct order_stats *os = &tm->parent;
if ( cc > os->k[0].tc && cc < os->k[1].tc)
tm->sum += c * y;
static void
destroy (struct statistic *s)
{
- struct order_stats *os = (struct order_stats *) s;
+ struct trimmed_mean *tm = UP_CAST (s, struct trimmed_mean, parent.parent);
+ struct order_stats *os = &tm->parent;
free (os->k);
- free (s);
+ free (tm);
}
-struct statistic *
+struct trimmed_mean *
trimmed_mean_create (double W, double tail)
{
struct trimmed_mean *tm = xzalloc (sizeof (*tm));
- struct order_stats *os = (struct order_stats *) tm;
- struct statistic *stat = (struct statistic *) tm;
+ struct order_stats *os = &tm->parent;
+ struct statistic *stat = &os->parent;
os->n_k = 2;
os->k = xcalloc (sizeof (*os->k), 2);
tm->w = W;
tm->tail = tail;
- return stat;
+ return tm;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
double tail;
};
-struct statistic * trimmed_mean_create (double W, double c_min);
+struct trimmed_mean * trimmed_mean_create (double W, double c_min);
double trimmed_mean_calculate (const struct trimmed_mean *);
#endif
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <gl/xalloc.h>
#include <libpspp/assertion.h>
+#include <libpspp/cast.h>
#include <math.h>
void
static void
destroy (struct statistic *s)
{
- struct order_stats *os = (struct order_stats *) s;
+ struct tukey_hinges *th = UP_CAST (s, struct tukey_hinges, parent.parent);
+ struct order_stats *os = &th->parent;
free (os->k);
free (s);
};
-struct statistic *
+struct tukey_hinges *
tukey_hinges_create (double W, double c_min)
{
double d;
struct tukey_hinges *th = xzalloc (sizeof (*th));
- struct order_stats *os = (struct order_stats *) th;
- struct statistic *stat = (struct statistic *) th;
+ struct order_stats *os = &th->parent;
+ struct statistic *stat = &os->parent;
assert (c_min >= 0);
stat->destroy = destroy;
- return stat;
+ return th;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
struct order_stats parent;
};
-struct statistic * tukey_hinges_create (double W, double c_min);
+struct tukey_hinges * tukey_hinges_create (double W, double c_min);
void tukey_hinges_calculate (const struct tukey_hinges *h, double hinge[3]);
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-#include "afm.h"
-#include "c-ctype.h"
-#include "c-strtod.h"
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <setjmp.h>
-#include "error.h"
-#include "minmax.h"
-#include <libpspp/assertion.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* A kern pair entry. */
-struct afm_kern_pair
- {
- struct afm_character *successor; /* Second character. */
- int adjust; /* Adjustment. */
- };
-
-/* A ligature. */
-struct afm_ligature
- {
- struct afm_character *successor; /* Second character. */
- struct afm_character *ligature; /* Resulting ligature. */
- };
-
-/* How to map between byte strings and character values. */
-enum mapping_scheme
- {
- MAP_UNKNOWN, /* Not yet determined. */
- MAP_ONE_BYTE, /* 8-bit coding. */
- MAP_TWO_BYTE, /* 16-bit coding. */
- MAP_ESCAPE, /* 8-bit coding with escape to change fonts. */
- MAP_DOUBLE_ESCAPE, /* 8-bit coding with multiple escapes. */
- MAP_SHIFT /* 8-bit coding with 2 fonts that toggle. */
- };
-
-/* AFM file data. */
-struct afm
- {
- struct pool *pool; /* Containing pool. */
- char *findfont_name; /* Name for PostScript /findfont operator. */
- int ascent; /* Height above the baseline (non-negative). */
- int descent; /* Depth below the baseline (non-negative). */
-
- /* Encoding characters into strings. */
- enum mapping_scheme mapping; /* Basic mapping scheme. */
- char escape_char; /* MAP_ESCAPE only: escape character to use. */
- char shift_out; /* MAP_SHIFT only: selects font 0. */
- char shift_in; /* MAP_SHIFT only: selects font 1. */
-
- /* Characters. */
- struct afm_character *undefined_codes[256];
- struct afm_character **codes[256];
- struct afm_character **chars;
- size_t char_cnt;
- };
-
-/* AFM file parser. */
-struct parser
- {
- struct pool *pool; /* Containing pool. */
- struct afm *afm; /* AFM being parsed. */
- FILE *file; /* File being parsed. */
- const char *file_name; /* Name of file being parsed. */
- int line_number; /* Current line number in file. */
- jmp_buf bail_out; /* longjmp() target for error handling. */
-
- size_t char_allocated;
- int max_code;
- };
-
-static struct afm *create_afm (void);
-static struct afm_character *create_character (struct afm *);
-
-static void afm_error (struct parser *, const char *, ...)
- PRINTF_FORMAT (2, 3)
- NO_RETURN;
-
-static void parse_afm (struct parser *);
-static void skip_section (struct parser *, const char *end_key);
-static bool parse_set_specific (struct parser *, const char *end_key);
-static void parse_direction (struct parser *);
-static void parse_char_metrics (struct parser *);
-static void parse_kern_pairs (struct parser *);
-static void add_kern_pair (struct parser *p,
- struct afm_character *, struct afm_character *,
- int adjust);
-
-static int skip_spaces (struct parser *);
-static char *parse_key (struct parser *);
-static void skip_line (struct parser *);
-static void force_eol (struct parser *);
-static bool get_integer (struct parser *, int *);
-static int force_get_integer (struct parser *);
-static bool get_number (struct parser *, int *);
-static int force_get_number (struct parser *);
-static bool get_hex_code (struct parser *, int *);
-static int force_get_hex_code (struct parser *);
-static bool get_word (struct parser *, char **);
-static char *force_get_word (struct parser *);
-static bool get_string (struct parser *, char **);
-static char *force_get_string (struct parser *);
-
-static struct afm_character *get_char_by_name (struct parser *, const char *);
-static struct afm_character *get_char_by_code (const struct afm *, int code);
-
-/* Reads FILE_NAME as an AFM file and returns the metrics data.
- Returns a null pointer if the file cannot be parsed. */
-struct afm *
-afm_open (const char *file_name)
-{
- struct afm *volatile afm;
- struct parser *parser;
-
- parser = pool_create_container (struct parser, pool);
- afm = parser->afm = create_afm ();
- parser->file = pool_fopen (parser->pool, file_name, "r");
- parser->file_name = file_name;
- parser->line_number = 0;
- if (parser->file == NULL)
- {
- error (0, errno, _("opening font metrics file \"%s\""), file_name);
- goto error;
- }
-
- if (setjmp (parser->bail_out))
- goto error;
-
- parse_afm (parser);
- pool_destroy (parser->pool);
- return afm;
-
- error:
- pool_destroy (parser->pool);
- pool_destroy (afm->pool);
- return create_afm ();
-}
-
-/* Creates and returns an empty set of metrics. */
-static struct afm *
-create_afm (void)
-{
- struct afm *afm;
- struct afm_character *def_char;
- size_t i;
-
- afm = pool_create_container (struct afm, pool);
- afm->findfont_name = NULL;
- afm->ascent = 0;
- afm->descent = 0;
- afm->mapping = MAP_UNKNOWN;
- afm->escape_char = 255;
- afm->shift_out = 14;
- afm->shift_in = 15;
- def_char = create_character (afm);
- for (i = 0; i < 256; i++)
- afm->undefined_codes[i] = def_char;
- for (i = 0; i < 256; i++)
- afm->codes[i] = afm->undefined_codes;
- afm->chars = NULL;
- afm->char_cnt = 0;
-
- return afm;
-}
-
-/* Creates and returns an initialized character within AFM. */
-static struct afm_character *
-create_character (struct afm *afm)
-{
- struct afm_character *c = pool_alloc (afm->pool, sizeof *c);
- c->code = ' ';
- c->name = NULL;
- c->width = 12000;
- c->ascent = 0;
- c->descent = 0;
- c->kern_pairs = NULL;
- c->kern_pair_cnt = 0;
- c->ligatures = NULL;
- c->ligature_cnt = 0;
- return c;
-}
-
-/* Reports the given MESSAGE at the current line in parser P
- and bails out with longjmp(). */
-static void
-afm_error (struct parser *p, const char *message, ...)
-{
- va_list args;
- char *msg;
-
- va_start (args, message);
- msg = xasprintf (message, args);
- va_end (args);
-
- error_at_line (0, 0, p->file_name, p->line_number, "%s", msg);
- free (msg);
-
- longjmp (p->bail_out, 1);
-}
-
-/* Parses an AFM file with parser P. */
-static void
-parse_afm (struct parser *p)
-{
- char *key;
-
- p->char_allocated = 0;
- p->max_code = 0;
-
- key = force_get_word (p);
- if (strcmp (key, "StartFontMetrics"))
- afm_error (p, _("first line must be StartFontMetrics"));
- skip_line (p);
-
- do
- {
- key = parse_key (p);
- if (!strcmp (key, "FontName"))
- p->afm->findfont_name = pool_strdup (p->afm->pool,
- force_get_string (p));
- else if (!strcmp (key, "Ascender"))
- p->afm->ascent = force_get_integer (p);
- else if (!strcmp (key, "Descender"))
- p->afm->descent = force_get_integer (p);
- else if (!strcmp (key, "MappingScheme"))
- {
- int scheme = force_get_integer (p);
- if (scheme == 4)
- p->afm->mapping = MAP_ONE_BYTE;
- else if (scheme == 2 || scheme == 5 || scheme == 6)
- p->afm->mapping = MAP_TWO_BYTE;
- else if (scheme == 3)
- p->afm->mapping = MAP_ESCAPE;
- else if (scheme == 7)
- p->afm->mapping = MAP_DOUBLE_ESCAPE;
- else if (scheme == 8)
- p->afm->mapping = MAP_SHIFT;
- else
- afm_error (p, _("unsupported MappingScheme %d"), scheme);
- }
- else if (!strcmp (key, "EscChar"))
- p->afm->escape_char = force_get_integer (p);
- else if (!strcmp (key, "StartDirection"))
- parse_direction (p);
- else if (!strcmp (key, "StartCharMetrics"))
- parse_char_metrics (p);
- else if (!strcmp (key, "StartKernPairs")
- || !strcmp (key, "StartKernPairs0"))
- parse_kern_pairs (p);
- else if (!strcmp (key, "StartTrackKern"))
- skip_section (p, "EndTrackKern");
- else if (!strcmp (key, "StartComposites"))
- skip_section (p, "EndComposites");
- else
- skip_line (p);
- }
- while (strcmp (key, "EndFontMetrics"));
-
- if (p->afm->findfont_name == NULL)
- afm_error (p, _("required FontName is missing"));
- if (p->afm->mapping == MAP_UNKNOWN)
- {
- /* There seem to be a number of fonts out there that use a
- 2-byte encoding but don't announce it with
- MappingScheme. */
- p->afm->mapping = p->max_code > 255 ? MAP_TWO_BYTE : MAP_ONE_BYTE;
- }
-}
-
-/* Reads lines from parser P until one starts with END_KEY. */
-static void
-skip_section (struct parser *p, const char *end_key)
-{
- const char *key;
- skip_line (p);
- do
- {
- key = parse_key (p);
- skip_line (p);
- }
- while (strcmp (key, end_key));
-}
-
-/* Attempts to read an integer from parser P.
- If one is found, and it is nonzero, skips lines until END_KEY
- is encountered and returns false.
- Otherwise, skips the rest of the line and returns true.
- (This is useful because AFM files can have multiple sets of
- metrics. Set 0 is for normal text, other sets are for
- vertical text, etc. We only care about set 0.) */
-static bool
-parse_set_specific (struct parser *p, const char *end_key)
-{
- int set;
-
- if (get_integer (p, &set) && set != 0)
- {
- skip_section (p, end_key);
- return false;
- }
- else
- {
- force_eol (p);
- return true;
- }
-}
-
-/* Parses a StartDirection...EndDirection section in parser P. */
-static void
-parse_direction (struct parser *p)
-{
- const char *key;
-
- if (!parse_set_specific (p, "EndDirection"))
- return;
-
- do
- {
- key = parse_key (p);
- if (!strcmp (key, "CharWidth"))
- p->afm->codes[0][0]->width = force_get_integer (p);
- skip_line (p);
- }
- while (strcmp (key, "EndDirection"));
-}
-
-/* Parses a StartCharMetrics...EndCharMetrics section in parser
- P. */
-static void
-parse_char_metrics (struct parser *p)
-{
- struct parsing_ligature
- {
- struct afm_character *first;
- char *successor;
- char *ligature;
- };
-
- struct parsing_ligature *ligatures = NULL;
- size_t ligature_cnt = 0;
- size_t ligature_allocated = 0;
-
- size_t i;
-
- skip_line (p);
-
- for (;;)
- {
- char *key;
- struct afm_character *c;
-
- key = parse_key (p);
- if (!strcmp (key, "EndCharMetrics"))
- break;
-
- if (p->afm->char_cnt == p->char_allocated)
- p->afm->chars = pool_2nrealloc (p->afm->pool, p->afm->chars,
- &p->char_allocated,
- sizeof *p->afm->chars);
- c = create_character (p->afm);
-
- if (!strcmp (key, "C"))
- c->code = force_get_integer (p);
- else if (!strcmp (key, "CH"))
- c->code = force_get_hex_code (p);
- else
- afm_error (p, _("CharMetrics line must start with C or CH"));
- if (c->code < 0 || c->code > 65535)
- c->code = -1;
-
- if (c->code > p->max_code)
- p->max_code = c->code;
-
- p->afm->chars[p->afm->char_cnt++] = c;
- if (c->code != -1)
- p->afm->codes[c->code >> 8][c->code & 0xff] = c;
-
- key = force_get_word (p);
- while (!strcmp (key, ";"))
- {
- if (!get_word (p, &key))
- break;
-
- if (!strcmp (key, "N"))
- c->name = force_get_word (p);
- else if (!strcmp (key, "WX") || !strcmp (key, "W0X"))
- c->width = force_get_number (p);
- else if (!strcmp (key, "W") || !strcmp (key, "W0"))
- {
- c->width = force_get_number (p);
- force_get_number (p);
- }
- else if (!strcmp (key, "B"))
- {
- int llx, lly, urx, ury;
- llx = force_get_number (p);
- lly = force_get_number (p);
- urx = force_get_number (p);
- ury = force_get_number (p);
- c->ascent = MAX (0, ury);
- c->descent = MAX (0, -lly);
- }
- else if (!strcmp (key, "L"))
- {
- struct parsing_ligature *ligature;
- if (ligature_cnt == ligature_allocated)
- ligatures = pool_2nrealloc (p->pool, ligatures,
- &ligature_allocated,
- sizeof *ligatures);
- ligature = &ligatures[ligature_cnt++];
- ligature->first = c;
- ligature->successor = force_get_word (p);
- ligature->ligature = force_get_word (p);
- }
- else
- {
- while (strcmp (key, ";"))
- key = force_get_word (p);
- continue;
- }
- if (!get_word (p, &key))
- break;
- }
- }
- skip_line (p);
-
- for (i = 0; i < ligature_cnt; i++)
- {
- struct parsing_ligature *src = &ligatures[i];
- struct afm_ligature *dst;
- src->first->ligatures = pool_nrealloc (p->afm->pool,
- src->first->ligatures,
- src->first->ligature_cnt + 1,
- sizeof *src->first->ligatures);
- dst = &src->first->ligatures[src->first->ligature_cnt++];
- dst->successor = get_char_by_name (p, src->successor);
- dst->ligature = get_char_by_name (p, src->ligature);
- }
-}
-
-/* Parses a StartKernPairs...EndKernPairs section in parser P. */
-static void
-parse_kern_pairs (struct parser *p)
-{
- char *key;
-
- skip_line (p);
-
- do
- {
- struct afm_character *c1, *c2;
- int adjust;
-
- key = parse_key (p);
- if (!strcmp (key, "KP") || !strcmp (key, "KPX"))
- {
- c1 = get_char_by_name (p, force_get_word (p));
- c2 = get_char_by_name (p, force_get_word (p));
- adjust = force_get_number (p);
- if (!strcmp (key, "KP"))
- force_get_number (p);
- add_kern_pair (p, c1, c2, adjust);
- }
- else if (!strcmp (key, "KPH"))
- {
- c1 = get_char_by_code (p->afm, force_get_hex_code (p));
- c2 = get_char_by_code (p->afm, force_get_hex_code (p));
- adjust = force_get_number (p);
- force_get_number (p);
- add_kern_pair (p, c1, c2, adjust);
- }
- else
- skip_line (p);
- }
- while (strcmp (key, "EndKernPairs"));
-}
-
-/* Adds a kern pair that adjusts (FIRST, SECOND) by ADJUST units
- to the metrics within parser P. */
-static void
-add_kern_pair (struct parser *p, struct afm_character *first,
- struct afm_character *second, int adjust)
-{
- struct afm_kern_pair *kp;
-
- first->kern_pairs = pool_nrealloc (p->afm->pool, first->kern_pairs,
- first->kern_pair_cnt + 1,
- sizeof *first->kern_pairs);
- kp = &first->kern_pairs[first->kern_pair_cnt++];
- kp->successor = second;
- kp->adjust = adjust;
-}
-
-/* Returns the character with the given NAME with the metrics for
- parser P. Reports an error if no character has the given
- name. */
-static struct afm_character *
-get_char_by_name (struct parser *p, const char *name)
-{
- size_t i;
-
- for (i = 0; i < p->afm->char_cnt; i++)
- {
- struct afm_character *c = p->afm->chars[i];
- if (c->name != NULL && !strcmp (c->name, name))
- return c;
- }
- afm_error (p, _("reference to unknown character \"%s\""), name);
-}
-
-/* Returns the character with the given CODE within AFM.
- Returns a default character if the font doesn't have a
- character with that code. */
-static struct afm_character *
-get_char_by_code (const struct afm *afm, int code_)
-{
- uint16_t code = code_;
- return afm->codes[code >> 8][code & 0xff];
-}
-\f
-/* Skips white space, except for new-lines, within parser P. */
-static int
-skip_spaces (struct parser *p)
-{
- int c;
- while (isspace (c = getc (p->file)) && c != '\n')
- continue;
- ungetc (c, p->file);
- return c;
-}
-
-/* Parses a word at the beginning of a line.
- Skips comments.
- Reports an error if not at the beginning of a line. */
-static char *
-parse_key (struct parser *p)
-{
- force_eol (p);
- for (;;)
- {
- char *key;
-
- do
- {
- p->line_number++;
- getc (p->file);
- }
- while (skip_spaces (p) == '\n');
-
- key = force_get_word (p);
- if (strcmp (key, "Comment"))
- return key;
-
- skip_line (p);
- }
-}
-
-/* Skips to the next line within parser P. */
-static void
-skip_line (struct parser *p)
-{
- for (;;)
- {
- int c = getc (p->file);
- if (c == EOF)
- afm_error (p, _("expected end of file"));
- if (c == '\n')
- break;
- }
- ungetc ('\n', p->file);
-}
-
-/* Ensures that parser P is at the end of a line. */
-static void
-force_eol (struct parser *p)
-{
- if (skip_spaces (p) != '\n')
- afm_error (p, _("syntax error expecting end of line"));
-}
-
-/* Tries to read an integer into *INTEGER at the current position
- in parser P.
- Returns success. */
-static bool
-get_integer (struct parser *p, int *integer)
-{
- int c = skip_spaces (p);
- if (isdigit (c) || c == '-')
- {
- char *tail;
- long tmp;
-
- errno = 0;
- tmp = strtol (force_get_word (p), &tail, 10);
- if (errno == ERANGE || tmp < INT_MIN || tmp > INT_MAX)
- afm_error (p, _("number out of valid range"));
- if (*tail != '\0')
- afm_error (p, _("invalid numeric syntax"));
- *integer = tmp;
-
- return true;
- }
- else
- return false;
-}
-
-/* Returns an integer read from the current position in P.
- Reports an error if unsuccessful. */
-static int
-force_get_integer (struct parser *p)
-{
- int integer;
- if (!get_integer (p, &integer))
- afm_error (p, _("syntax error expecting integer"));
- return integer;
-}
-
-/* Tries to read a floating-point number at the current position
- in parser P. Stores the number's integer part into *INTEGER.
- Returns success. */
-static bool
-get_number (struct parser *p, int *integer)
-{
- int c = skip_spaces (p);
- if (c == '-' || c == '.' || isdigit (c))
- {
- char *tail;
- double number;
-
- errno = 0;
- number = c_strtod (force_get_word (p), &tail);
- if (errno == ERANGE || number < INT_MIN || number > INT_MAX)
- afm_error (p, _("number out of valid range"));
- if (*tail != '\0')
- afm_error (p, _("invalid numeric syntax"));
- *integer = number;
-
- return true;
- }
- else
- return false;
-}
-
-/* Returns the integer part of a floating-point number read from
- the current position in P.
- Reports an error if unsuccessful. */
-static int
-force_get_number (struct parser *p)
-{
- int integer;
- if (!get_number (p, &integer))
- afm_error (p, _("syntax error expecting number"));
- return integer;
-}
-
-/* Tries to read an integer expressed in hexadecimal into
- *INTEGER from P.
- Returns success. */
-static bool
-get_hex_code (struct parser *p, int *integer)
-{
- if (skip_spaces (p) == '<')
- {
- if (fscanf (p->file, "<%x", integer) != 1 || getc (p->file) != '>')
- afm_error (p, _("syntax error in hex constant"));
- return true;
- }
- else
- return false;
-}
-
-/* Reads an integer expressed in hexadecimal and returns its
- value.
- Reports an error if unsuccessful. */
-static int
-force_get_hex_code (struct parser *p)
-{
- int integer;
- if (!get_hex_code (p, &integer))
- afm_error (p, _("syntax error expecting hex constant"));
- return integer;
-}
-
-/* Tries to read a word from P into *WORD.
- The word is allocated in P's pool.
- Returns success. */
-static bool
-get_word (struct parser *p, char **word)
-{
- if (skip_spaces (p) != '\n')
- {
- struct string s;
- int c;
-
- ds_init_empty (&s);
- while (!isspace (c = getc (p->file)) && c != EOF)
- ds_put_char (&s, c);
- ungetc (c, p->file);
- *word = ds_cstr (&s);
- pool_register (p->pool, free, *word);
- return true;
- }
- else
- {
- *word = NULL;
- return false;
- }
-}
-
-/* Reads a word from P and returns it.
- The word is allocated in P's pool.
- Reports an error if unsuccessful. */
-static char *
-force_get_word (struct parser *p)
-{
- char *word;
- if (!get_word (p, &word))
- afm_error (p, _("unexpected end of line"));
- return word;
-}
-
-/* Reads a string, consisting of the remainder of the current
- line, from P, and stores it in *STRING.
- Leading and trailing spaces are removed.
- The word is allocated in P's pool.
- Returns true if a non-empty string was successfully read,
- false otherwise. */
-static bool
-get_string (struct parser *p, char **string)
-{
- struct string s = DS_EMPTY_INITIALIZER;
-
- skip_spaces (p);
- for (;;)
- {
- int c = getc (p->file);
- if (c == EOF || c == '\n')
- break;
- ds_put_char (&s, c);
- }
- ungetc ('\n', p->file);
- ds_rtrim (&s, ss_cstr (CC_SPACES));
-
- if (!ds_is_empty (&s))
- {
- *string = ds_cstr (&s);
- pool_register (p->pool, free, *string);
- return true;
- }
- else
- {
- *string = NULL;
- ds_destroy (&s);
- return false;
- }
-}
-
-/* Reads a string, consisting of the remainder of the current
- line, from P, and returns it.
- Leading and trailing spaces are removed.
- The word is allocated in P's pool.
- Reports an error if the string is empty. */
-static char *
-force_get_string (struct parser *p)
-{
- char *string;
- if (!get_string (p, &string))
- afm_error (p, _("unexpected end of line expecting string"));
- return string;
-}
-\f
-/* Closes AFM and frees its storage. */
-void
-afm_close (struct afm *afm)
-{
- if (afm != NULL)
- pool_destroy (afm->pool);
-}
-
-/* Returns the string that must be passed to the PostScript
- "findfont" operator to obtain AFM's font. */
-const char *
-afm_get_findfont_name (const struct afm *afm)
-{
- return afm->findfont_name;
-}
-
-/* Returns the ascent for AFM, that is, the font's height above
- the baseline, in units of 1/1000 of the nominal font size. */
-int
-afm_get_ascent (const struct afm *afm)
-{
- return afm->ascent;
-}
-
-/* Returns the descent for AFM, that is, the font's depth below
- the baseline, in units of 1/1000 of the nominal font size. */
-int
-afm_get_descent (const struct afm *afm)
-{
- return afm->descent;
-}
-
-/* Returns the character numbered CODE within AFM,
- or a default character if the font has none. */
-const struct afm_character *
-afm_get_character (const struct afm *afm, int code)
-{
- return get_char_by_code (afm, code);
-}
-
-/* Returns the ligature formed when FIRST is followed by SECOND,
- or a null pointer if there is no such ligature. */
-const struct afm_character *
-afm_get_ligature (const struct afm_character *first,
- const struct afm_character *second)
-{
- size_t i;
-
- for (i = 0; i < first->ligature_cnt; i++)
- if (first->ligatures[i].successor == second)
- return first->ligatures[i].ligature;
- return NULL;
-}
-
-/* Returns the pair kerning x-adjustment when FIRST is followed
- by SECOND, or 0 if no pair kerning should be done for the
- given pair of characters. */
-int
-afm_get_kern_adjustment (const struct afm_character *first,
- const struct afm_character *second)
-{
- size_t i;
-
- for (i = 0; i < first->kern_pair_cnt; i++)
- if (first->kern_pairs[i].successor == second)
- return first->kern_pairs[i].adjust;
- return 0;
-}
-\f
-/* Encodes the N characters in S as a PostScript string in OUT,
- using a single-byte encoding.
- Returns the number of characters remaining after all those
- that could be successfully encoded were. */
-static size_t
-encode_one_byte (const struct afm_character **s, size_t n,
- struct string *out)
-{
- ds_put_char (out, '(');
- for (; n > 0; s++, n--)
- {
- uint8_t code = (*s)->code;
- if (code != (*s)->code)
- break;
-
- if (code == '(' || code == ')' || code == '\\')
- ds_put_format (out, "\\%c", code);
- else if (!c_isprint (code))
- ds_put_format (out, "\\%03o", code);
- else
- ds_put_char (out, code);
- }
- ds_put_char (out, ')');
- return n;
-}
-
-/* State of binary encoder for PostScript. */
-struct binary_encoder
- {
- struct string *out; /* Output string. */
- uint32_t b; /* Accumulated bytes for base-85 encoding. */
- size_t n; /* Number of bytes in b (0...3). */
- };
-
-/* Initializes encoder E for output to OUT. */
-static void
-binary_init (struct binary_encoder *e, struct string *out)
-{
- e->out = out;
- e->b = e->n = 0;
-}
-
-/* Returns the character that represents VALUE in ASCII85
- encoding. */
-static int
-value_to_ascii85 (int value)
-{
- assert (value >= 0 && value < 85);
-#if C_CTYPE_ASCII
- return value + 33;
-#else
- return ("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJK"
- "LMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu")[value];
-#endif
-}
-
-/* Appends the first N characters of the ASCII85 representation
- of B to string OUT. */
-static void
-append_ascii85_block (unsigned b, size_t n, struct string *out)
-{
- char c[5];
- int i;
-
- for (i = 4; i >= 0; i--)
- {
- c[i] = value_to_ascii85 (b % 85);
- b /= 85;
- }
- ds_put_substring (out, ss_buffer (c, n));
-}
-
-/* Encodes BYTE with encoder E. */
-static void
-binary_put (struct binary_encoder *e, uint8_t byte)
-{
- e->b = (e->b << 8) | byte;
- e->n++;
- if (e->n % 4 == 0)
- {
- if (e->n == 4)
- ds_put_cstr (e->out, "<~");
-
- if (e->b != 0)
- append_ascii85_block (e->b, 5, e->out);
- else
- ds_put_char (e->out, 'z');
- }
-}
-
-/* Finishes up encoding with E. */
-static void
-binary_finish (struct binary_encoder *e)
-{
- if (e->n >= 4)
- {
- /* We output at least one complete ASCII85 block.
- Finish up. */
- size_t n = e->n % 4;
- if (n > 0)
- append_ascii85_block (e->b << 8 * (4 - n), n + 1, e->out);
- ds_put_cstr (e->out, "~>");
- }
- else if (e->n > 0)
- {
- /* It's cheaper (or at least the same cost) to encode this
- string in hexadecimal. */
- uint32_t b;
- size_t i;
-
- ds_put_cstr (e->out, "<");
- b = e->b << 8 * (4 - e->n);
- for (i = 0; i < e->n; i++)
- {
- ds_put_format (e->out, "%02x", b >> 24);
- b <<= 8;
- }
- ds_put_cstr (e->out, ">");
- }
- else
- {
- /* Empty string. */
- ds_put_cstr (e->out, "()");
- }
-}
-
-/* Encodes the N characters in S into encoder E,
- using a two-byte encoding.
- Returns the number of characters remaining after all those
- that could be successfully encoded were. */
-static size_t
-encode_two_byte (const struct afm_character **s, size_t n,
- struct binary_encoder *e)
-{
- for (; n > 0; s++, n--)
- {
- uint16_t code = (*s)->code;
- if (code != (*s)->code)
- break;
-
- binary_put (e, code >> 8);
- binary_put (e, code);
- }
- return n;
-}
-
-/* Encodes the N characters in S into encoder E,
- using an escape-based encoding with ESCAPE_CHAR as escape.
- Returns the number of characters remaining after all those
- that could be successfully encoded were. */
-static size_t
-encode_escape (const struct afm_character **s, size_t n,
- unsigned char escape_char,
- struct binary_encoder *e)
-{
- uint8_t cur_font = 0;
-
- for (; n > 0; s++, n--)
- {
- uint16_t code = (*s)->code;
- uint8_t font_num = code >> 8;
- uint8_t char_num = code & 0xff;
- if (code != (*s)->code)
- break;
-
- if (font_num != cur_font)
- {
- if (font_num == escape_char)
- break;
- binary_put (e, escape_char);
- binary_put (e, font_num);
- cur_font = font_num;
- }
- binary_put (e, char_num);
- }
- return n;
-}
-
-/* Encodes the N characters in S into encoder E,
- using an double escape-based encoding with ESCAPE_CHAR as
- escape.
- Returns the number of characters remaining after all those
- that could be successfully encoded were. */
-static size_t
-encode_double_escape (const struct afm_character **s, size_t n,
- unsigned char escape_char,
- struct binary_encoder *e)
-{
- unsigned cur_font = 0;
-
- for (; n > 0; s++, n--)
- {
- unsigned font_num = (*s)->code >> 8;
- uint8_t char_num = (*s)->code & 0xff;
- if ((*s)->code & ~0x1ffff)
- break;
-
- if (font_num != cur_font)
- {
- if (font_num == (escape_char & 0xff))
- break;
- if (font_num >= 256)
- binary_put (e, escape_char);
- binary_put (e, escape_char);
- binary_put (e, font_num & 0xff);
- cur_font = font_num;
- }
- binary_put (e, char_num);
- }
- return n;
-}
-
-/* Encodes the N characters in S into encoder E,
- using a shift-based encoding with SHIFT_IN and SHIFT_OUT as
- shift characters.
- Returns the number of characters remaining after all those
- that could be successfully encoded were. */
-static size_t
-encode_shift (const struct afm_character **s, size_t n,
- unsigned char shift_in, unsigned char shift_out,
- struct binary_encoder *e)
-{
- unsigned cur_font = 0;
-
- for (; n > 0; s++, n--)
- {
- int font_num = ((*s)->code & 0x100) != 0;
- uint8_t char_num = (*s)->code & 0xff;
- if ((*s)->code & ~0x1ff)
- break;
-
- if (font_num != cur_font)
- {
- binary_put (e, font_num ? shift_out : shift_in);
- cur_font = font_num;
- }
- binary_put (e, char_num);
- }
- return n;
-}
-
-/* Encodes the N characters in S into a PostScript string in OUT,
- according to AFM's character encoding.
- Returns the number of characters successfully encoded,
- which may be less than N if an unencodable character was
- encountered. */
-size_t
-afm_encode_string (const struct afm *afm,
- const struct afm_character **s, size_t n,
- struct string *out)
-{
- size_t initial_length = ds_length (out);
- size_t chars_left;
-
- if (afm->mapping == MAP_ONE_BYTE)
- chars_left = encode_one_byte (s, n, out);
- else
- {
- struct binary_encoder e;
-
- binary_init (&e, out);
- switch (afm->mapping)
- {
- case MAP_TWO_BYTE:
- chars_left = encode_two_byte (s, n, &e);
- break;
-
- case MAP_ESCAPE:
- chars_left = encode_escape (s, n, afm->escape_char, &e);
- break;
-
- case MAP_DOUBLE_ESCAPE:
- chars_left = encode_double_escape (s, n, afm->escape_char, &e);
- break;
-
- case MAP_SHIFT:
- chars_left = encode_shift (s, n, afm->shift_in, afm->shift_out, &e);
- break;
-
- default:
- NOT_REACHED ();
- }
- binary_finish (&e);
- }
-
- if (chars_left == n)
- ds_truncate (out, initial_length);
- return n - chars_left;
-}
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2006 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef AFM_H
-#define AFM_H 1
-
-#include <stddef.h>
-#include <libpspp/str.h>
-
-/* Metrics for a single character. */
-struct afm_character
- {
- int code; /* Non-negative character code, -1 if none. */
- const char *name; /* Character name, if any. */
- int width; /* Width. */
- int ascent; /* Height above baseline, never negative. */
- int descent; /* Depth below baseline, never negative. */
-
- /* Pairwise kerning data for this character in the first
- position, other characters in the second position. */
- struct afm_kern_pair *kern_pairs;
- size_t kern_pair_cnt;
-
- /* Ligature data for this character in the first position,
- other characters in the second position. */
- struct afm_ligature *ligatures;
- size_t ligature_cnt;
- };
-
-struct afm *afm_open (const char *file_name);
-void afm_close (struct afm *);
-
-int afm_get_ascent (const struct afm *);
-int afm_get_descent (const struct afm *);
-const char *afm_get_findfont_name (const struct afm *);
-
-const struct afm_character *afm_get_character (const struct afm *,
- int code);
-const struct afm_character *afm_get_ligature (const struct afm_character *,
- const struct afm_character *);
-int afm_get_kern_adjustment (const struct afm_character *,
- const struct afm_character *);
-
-size_t afm_encode_string (const struct afm *,
- const struct afm_character **, size_t,
- struct string *);
-
-#endif /* afm.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <libpspp/pool.h>
#include <libpspp/start-date.h>
#include <libpspp/version.h>
+#include <output/chart-provider.h>
+#include <output/chart.h>
+#include <output/output.h>
-#include "chart.h"
#include "error.h"
#include "minmax.h"
-#include "output.h"
#include "xalloc.h"
#include "gettext.h"
output-file="pspp.list"
append=no|yes If output-file exists, append to it?
chart-files="pspp-#.png" Name used for charts.
- chart-type=png Format of charts (use "none" to disable).
+ chart-type=png|none
paginate=on|off Formfeeds are desired?
tab-width=8 Width of a tab; 0 to not use tabs.
bool squeeze_blank_lines; /* Squeeze multiple blank lines into one? */
enum emphasis_style emphasis; /* How to emphasize text. */
int tab_width; /* Width of a tab; 0 not to use tabs. */
- const char *chart_type; /* Type of charts to output; NULL for none. */
+ bool enable_charts; /* Enable charts? */
const char *chart_file_name; /* Name of files used for charts. */
bool auto_width; /* Use viewwidth as page width? */
static void ascii_flush (struct outp_driver *);
static int get_default_box_char (size_t idx);
static bool update_page_size (struct outp_driver *, bool issue_error);
-static bool handle_option (struct outp_driver *this, const char *key,
+static bool handle_option (void *this, const char *key,
const struct string *val);
static bool
-ascii_open_driver (struct outp_driver *this, struct substring options)
+ascii_open_driver (const char *name, int types, struct substring options)
{
+ struct outp_driver *this;
struct ascii_driver_ext *x;
int i;
+ this = outp_allocate_driver (&ascii_class, name, types);
this->width = 79;
this->font_height = 1;
this->prop_em_width = 1;
x->emphasis = EMPH_BOLD;
x->tab_width = 8;
x->chart_file_name = pool_strdup (x->pool, "pspp-#.png");
- x->chart_type = pool_strdup (x->pool, "png");
+ x->enable_charts = true;
x->auto_width = false;
x->auto_length = false;
x->page_length = 66;
x->page_number = 0;
x->lines = NULL;
x->line_cap = 0;
- x->chart_cnt = 0;
+ x->chart_cnt = 1;
- if (!outp_parse_options (options, handle_option, this))
+ if (!outp_parse_options (this->name, options, handle_option, this))
goto error;
if (!update_page_size (this, true))
x->box[i] = pool_strdup (x->pool, s);
}
+ outp_register_driver (this);
+
return true;
error:
pool_destroy (x->pool);
+ outp_free_driver (this);
return false;
}
};
static bool
-handle_option (struct outp_driver *this, const char *key,
+handle_option (void *this_, const char *key,
const struct string *val)
{
+ struct outp_driver *this = this_;
struct ascii_driver_ext *x = this->ext;
int subcat;
const char *value;
error (0, 0, _("`chart-files' value must contain `#'"));
break;
case 2:
- if (value[0] != '\0')
- x->chart_type = pool_strdup (x->pool, value);
+ if (!strcmp (value, "png"))
+ x->enable_charts = true;
+ else if (!strcmp (value, "none"))
+ x->enable_charts = false;
else
- x->chart_type = NULL;
+ {
+ error (0, 0,
+ _("ascii: `png' or `none' expected for `chart-type'"));
+ return false;
+ }
break;
case 3:
x->init = pool_strdup (x->pool, value);
}
}
-static void
-ascii_submit (struct outp_driver *this UNUSED, struct som_entity *s)
-{
- extern struct som_table_class tab_table_class;
-
- assert (s->class == &tab_table_class);
- assert (s->type == SOM_CHART);
-}
-
static void
text_draw (struct outp_driver *this,
enum outp_font font,
}
static void
-ascii_chart_initialise (struct outp_driver *this, struct chart *ch)
+ascii_output_chart (struct outp_driver *this, const struct chart *chart)
{
struct ascii_driver_ext *x = this->ext;
struct outp_text t;
+ char *file_name;
char *text;
- if (x->chart_type == NULL)
- return;
-
- /* Initialize chart. */
- chart_init_separate (ch, x->chart_type, x->chart_file_name, ++x->chart_cnt);
- if (ch->file_name == NULL)
- return;
+ /* Draw chart into separate file */
+ file_name = chart_draw_png (chart, x->chart_file_name, x->chart_cnt++);
/* Mention chart in output.
First advance current position. */
}
/* Then write the text. */
- text = xasprintf ("See %s for a chart.", ch->file_name);
+ text = xasprintf ("See %s for a chart.", file_name);
t.font = OUTP_FIXED;
t.justification = OUTP_LEFT;
t.string = ss_cstr (text);
ascii_text_draw (this, &t);
this->cp_y++;
+ free (file_name);
free (text);
}
-static void
-ascii_chart_finalise (struct outp_driver *this, struct chart *ch)
-{
- struct ascii_driver_ext *x = this->ext;
- if (x->chart_type != NULL)
- chart_finalise_separate (ch);
-}
-
const struct outp_class ascii_class =
{
"ascii",
ascii_close_page,
ascii_flush,
- ascii_submit,
+ ascii_output_chart,
+
+ NULL, /* submit */
ascii_line,
ascii_text_metrics,
ascii_text_draw,
-
- ascii_chart_initialise,
- ascii_chart_finalise
};
## Process this file with automake to produce Makefile.in -*- makefile -*-
-
-include $(top_srcdir)/src/output/charts/automake.mk
-
noinst_LTLIBRARIES += src/output/liboutput.la
-output_sources = \
- src/output/afm.c \
- src/output/afm.h \
+src_output_liboutput_la_CPPFLAGS = $(LIBXML2_CFLAGS) $(AM_CPPFLAGS)
+
+src_output_liboutput_la_SOURCES = \
src/output/ascii.c \
+ src/output/chart.c \
+ src/output/chart.h \
+ src/output/charts/boxplot.c \
+ src/output/charts/boxplot.h \
+ src/output/charts/cartesian.c \
+ src/output/charts/cartesian.h \
+ src/output/charts/np-plot.c \
+ src/output/charts/np-plot.h \
+ src/output/charts/piechart.c \
+ src/output/charts/piechart.h \
+ src/output/charts/plot-chart.c \
+ src/output/charts/plot-chart.h \
+ src/output/charts/plot-hist.c \
+ src/output/charts/plot-hist.h \
+ src/output/charts/roc-chart.c \
+ src/output/charts/roc-chart.h \
src/output/html.c \
src/output/htmlP.h \
src/output/journal.c \
src/output/journal.h \
- src/output/output.c \
- src/output/output.h \
- src/output/postscript.c \
src/output/manager.c \
src/output/manager.h \
- src/output/chart.h \
- src/output/table.c src/output/table.h
-
-
-if WITHCHARTS
-src_output_liboutput_la_SOURCES = $(output_sources) src/output/chart.c
-
-EXTRA_DIST += src/output/dummy-chart.c
-else
-src_output_liboutput_la_SOURCES = $(output_sources) src/output/dummy-chart.c
-
-EXTRA_DIST += src/output/chart.c
+ src/output/odt.c \
+ src/output/output.c \
+ src/output/output.h \
+ src/output/table.c \
+ src/output/table.h
+if HAVE_CAIRO
+src_output_liboutput_la_SOURCES += src/output/cairo.c
endif
EXTRA_DIST += src/output/OChangeLog
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <output/cairo.h>
+
+#include <libpspp/assertion.h>
+#include <libpspp/start-date.h>
+#include <libpspp/version.h>
+#include <output/chart-provider.h>
+#include <output/manager.h>
+#include <output/output.h>
+
+#include <cairo/cairo-pdf.h>
+#include <cairo/cairo-ps.h>
+#include <cairo/cairo-svg.h>
+#include <cairo/cairo.h>
+#include <pango/pango-font.h>
+#include <pango/pango-layout.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "intprops.h"
+#include "minmax.h"
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* Cairo driver options: (defaults listed first)
+
+ output-file="pspp.pdf"
+ output-type=pdf|ps|png|svg
+ paper-size=letter (see "papersize" file)
+ orientation=portrait|landscape
+ headers=on|off
+
+ left-margin=0.5in
+ right-margin=0.5in
+ top-margin=0.5in
+ bottom-margin=0.5in
+
+ prop-font=serif
+ emph-font=serif italic
+ fixed-font=monospace
+ font-size=10000
+
+ line-gutter=1pt
+ line-spacing=1pt
+ line-width=0.5pt
+ */
+
+/* Measurements as we present to the rest of PSPP. */
+#define XR_POINT PANGO_SCALE
+#define XR_INCH (XR_POINT * 72)
+
+/* Conversions to and from points. */
+static double
+xr_to_pt (int x)
+{
+ return x / (double) XR_POINT;
+}
+
+static int
+pt_to_xr (double x)
+{
+ return x * XR_POINT + 0.5;
+}
+
+/* Output types. */
+enum xr_output_type
+ {
+ XR_PDF,
+ XR_PS,
+ XR_SVG
+ };
+
+/* A font for use with Cairo. */
+struct xr_font
+ {
+ char *string;
+ PangoFontDescription *desc;
+ PangoLayout *layout;
+ PangoFontMetrics *metrics;
+ };
+
+/* Cairo output driver extension record. */
+struct xr_driver_ext
+ {
+ cairo_t *cairo;
+ struct xr_font fonts[OUTP_FONT_CNT];
+
+ bool draw_headers; /* Draw headers at top of page? */
+ int page_number; /* Current page number. */
+
+ int line_gutter; /* Space around lines. */
+ int line_space; /* Space between lines. */
+ int line_width; /* Width of lines. */
+ };
+
+struct xr_driver_options
+ {
+ struct outp_driver *driver;
+
+ char *file_name; /* Output file name. */
+ enum xr_output_type file_type; /* Type of output file. */
+
+
+ bool portrait; /* Portrait mode? */
+
+ int paper_width; /* Width of paper before dropping margins. */
+ int paper_length; /* Length of paper before dropping margins. */
+ int left_margin; /* Left margin in XR units. */
+ int right_margin; /* Right margin in XR units. */
+ int top_margin; /* Top margin in XR units. */
+ int bottom_margin; /* Bottom margin in XR units. */
+ };
+
+static bool handle_option (void *options, const char *key,
+ const struct string *val);
+static void draw_headers (struct outp_driver *this);
+
+static bool load_font (struct outp_driver *this, struct xr_font *);
+static void free_font (struct xr_font *);
+static int text_width (struct outp_driver *, const char *, enum outp_font);
+\f
+/* Driver initialization. */
+
+static struct outp_driver *
+xr_allocate (const char *name, int types)
+{
+ struct outp_driver *this;
+ struct xr_driver_ext *x;
+ size_t i;
+
+ this = outp_allocate_driver (&cairo_class, name, types);
+ this->width = this->length = 0;
+ this->font_height = XR_POINT * 10;
+ this->ext = x = xzalloc (sizeof *x);
+ x->cairo = NULL;
+ x->fonts[OUTP_FIXED].string = xstrdup ("monospace");
+ x->fonts[OUTP_PROPORTIONAL].string = xstrdup ("serif");
+ x->fonts[OUTP_EMPHASIS].string = xstrdup ("serif italic");
+ for (i = 0; i < OUTP_FONT_CNT; i++)
+ {
+ struct xr_font *font = &x->fonts[i];
+ font->desc = NULL;
+ font->metrics = NULL;
+ font->layout = NULL;
+ }
+ x->draw_headers = true;
+ x->page_number = 0;
+ x->line_gutter = XR_POINT;
+ x->line_space = XR_POINT;
+ x->line_width = XR_POINT / 2;
+
+ return this;
+}
+
+static bool
+xr_set_cairo (struct outp_driver *this, cairo_t *cairo)
+{
+ struct xr_driver_ext *x = this->ext;
+ int i;
+
+ x->cairo = cairo;
+
+ cairo_set_line_width (x->cairo, xr_to_pt (x->line_width));
+
+ for (i = 0; i < OUTP_FONT_CNT; i++)
+ if (!load_font (this, &x->fonts[i]))
+ return false;
+
+ this->fixed_width = text_width (this, "0", OUTP_FIXED);
+ this->prop_em_width = text_width (this, "0", OUTP_PROPORTIONAL);
+
+ this->horiz_line_width[OUTP_L_NONE] = 0;
+ this->horiz_line_width[OUTP_L_SINGLE] = 2 * x->line_gutter + x->line_width;
+ this->horiz_line_width[OUTP_L_DOUBLE] = (2 * x->line_gutter + x->line_space
+ + 2 * x->line_width);
+ memcpy (this->vert_line_width, this->horiz_line_width,
+ sizeof this->vert_line_width);
+
+ return true;
+}
+
+struct outp_driver *
+xr_create_driver (cairo_t *cairo)
+{
+ struct outp_driver *this;
+
+ this = xr_allocate ("cairo", 0);
+ this->width = INT_MAX / 8;
+ this->length = INT_MAX / 8;
+ if (!xr_set_cairo (this, cairo))
+ {
+ this->class->close_driver (this);
+ outp_free_driver (this);
+ return NULL;
+ }
+ return this;
+}
+
+static bool
+xr_open_driver (const char *name, int types, struct substring option_string)
+{
+ struct outp_driver *this;
+ struct xr_driver_ext *x;
+ struct xr_driver_options options;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ double width_pt, length_pt;
+
+ this = xr_allocate (name, types);
+ x = this->ext;
+
+ options.driver = this;
+ options.file_name = xstrdup ("pspp.pdf");
+ options.file_type = XR_PDF;
+ options.portrait = true;
+ outp_get_paper_size ("", &options.paper_width, &options.paper_length);
+ options.left_margin = XR_INCH / 2;
+ options.right_margin = XR_INCH / 2;
+ options.top_margin = XR_INCH / 2;
+ options.bottom_margin = XR_INCH / 2;
+
+ outp_parse_options (this->name, option_string, handle_option, &options);
+
+ width_pt = options.paper_width / 1000.0;
+ length_pt = options.paper_length / 1000.0;
+ if (options.portrait)
+ {
+ this->width = pt_to_xr (width_pt);
+ this->length = pt_to_xr (length_pt);
+ }
+ else
+ {
+ this->width = pt_to_xr (width_pt);
+ this->length = pt_to_xr (length_pt);
+ }
+ if (x->draw_headers)
+ options.top_margin += 3 * this->font_height;
+ this->width -= options.left_margin + options.right_margin;
+ this->length -= options.top_margin + options.bottom_margin;
+
+ if (options.file_type == XR_PDF)
+ surface = cairo_pdf_surface_create (options.file_name,
+ width_pt, length_pt);
+ else if (options.file_type == XR_PS)
+ surface = cairo_ps_surface_create (options.file_name, width_pt, length_pt);
+ else if (options.file_type == XR_SVG)
+ surface = cairo_svg_surface_create (options.file_name,
+ width_pt, length_pt);
+ else
+ NOT_REACHED ();
+
+ status = cairo_surface_status (surface);
+ if (status != CAIRO_STATUS_SUCCESS)
+ {
+ error (0, 0, _("opening output file \"%s\": %s"),
+ options.file_name, cairo_status_to_string (status));
+ cairo_surface_destroy (surface);
+ goto error;
+ }
+
+ x->cairo = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_translate (x->cairo,
+ xr_to_pt (options.left_margin),
+ xr_to_pt (options.top_margin));
+
+ if (this->length / this->font_height < 15)
+ {
+ error (0, 0, _("The defined page is not long "
+ "enough to hold margins and headers, plus least 15 "
+ "lines of the default fonts. In fact, there's only "
+ "room for %d lines."),
+ this->length / this->font_height);
+ goto error;
+ }
+
+ if (!xr_set_cairo (this, x->cairo))
+ goto error;
+
+ outp_register_driver (this);
+ free (options.file_name);
+ return true;
+
+ error:
+ this->class->close_driver (this);
+ outp_free_driver (this);
+ free (options.file_name);
+ return false;
+}
+
+static bool
+xr_close_driver (struct outp_driver *this)
+{
+ struct xr_driver_ext *x = this->ext;
+ bool ok = true;
+ size_t i;
+
+ if (x->cairo != NULL)
+ {
+ cairo_status_t status;
+
+ cairo_surface_finish (cairo_get_target (x->cairo));
+ status = cairo_status (x->cairo);
+ if (status != CAIRO_STATUS_SUCCESS)
+ error (0, 0, _("error writing output file for %s driver: %s"),
+ this->name, cairo_status_to_string (status));
+ cairo_destroy (x->cairo);
+ }
+
+ for (i = 0; i < OUTP_FONT_CNT; i++)
+ free_font (&x->fonts[i]);
+ free (x);
+
+ return ok;
+}
+
+/* Generic option types. */
+enum
+{
+ output_file_arg,
+ output_type_arg,
+ paper_size_arg,
+ orientation_arg,
+ line_style_arg,
+ boolean_arg,
+ dimension_arg,
+ string_arg,
+ nonneg_int_arg
+};
+
+/* All the options that the Cairo driver supports. */
+static const struct outp_option option_tab[] =
+{
+ {"output-file", output_file_arg,0},
+ {"output-type", output_type_arg,0},
+ {"paper-size", paper_size_arg, 0},
+ {"orientation", orientation_arg,0},
+
+ {"headers", boolean_arg, 1},
+
+ {"prop-font", string_arg, OUTP_PROPORTIONAL},
+ {"emph-font", string_arg, OUTP_EMPHASIS},
+ {"fixed-font", string_arg, OUTP_FIXED},
+
+ {"left-margin", dimension_arg, 0},
+ {"right-margin", dimension_arg, 1},
+ {"top-margin", dimension_arg, 2},
+ {"bottom-margin", dimension_arg, 3},
+ {"font-size", dimension_arg, 4},
+ {"line-width", dimension_arg, 5},
+ {"line-gutter", dimension_arg, 6},
+ {"line-width", dimension_arg, 7},
+ {NULL, 0, 0},
+};
+
+static bool
+handle_option (void *options_, const char *key, const struct string *val)
+{
+ struct xr_driver_options *options = options_;
+ struct outp_driver *this = options->driver;
+ struct xr_driver_ext *x = this->ext;
+ int subcat;
+ char *value = ds_cstr (val);
+
+ switch (outp_match_keyword (key, option_tab, &subcat))
+ {
+ case -1:
+ error (0, 0,
+ _("unknown configuration parameter `%s' for %s device "
+ "driver"), key, this->class->name);
+ break;
+ case output_file_arg:
+ free (options->file_name);
+ options->file_name = xstrdup (value);
+ break;
+ case output_type_arg:
+ if (!strcmp (value, "pdf"))
+ options->file_type = XR_PDF;
+ else if (!strcmp (value, "ps"))
+ options->file_type = XR_PS;
+ else if (!strcmp (value, "svg"))
+ options->file_type = XR_SVG;
+ else
+ {
+ error (0, 0, _("unknown Cairo output type \"%s\""), value);
+ return false;
+ }
+ break;
+ case paper_size_arg:
+ outp_get_paper_size (value,
+ &options->paper_width, &options->paper_length);
+ break;
+ case orientation_arg:
+ if (!strcmp (value, "portrait"))
+ options->portrait = true;
+ else if (!strcmp (value, "landscape"))
+ options->portrait = false;
+ else
+ error (0, 0, _("unknown orientation `%s' (valid orientations are "
+ "`portrait' and `landscape')"), value);
+ break;
+ case boolean_arg:
+ if (!strcmp (value, "on") || !strcmp (value, "true")
+ || !strcmp (value, "yes") || atoi (value))
+ x->draw_headers = true;
+ else if (!strcmp (value, "off") || !strcmp (value, "false")
+ || !strcmp (value, "no") || !strcmp (value, "0"))
+ x->draw_headers = false;
+ else
+ {
+ error (0, 0, _("boolean value expected for %s"), key);
+ return false;
+ }
+ break;
+ case dimension_arg:
+ {
+ int dimension = outp_evaluate_dimension (value);
+
+ if (dimension <= 0)
+ break;
+ switch (subcat)
+ {
+ case 0:
+ options->left_margin = dimension;
+ break;
+ case 1:
+ options->right_margin = dimension;
+ break;
+ case 2:
+ options->top_margin = dimension;
+ break;
+ case 3:
+ options->bottom_margin = dimension;
+ break;
+ case 4:
+ this->font_height = dimension;
+ break;
+ case 5:
+ x->line_width = dimension;
+ break;
+ case 6:
+ x->line_gutter = dimension;
+ break;
+ case 7:
+ x->line_width = dimension;
+ break;
+ default:
+ NOT_REACHED ();
+ }
+ }
+ break;
+ case string_arg:
+ free (x->fonts[subcat].string);
+ x->fonts[subcat].string = ds_xstrdup (val);
+ break;
+ default:
+ NOT_REACHED ();
+ }
+
+ return true;
+}
+\f
+/* Basic file operations. */
+
+static void
+xr_open_page (struct outp_driver *this)
+{
+ struct xr_driver_ext *x = this->ext;
+
+ x->page_number++;
+
+ if (x->draw_headers)
+ draw_headers (this);
+}
+
+static void
+xr_close_page (struct outp_driver *this)
+{
+ struct xr_driver_ext *x = this->ext;
+ cairo_show_page (x->cairo);
+}
+
+static void
+xr_output_chart (struct outp_driver *this, const struct chart *chart)
+{
+ struct xr_driver_ext *x = this->ext;
+ struct chart_geometry geom;
+
+ outp_eject_page (this);
+ outp_open_page (this);
+
+ cairo_save (x->cairo);
+ cairo_translate (x->cairo, 0.0, xr_to_pt (this->length));
+ cairo_scale (x->cairo, 1.0, -1.0);
+ chart_geometry_init (x->cairo, &geom,
+ xr_to_pt (this->width), xr_to_pt (this->length));
+ chart_draw (chart, x->cairo, &geom);
+ chart_geometry_free (x->cairo, &geom);
+ cairo_restore (x->cairo);
+
+ outp_close_page (this);
+}
+\f
+/* Draws a line from (x0,y0) to (x1,y1). */
+static void
+dump_line (struct outp_driver *this, int x0, int y0, int x1, int y1)
+{
+ struct xr_driver_ext *x = this->ext;
+ cairo_new_path (x->cairo);
+ cairo_move_to (x->cairo, xr_to_pt (x0), xr_to_pt (y0));
+ cairo_line_to (x->cairo, xr_to_pt (x1), xr_to_pt (y1));
+ cairo_stroke (x->cairo);
+}
+
+/* Draws a horizontal line X0...X2 at Y if LEFT says so,
+ shortening it to X0...X1 if SHORTEN is true.
+ Draws a horizontal line X1...X3 at Y if RIGHT says so,
+ shortening it to X2...X3 if SHORTEN is true. */
+static void
+horz_line (struct outp_driver *this,
+ int x0, int x1, int x2, int x3, int y,
+ enum outp_line_style left, enum outp_line_style right,
+ bool shorten)
+{
+ if (left != OUTP_L_NONE && right != OUTP_L_NONE && !shorten)
+ dump_line (this, x0, y, x3, y);
+ else
+ {
+ if (left != OUTP_L_NONE)
+ dump_line (this, x0, y, shorten ? x1 : x2, y);
+ if (right != OUTP_L_NONE)
+ dump_line (this, shorten ? x2 : x1, y, x3, y);
+ }
+}
+
+/* Draws a vertical line Y0...Y2 at X if TOP says so,
+ shortening it to Y0...Y1 if SHORTEN is true.
+ Draws a vertical line Y1...Y3 at X if BOTTOM says so,
+ shortening it to Y2...Y3 if SHORTEN is true. */
+static void
+vert_line (struct outp_driver *this,
+ int y0, int y1, int y2, int y3, int x,
+ enum outp_line_style top, enum outp_line_style bottom,
+ bool shorten)
+{
+ if (top != OUTP_L_NONE && bottom != OUTP_L_NONE && !shorten)
+ dump_line (this, x, y0, x, y3);
+ else
+ {
+ if (top != OUTP_L_NONE)
+ dump_line (this, x, y0, x, shorten ? y1 : y2);
+ if (bottom != OUTP_L_NONE)
+ dump_line (this, x, shorten ? y2 : y1, x, y3);
+ }
+}
+
+/* Draws a generalized intersection of lines in the rectangle
+ (X0,Y0)-(X3,Y3). The line coming from the top to the center
+ is of style TOP, from left to center of style LEFT, from
+ bottom to center of style BOTTOM, and from right to center of
+ style RIGHT. */
+static void
+xr_line (struct outp_driver *this,
+ int x0, int y0, int x3, int y3,
+ enum outp_line_style top, enum outp_line_style left,
+ enum outp_line_style bottom, enum outp_line_style right)
+{
+ /* The algorithm here is somewhat subtle, to allow it to handle
+ all the kinds of intersections that we need.
+
+ Three additional ordinates are assigned along the x axis. The
+ first is xc, midway between x0 and x3. The others are x1 and
+ x2; for a single vertical line these are equal to xc, and for
+ a double vertical line they are the ordinates of the left and
+ right half of the double line.
+
+ yc, y1, and y2 are assigned similarly along the y axis.
+
+ The following diagram shows the coordinate system and output
+ for double top and bottom lines, single left line, and no
+ right line:
+
+ x0 x1 xc x2 x3
+ y0 ________________________
+ | # # |
+ | # # |
+ | # # |
+ | # # |
+ | # # |
+ y1 = y2 = yc |######### # |
+ | # # |
+ | # # |
+ | # # |
+ | # # |
+ y3 |________#_____#_______|
+ */
+ struct xr_driver_ext *ext = this->ext;
+
+ /* Offset from center of each line in a pair of double lines. */
+ int double_line_ofs = (ext->line_space + ext->line_width) / 2;
+
+ /* Are the lines along each axis single or double?
+ (It doesn't make sense to have different kinds of line on the
+ same axis, so we don't try to gracefully handle that case.) */
+ bool double_vert = top == OUTP_L_DOUBLE || bottom == OUTP_L_DOUBLE;
+ bool double_horz = left == OUTP_L_DOUBLE || right == OUTP_L_DOUBLE;
+
+ /* When horizontal lines are doubled,
+ the left-side line along y1 normally runs from x0 to x2,
+ and the right-side line along y1 from x3 to x1.
+ If the top-side line is also doubled, we shorten the y1 lines,
+ so that the left-side line runs only to x1,
+ and the right-side line only to x2.
+ Otherwise, the horizontal line at y = y1 below would cut off
+ the intersection, which looks ugly:
+ x0 x1 x2 x3
+ y0 ________________________
+ | # # |
+ | # # |
+ | # # |
+ | # # |
+ y1 |######### ########|
+ | |
+ | |
+ y2 |######################|
+ | |
+ | |
+ y3 |______________________|
+ It is more of a judgment call when the horizontal line is
+ single. We actually choose to cut off the line anyhow, as
+ shown in the first diagram above.
+ */
+ bool shorten_y1_lines = top == OUTP_L_DOUBLE;
+ bool shorten_y2_lines = bottom == OUTP_L_DOUBLE;
+ bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
+ int horz_line_ofs = double_vert ? double_line_ofs : 0;
+ int xc = (x0 + x3) / 2;
+ int x1 = xc - horz_line_ofs;
+ int x2 = xc + horz_line_ofs;
+
+ bool shorten_x1_lines = left == OUTP_L_DOUBLE;
+ bool shorten_x2_lines = right == OUTP_L_DOUBLE;
+ bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
+ int vert_line_ofs = double_horz ? double_line_ofs : 0;
+ int yc = (y0 + y3) / 2;
+ int y1 = yc - vert_line_ofs;
+ int y2 = yc + vert_line_ofs;
+
+ if (!double_horz)
+ horz_line (this, x0, x1, x2, x3, yc, left, right, shorten_yc_line);
+ else
+ {
+ horz_line (this, x0, x1, x2, x3, y1, left, right, shorten_y1_lines);
+ horz_line (this, x0, x1, x2, x3, y2, left, right, shorten_y2_lines);
+ }
+
+ if (!double_vert)
+ vert_line (this, y0, y1, y2, y3, xc, top, bottom, shorten_xc_line);
+ else
+ {
+ vert_line (this, y0, y1, y2, y3, x1, top, bottom, shorten_x1_lines);
+ vert_line (this, y0, y1, y2, y3, x2, top, bottom, shorten_x2_lines);
+ }
+}
+
+/* Writes STRING at location (X,Y) trimmed to the given MAX_WIDTH
+ and with the given JUSTIFICATION for THIS driver. */
+static int
+draw_text (struct outp_driver *this,
+ const char *string, int x, int y, int max_width,
+ enum outp_justification justification)
+{
+ struct outp_text text;
+ int width;
+
+ text.font = OUTP_PROPORTIONAL;
+ text.justification = justification;
+ text.string = ss_cstr (string);
+ text.h = max_width;
+ text.v = this->font_height;
+ text.x = x;
+ text.y = y;
+ this->class->text_metrics (this, &text, &width, NULL);
+ this->class->text_draw (this, &text);
+ return width;
+}
+
+/* Writes STRING at location (X,Y) trimmed to the given MAX_WIDTH
+ and with the given JUSTIFICATION for THIS driver. */
+static int
+text_width (struct outp_driver *this, const char *string, enum outp_font font)
+{
+ struct outp_text text;
+ int width;
+
+ text.font = font;
+ text.justification = OUTP_LEFT;
+ text.string = ss_cstr (string);
+ text.h = INT_MAX;
+ text.v = this->font_height;
+ text.x = 0;
+ text.y = 0;
+ this->class->text_metrics (this, &text, &width, NULL);
+ return width;
+}
+
+/* Writes LEFT left-justified and RIGHT right-justified within
+ (X0...X1) at Y. LEFT or RIGHT or both may be null. */
+static void
+draw_header_line (struct outp_driver *this,
+ const char *left, const char *right,
+ int x0, int x1, int y)
+{
+ int right_width = 0;
+ if (right != NULL)
+ right_width = (draw_text (this, right, x0, y, x1 - x0, OUTP_RIGHT)
+ + this->prop_em_width);
+ if (left != NULL)
+ draw_text (this, left, x0, y, x1 - x0 - right_width, OUTP_LEFT);
+}
+
+/* Draw top of page headers for THIS driver. */
+static void
+draw_headers (struct outp_driver *this)
+{
+ struct xr_driver_ext *ext = this->ext;
+ char *r1, *r2;
+ int x0, x1;
+ int y;
+
+ y = -3 * this->font_height;
+ x0 = this->prop_em_width;
+ x1 = this->width - this->prop_em_width;
+
+ /* Draw box. */
+ cairo_rectangle (ext->cairo, 0, xr_to_pt (y), xr_to_pt (this->width),
+ xr_to_pt (2 * (this->font_height
+ + ext->line_width + ext->line_gutter)));
+ cairo_save (ext->cairo);
+ cairo_set_source_rgb (ext->cairo, 0.9, 0.9, 0.9);
+ cairo_fill_preserve (ext->cairo);
+ cairo_restore (ext->cairo);
+ cairo_stroke (ext->cairo);
+
+ y += ext->line_width + ext->line_gutter;
+
+ r1 = xasprintf (_("%s - Page %d"), get_start_date (), ext->page_number);
+ r2 = xasprintf ("%s - %s", version, host_system);
+
+ draw_header_line (this, outp_title, r1, x0, x1, y);
+ y += this->font_height;
+
+ draw_header_line (this, outp_subtitle, r2, x0, x1, y);
+
+ free (r1);
+ free (r2);
+}
+\f
+/* Format TEXT on THIS driver.
+ If DRAW is nonzero, draw the text.
+ The width of the widest line is stored into *WIDTH, if WIDTH
+ is nonnull.
+ The total height of the text written is stored into *HEIGHT,
+ if HEIGHT is nonnull. */
+static void
+text (struct outp_driver *this, const struct outp_text *text, bool draw,
+ int *width, int *height)
+{
+ struct xr_driver_ext *ext = this->ext;
+ struct xr_font *font = &ext->fonts[text->font];
+
+ pango_layout_set_text (font->layout,
+ text->string.string, text->string.length);
+ pango_layout_set_alignment (
+ font->layout,
+ (text->justification == OUTP_RIGHT ? PANGO_ALIGN_RIGHT
+ : text->justification == OUTP_LEFT ? PANGO_ALIGN_LEFT
+ : PANGO_ALIGN_CENTER));
+ pango_layout_set_width (font->layout, text->h == INT_MAX ? -1 : text->h);
+ pango_layout_set_wrap (font->layout, PANGO_WRAP_WORD_CHAR);
+ /* XXX need to limit number of lines to those that fit in text->v. */
+
+ if (draw)
+ {
+ int x = text->x;
+ if (text->justification != OUTP_LEFT && text->h != INT_MAX)
+ {
+ int w, h, excess;
+ pango_layout_get_size (font->layout, &w, &h);
+ excess = text->h - w;
+ if (excess > 0)
+ {
+ if (text->justification == OUTP_CENTER)
+ x += excess / 2;
+ else
+ x += excess;
+ }
+ }
+ cairo_save (ext->cairo);
+ cairo_translate (ext->cairo, xr_to_pt (text->x), xr_to_pt (text->y));
+ pango_cairo_show_layout (ext->cairo, font->layout);
+ cairo_restore (ext->cairo);
+ }
+
+ if (width != NULL || height != NULL)
+ {
+ int w, h;
+ pango_layout_get_size (font->layout, &w, &h);
+ if (width != NULL)
+ *width = w;
+ if (height != NULL)
+ *height = h;
+ }
+}
+
+static void
+xr_text_metrics (struct outp_driver *this, const struct outp_text *t,
+ int *width, int *height)
+{
+ text (this, t, false, width, height);
+}
+
+static void
+xr_text_draw (struct outp_driver *this, const struct outp_text *t)
+{
+ text (this, t, true, NULL, NULL);
+}
+\f
+/* Attempts to load FONT, initializing its other members based on
+ its 'string' member and the information in THIS. Returns true
+ if successful, otherwise false. */
+static bool
+load_font (struct outp_driver *this, struct xr_font *font)
+{
+ struct xr_driver_ext *x = this->ext;
+ PangoContext *context;
+ PangoLanguage *language;
+
+ font->desc = pango_font_description_from_string (font->string);
+ if (font->desc == NULL)
+ {
+ error (0, 0, _("\"%s\": bad font specification"), font->string);
+ return false;
+ }
+ pango_font_description_set_absolute_size (font->desc, this->font_height);
+
+ font->layout = pango_cairo_create_layout (x->cairo);
+ pango_layout_set_font_description (font->layout, font->desc);
+
+ language = pango_language_get_default ();
+ context = pango_layout_get_context (font->layout);
+ font->metrics = pango_context_get_metrics (context, font->desc, language);
+
+ return true;
+}
+
+/* Frees FONT. */
+static void
+free_font (struct xr_font *font)
+{
+ free (font->string);
+ if (font->desc != NULL)
+ pango_font_description_free (font->desc);
+ pango_font_metrics_unref (font->metrics);
+ g_object_unref (font->layout);
+}
+
+/* Cairo driver class. */
+const struct outp_class cairo_class =
+{
+ "cairo",
+ 0,
+
+ xr_open_driver,
+ xr_close_driver,
+
+ xr_open_page,
+ xr_close_page,
+ NULL,
+
+ xr_output_chart,
+
+ NULL,
+
+ xr_line,
+ xr_text_metrics,
+ xr_text_draw,
+};
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CAIRO_H
+#define OUTPUT_CAIRO_H 1
+
+#include <cairo/cairo.h>
+
+struct outp_driver *xr_create_driver (cairo_t *);
+
+#endif /* output/cairo.h */
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CHART_PROVIDER_H
+#define OUTPUT_CHART_PROVIDER_H 1
+
+#include <cairo/cairo.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <output/chart.h>
+
+struct chart_colour
+ {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+ };
+
+/* The geometry of a chart. */
+struct chart_geometry
+ {
+ int data_top ;
+ int data_right ;
+ int data_bottom;
+ int data_left ;
+
+ int abscissa_top;
+
+ int ordinate_right ;
+
+ int title_bottom ;
+
+ /* Legend. */
+ int legend_left ;
+ int legend_right ;
+ const char **dataset;
+ int n_datasets;
+
+ /* Default font size for the plot. */
+ double font_size;
+
+ struct chart_colour fill_colour;
+
+ /* Stuff Particular to Cartesians (and Boxplots ) */
+ double ordinate_scale;
+ double abscissa_scale;
+ double x_min;
+ double x_max;
+ double y_min;
+ double y_max;
+ bool in_path;
+ };
+
+struct chart_class
+ {
+ void (*draw) (const struct chart *, cairo_t *, struct chart_geometry *);
+ void (*destroy) (struct chart *);
+ };
+
+struct chart
+ {
+ const struct chart_class *class;
+ int ref_cnt;
+ };
+
+void chart_init (struct chart *, const struct chart_class *);
+
+void chart_geometry_init (cairo_t *, struct chart_geometry *,
+ double width, double length);
+void chart_geometry_free (cairo_t *, struct chart_geometry *);
+
+void chart_draw (const struct chart *, cairo_t *, struct chart_geometry *);
+char *chart_draw_png (const struct chart *, const char *file_name_template,
+ int number);
+
+#endif /* output/chart-provider.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <config.h>
#include <output/chart.h>
+#include <output/chart-provider.h>
#include <assert.h>
+#include <cairo/cairo.h>
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
-#include <plot.h>
-
#include <libpspp/str.h>
#include <output/manager.h>
#include <output/output.h>
extern struct som_table_class tab_table_class;
-struct chart *
-chart_create(void)
+void
+chart_init (struct chart *chart, const struct chart_class *class)
{
- struct chart *chart;
- struct outp_driver *d;
-
- d = outp_drivers (NULL);
- if (d == NULL)
- return NULL;
-
- chart = xmalloc (sizeof *chart);
- chart->lp = NULL;
- d->class->initialise_chart(d, chart);
- if (!chart->lp)
- {
- free (chart);
- return NULL;
- }
-
- if (pl_openpl_r (chart->lp) < 0) /* open Plotter */
- return NULL;
-
- pl_fspace_r (chart->lp, 0.0, 0.0, 1000.0, 1000.0); /* set coordinate system */
- pl_flinewidth_r (chart->lp, 0.25); /* set line thickness */
- pl_pencolorname_r (chart->lp, "black");
-
- pl_erase_r (chart->lp); /* erase graphics display */
- pl_filltype_r(chart->lp,0);
-
- pl_savestate_r(chart->lp);
-
- /* Set default chartetry */
- chart->data_top = 900;
- chart->data_right = 800;
- chart->data_bottom = 120;
- chart->data_left = 150;
- chart->abscissa_top = 70;
- chart->ordinate_right = 120;
- chart->title_bottom = 920;
- chart->legend_left = 810;
- chart->legend_right = 1000;
- chart->font_size = 0;
- chart->in_path = false;
- chart->dataset = NULL;
- chart->n_datasets = 0;
- strcpy(chart->fill_colour,"red");
-
- /* Get default font size */
- if ( !chart->font_size)
- chart->font_size = pl_fontsize_r(chart->lp, -1);
-
- /* Draw the data area */
- pl_box_r(chart->lp,
- chart->data_left, chart->data_bottom,
- chart->data_right, chart->data_top);
+ chart->class = class;
+ chart->ref_cnt = 1;
+}
- return chart;
+void
+chart_geometry_init (cairo_t *cr, struct chart_geometry *geom,
+ double width, double length)
+{
+ /* Set default chartetry. */
+ geom->data_top = 0.900 * length;
+ geom->data_right = 0.800 * width;
+ geom->data_bottom = 0.120 * length;
+ geom->data_left = 0.150 * width;
+ geom->abscissa_top = 0.070 * length;
+ geom->ordinate_right = 0.120 * width;
+ geom->title_bottom = 0.920 * length;
+ geom->legend_left = 0.810 * width;
+ geom->legend_right = width;
+ geom->font_size = 15.0;
+ geom->in_path = false;
+ geom->dataset = NULL;
+ geom->n_datasets = 0;
+
+ geom->fill_colour.red = 255;
+ geom->fill_colour.green = 0;
+ geom->fill_colour.blue = 0;
+
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_rectangle (cr, geom->data_left, geom->data_bottom,
+ geom->data_right - geom->data_left,
+ geom->data_top - geom->data_bottom);
+ cairo_stroke (cr);
}
void
-chart_submit(struct chart *chart)
+chart_geometry_free (cairo_t *cr UNUSED, struct chart_geometry *geom)
{
int i;
- struct som_entity s;
- struct outp_driver *d;
-
- if ( ! chart )
- return ;
-
- pl_restorestate_r(chart->lp);
-
- s.class = &tab_table_class;
- s.ext = chart;
- s.type = SOM_CHART;
- som_submit (&s);
- if (pl_closepl_r (chart->lp) < 0) /* close Plotter */
- {
- fprintf (stderr, "Couldn't close Plotter\n");
- }
-
- pl_deletepl_r(chart->lp);
+ for (i = 0 ; i < geom->n_datasets; ++i)
+ free (geom->dataset[i]);
+ free (geom->dataset);
+}
- pl_deleteplparams(chart->pl_params);
+void
+chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ chart->class->draw (chart, cr, geom);
+}
- d = outp_drivers (NULL);
- d->class->finalise_chart(d, chart);
+char *
+chart_draw_png (const struct chart *chart, const char *file_name_template,
+ int number)
+{
+ const int width = 640;
+ const int length = 480;
+
+ struct chart_geometry geom;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ const char *number_pos;
+ char *file_name;
+ cairo_t *cr;
+
+ number_pos = strchr (file_name_template, '#');
+ if (number_pos != NULL)
+ file_name = xasprintf ("%.*s%d%s", (int) (number_pos - file_name_template),
+ file_name_template, number, number_pos + 1);
+ else
+ file_name = xstrdup (file_name_template);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, length);
+ cr = cairo_create (surface);
+
+ cairo_translate (cr, 0.0, length);
+ cairo_scale (cr, 1.0, -1.0);
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
+ cairo_rectangle (cr, 0, 0, width, length);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+
+ chart_geometry_init (cr, &geom, width, length);
+ chart_draw (chart, cr, &geom);
+ chart_geometry_free (cr, &geom);
+
+ status = cairo_surface_write_to_png (surface, file_name);
+ if (status != CAIRO_STATUS_SUCCESS)
+ error (0, 0, _("writing output file \"%s\": %s"),
+ file_name, cairo_status_to_string (status));
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return file_name;
+}
- for (i = 0 ; i < chart->n_datasets; ++i)
- free (chart->dataset[i]);
- free (chart->dataset);
- free(chart);
+struct chart *
+chart_ref (const struct chart *chart_)
+{
+ struct chart *chart = CONST_CAST (struct chart *, chart_);
+ chart->ref_cnt++;
+ return chart;
}
void
-chart_init_separate (struct chart *ch, const char *type,
- const char *file_name_tmpl, int number)
+chart_unref (struct chart *chart)
{
- FILE *fp;
- int number_pos;
-
- number_pos = strchr (file_name_tmpl, '#') - file_name_tmpl;
- ch->file_name = xasprintf ("%.*s%d%s",
- number_pos, file_name_tmpl,
- number,
- file_name_tmpl + number_pos + 1);
- fp = fopen (ch->file_name, "wb");
- if (fp == NULL)
+ if (chart != NULL)
{
- error (0, errno, _("creating \"%s\""), ch->file_name);
- free (ch->file_name);
- ch->file_name = NULL;
- return;
+ assert (chart->ref_cnt > 0);
+ if (--chart->ref_cnt == 0)
+ chart->class->destroy (chart);
}
-
- ch->pl_params = pl_newplparams ();
- ch->lp = pl_newpl_r (type, 0, fp, stderr, ch->pl_params);
}
void
-chart_finalise_separate (struct chart *ch)
+chart_submit (struct chart *chart)
{
- free (ch->file_name);
+#ifdef HAVE_CAIRO
+ struct outp_driver *d;
+
+ for (d = outp_drivers (NULL); d; d = outp_drivers (d))
+ if (d->class->output_chart != NULL)
+ d->class->output_chart (d, chart);
+#endif
+
+ chart_unref (chart);
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <float.h>
-#include <assert.h>
-#include <math.h>
+#ifndef OUTPUT_CHART_H
+#define OUTPUT_CHART_H 1
-#include <math/chart-geometry.h>
-#include <libpspp/str.h>
-#include "manager.h"
-#include "output.h"
+#include <cairo/cairo.h>
-#include "xalloc.h"
+struct chart;
-#ifndef CHART_H
-#define CHART_H
+struct chart *chart_ref (const struct chart *);
+void chart_unref (struct chart *);
-#ifndef NO_CHARTS
-#include <plot.h>
-#endif
+void chart_submit (struct chart *);
-struct chart {
-
-#ifndef NO_CHARTS
- plPlotter *lp ;
- plPlotterParams *pl_params;
-#else
- void *lp;
-#endif
- char *file_name;
- FILE *file;
-
- /* The geometry of the chart
- See diagram at the foot of this file.
- */
-
- int data_top ;
- int data_right ;
- int data_bottom;
- int data_left ;
-
- int abscissa_top;
-
- int ordinate_right ;
-
- int title_bottom ;
-
- int legend_left ;
- int legend_right ;
- const char **dataset;
- int n_datasets;
-
-
- /* Default font size for the plot (if zero, then use plotter default) */
- int font_size;
-
- char fill_colour[10];
-
- /* Stuff Particular to Cartesians (and Boxplots ) */
- double ordinate_scale;
- double abscissa_scale;
- double x_min;
- double x_max;
- double y_min;
- double y_max;
- bool in_path;
-};
-
-
-
-struct chart * chart_create(void);
-void chart_submit(struct chart *ch);
-
-/* Helper functions for output drivers that put each chart into a
- separate file. */
-void chart_init_separate (struct chart *, const char *type,
- const char *file_name_tmpl, int number);
-
-void chart_finalise_separate (struct chart *);
-
-#endif
+#endif /* output/chart.h */
+++ /dev/null
-all:
- $(MAKE) -C /home/res/jmd/PSPP/pspp
+++ /dev/null
-## Process this file with automake to produce Makefile.in -*- makefile -*-
-
-noinst_LTLIBRARIES += src/output/charts/libcharts.la
-
-chart_sources = \
- src/output/charts/barchart.c \
- src/output/charts/barchart.h \
- src/output/charts/box-whisker.c \
- src/output/charts/box-whisker.h \
- src/output/charts/cartesian.c \
- src/output/charts/cartesian.h \
- src/output/charts/piechart.c \
- src/output/charts/piechart.h \
- src/output/charts/plot-chart.h \
- src/output/charts/plot-chart.c \
- src/output/charts/plot-hist.c \
- src/output/charts/plot-hist.h
-
-if WITHCHARTS
-src_output_charts_libcharts_la_SOURCES = \
- $(chart_sources)
-
-EXTRA_DIST += src/output/charts/dummy-chart.c
-else
-src_output_charts_libcharts_la_SOURCES = \
- src/output/charts/dummy-chart.c
-
-EXTRA_DIST += $(chart_sources)
-
-AM_CPPFLAGS += -DNO_CHARTS
-
-endif
-
-EXTRA_DIST += src/output/charts/OChangeLog
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2004, 2009 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-
-#include <config.h>
-
-#include <stdio.h>
-#include <plot.h>
-#include <stdarg.h>
-#include <math.h>
-#include <output/charts/barchart.h>
-#include <output/chart.h>
-#include <output/charts/plot-chart.h>
-
-#define CATAGORIES 6
-#define SUB_CATAGORIES 3
-
-static const double x_min = 0;
-static const double x_max = 15.0;
-
-static const char *cat_labels[] =
- {
- "Age",
- "Intelligence",
- "Wealth",
- "Emotional",
- "cat 5",
- "cat 6",
- "cat 7",
- "cat 8",
- "cat 9",
- "cat 10",
- "cat 11"
- };
-
-
-
-
-/* Subcatagories */
-static const double data1[] =
-{
- 28,83,
- 34,
- 29,13,
- 9,4,
- 3,3,
- 2,0,
- 1,0,
- 0,
- 1,1
-};
-
-
-static const double data2[] =
-{
- 45,13,
- 9,4,
- 3,43,
- 2,0,
- 1,20,
- 0,0,
- 1,1,
- 0,0
-};
-
-static const double data3[] =
- {
- 23,18,
- 0, 45,23, 9, 40, 24,4, 8
- };
-
-
-static const char subcat_name[]="Gender";
-
-
-struct subcat {
- const double *data;
- const char *label;
-};
-
-static const struct subcat sub_catagory[SUB_CATAGORIES] =
- {
- {data1, "male"},
- {data2, "female"},
- {data3, "47xxy"}
- };
-
-
-
-static const double y_min = 0;
-static const double y_max = 120.0;
-static const double y_tick = 20.0;
-
-
-
-static void write_legend(struct chart *chart) ;
-
-
-void
-draw_barchart(struct chart *ch, const char *title,
- const char *xlabel, const char *ylabel, enum bar_opts opt)
-{
- double d;
- int i;
-
- double interval_size = fabs(ch->data_right - ch->data_left) / ( CATAGORIES );
-
- double bar_width = interval_size / 1.1 ;
-
- double ordinate_scale = fabs(ch->data_top - ch->data_bottom) /
- fabs(y_max - y_min) ;
-
- if ( opt != BAR_STACKED )
- bar_width /= SUB_CATAGORIES;
-
- /* Move to data bottom-left */
- pl_move_r(ch->lp, ch->data_left, ch->data_bottom);
-
- pl_savestate_r(ch->lp);
- pl_filltype_r(ch->lp,1);
-
- /* Draw the data */
- for (i = 0 ; i < CATAGORIES ; ++i )
- {
- int sc;
- double ystart=0.0;
- double x = i * interval_size;
-
- pl_savestate_r(ch->lp);
-
- draw_tick (ch, TICK_ABSCISSA, x + (interval_size/2 ), "%s",
- cat_labels[i]);
-
- for(sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
- {
-
- pl_savestate_r(ch->lp);
- pl_fillcolorname_r(ch->lp,data_colour[sc % N_CHART_COLOURS]);
-
- switch ( opt )
- {
- case BAR_GROUPED:
- pl_fboxrel_r(ch->lp,
- x + (sc * bar_width ), 0,
- x + (sc + 1) * bar_width,
- sub_catagory[sc].data[i] * ordinate_scale );
- break;
-
-
- case BAR_STACKED:
-
- pl_fboxrel_r(ch->lp,
- x, ystart,
- x + bar_width,
- ystart + sub_catagory[sc].data[i] * ordinate_scale );
-
- ystart += sub_catagory[sc].data[i] * ordinate_scale ;
-
- break;
-
- default:
- break;
- }
- pl_restorestate_r(ch->lp);
- }
-
- pl_restorestate_r(ch->lp);
- }
- pl_restorestate_r(ch->lp);
-
- for ( d = y_min; d <= y_max ; d += y_tick )
- {
-
- draw_tick (ch, TICK_ORDINATE,
- (d - y_min ) * ordinate_scale, "%g", d);
-
- }
-
- /* Write the abscissa label */
- pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
- pl_alabel_r(ch->lp,0,'t',xlabel);
-
-
- /* Write the ordinate label */
- pl_savestate_r(ch->lp);
- pl_move_r(ch->lp,ch->data_bottom, ch->ordinate_right);
- pl_textangle_r(ch->lp,90);
- pl_alabel_r(ch->lp,0,0,ylabel);
- pl_restorestate_r(ch->lp);
-
-
- chart_write_title(ch, "%s", title);
-
- write_legend(ch);
-
-
-}
-
-
-
-
-
-static void
-write_legend(struct chart *chart)
-{
- int sc;
-
- pl_savestate_r(chart->lp);
-
- pl_filltype_r(chart->lp,1);
-
- pl_move_r(chart->lp, chart->legend_left,
- chart->data_bottom + chart->font_size * SUB_CATAGORIES * 1.5);
-
- pl_alabel_r(chart->lp,0,'b',subcat_name);
-
- for (sc = 0 ; sc < SUB_CATAGORIES ; ++sc )
- {
- pl_fmove_r(chart->lp,
- chart->legend_left,
- chart->data_bottom + chart->font_size * sc * 1.5);
-
- pl_savestate_r(chart->lp);
- pl_fillcolorname_r(chart->lp,data_colour[sc]);
- pl_fboxrel_r (chart->lp,
- 0,0,
- chart->font_size, chart->font_size);
- pl_restorestate_r(chart->lp);
-
- pl_fmove_r(chart->lp,
- chart->legend_left + chart->font_size * 1.5,
- chart->data_bottom + chart->font_size * sc * 1.5);
-
- pl_alabel_r(chart->lp,'l','b',sub_catagory[sc].label);
- }
-
-
- pl_restorestate_r(chart->lp);
-}
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef BARCHART_H
-#define BARCHART_H
-
-#include <output/chart.h>
-
-enum bar_opts {
- BAR_GROUPED = 0,
- BAR_STACKED,
- BAR_RANGE
-};
-
-void draw_barchart(struct chart *ch, const char *title,
- const char *xlabel, const char *ylabel, enum bar_opts opt);
-
-#endif
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-
-#include <config.h>
-
-#include <math.h>
-#include <assert.h>
-#include <libpspp/misc.h>
-
-#include <output/charts/box-whisker.h>
-#include <output/charts/plot-chart.h>
-
-#include <output/chart.h>
-#include <math/chart-geometry.h>
-#include <math/box-whisker.h>
-
-/* Draw a box-and-whiskers plot
-*/
-
-/* Draw an OUTLIER on the plot CH
- * at CENTRELINE
- */
-static void
-draw_case (struct chart *ch, double centreline,
- const struct outlier *outlier)
-{
-
-#define MARKER_CIRCLE 4
-#define MARKER_STAR 3
-
- pl_fmarker_r(ch->lp,
- centreline,
- ch->data_bottom + (outlier->value - ch->y_min) * ch->ordinate_scale,
- outlier->extreme ? MARKER_STAR : MARKER_CIRCLE,
- 20);
-
- pl_moverel_r(ch->lp, 10,0);
-
- pl_alabel_r(ch->lp, 'l', 'c', ds_cstr (&outlier->label));
-}
-
-
-void
-boxplot_draw_boxplot (struct chart *ch,
- double box_centre,
- double box_width,
- const struct box_whisker *bw,
- const char *name)
-{
- double whisker[2];
- double hinge[3];
- struct ll *ll;
-
- const struct ll_list *outliers;
-
- const double box_left = box_centre - box_width / 2.0;
-
- const double box_right = box_centre + box_width / 2.0;
-
- double box_bottom ;
- double box_top ;
- double bottom_whisker ;
- double top_whisker ;
-
- box_whisker_whiskers (bw, whisker);
- box_whisker_hinges (bw, hinge);
-
- box_bottom = ch->data_bottom + (hinge[0] - ch->y_min ) * ch->ordinate_scale;
-
- box_top = ch->data_bottom + (hinge[2] - ch->y_min ) * ch->ordinate_scale;
-
- bottom_whisker = ch->data_bottom + (whisker[0] - ch->y_min) *
- ch->ordinate_scale;
-
- top_whisker = ch->data_bottom + (whisker[1] - ch->y_min) * ch->ordinate_scale;
-
- pl_savestate_r(ch->lp);
-
- /* Draw the box */
- pl_savestate_r (ch->lp);
- pl_fillcolorname_r (ch->lp, ch->fill_colour);
- pl_filltype_r (ch->lp,1);
- pl_fbox_r (ch->lp,
- box_left,
- box_bottom,
- box_right,
- box_top);
-
- pl_restorestate_r (ch->lp);
-
- /* Draw the median */
- pl_savestate_r (ch->lp);
- pl_linewidth_r (ch->lp, 5);
- pl_fline_r (ch->lp,
- box_left,
- ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale,
- box_right,
- ch->data_bottom + (hinge[1] - ch->y_min) * ch->ordinate_scale);
- pl_restorestate_r (ch->lp);
-
- /* Draw the bottom whisker */
- pl_fline_r (ch->lp,
- box_left,
- bottom_whisker,
- box_right,
- bottom_whisker);
-
- /* Draw top whisker */
- pl_fline_r (ch->lp,
- box_left,
- top_whisker,
- box_right,
- top_whisker);
-
-
- /* Draw centre line.
- (bottom half) */
- pl_fline_r (ch->lp,
- box_centre, bottom_whisker,
- box_centre, box_bottom);
-
- /* (top half) */
- pl_fline_r (ch->lp,
- box_centre, top_whisker,
- box_centre, box_top);
-
- outliers = box_whisker_outliers (bw);
- for (ll = ll_head (outliers);
- ll != ll_null (outliers); ll = ll_next (ll))
- {
- const struct outlier *outlier = ll_data (ll, struct outlier, ll);
- draw_case (ch, box_centre, outlier);
- }
-
- /* Draw tick mark on x axis */
- draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, "%s", name);
-
- pl_restorestate_r(ch->lp);
-}
-
-void
-boxplot_draw_yscale (struct chart *ch, double y_max, double y_min)
-{
- double y_tick;
- double d;
-
- if ( !ch )
- return ;
-
- ch->y_max = y_max;
- ch->y_min = y_min;
-
- y_tick = chart_rounded_tick (fabs(ch->y_max - ch->y_min) / 5.0);
-
- ch->y_min = (ceil( ch->y_min / y_tick ) - 1.0 ) * y_tick;
-
- ch->y_max = ( floor( ch->y_max / y_tick ) + 1.0 ) * y_tick;
-
- ch->ordinate_scale = fabs(ch->data_top - ch->data_bottom)
- / fabs(ch->y_max - ch->y_min) ;
-
- /* Move to data bottom-left */
- pl_move_r(ch->lp,
- ch->data_left, ch->data_bottom);
-
- for ( d = ch->y_min; d <= ch->y_max ; d += y_tick )
- {
- draw_tick (ch, TICK_ORDINATE, (d - ch->y_min ) * ch->ordinate_scale, "%g", d);
- }
-}
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-#ifndef BOX_WHISKER_H
-#define BOX_WHISKER_H
-
-struct chart ;
-struct box_whisker;
-
-void boxplot_draw_boxplot (struct chart *ch,
- double box_centre,
- double box_width,
- const struct box_whisker *w,
- const char *name);
-
-
-void boxplot_draw_yscale (struct chart *ch , double y_max, double y_min);
-
-#endif
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+
+#include <config.h>
+
+#include <output/charts/boxplot.h>
+
+#include <math.h>
+#include <assert.h>
+#include <cairo/cairo.h>
+
+#include <libpspp/cast.h>
+#include <libpspp/misc.h>
+#include <math/chart-geometry.h>
+#include <math/box-whisker.h>
+#include <output/chart.h>
+#include <output/chart-provider.h>
+#include <output/charts/plot-chart.h>
+
+/* Draw a box-and-whiskers plot
+*/
+
+struct box
+ {
+ struct box_whisker *bw;
+ char *label;
+ };
+
+struct boxplot
+ {
+ struct chart chart;
+ double y_min;
+ double y_max;
+ char *title;
+ struct box *boxes;
+ size_t n_boxes, boxes_allocated;
+ };
+
+static const struct chart_class boxplot_chart_class;
+
+struct boxplot *
+boxplot_create (double y_min, double y_max, const char *title)
+{
+ struct boxplot *boxplot = xmalloc (sizeof *boxplot);
+ chart_init (&boxplot->chart, &boxplot_chart_class);
+ boxplot->y_min = y_min;
+ boxplot->y_max = y_max;
+ boxplot->title = xstrdup (title);
+ boxplot->boxes = NULL;
+ boxplot->n_boxes = boxplot->boxes_allocated = 0;
+ return boxplot;
+}
+
+void
+boxplot_add_box (struct boxplot *boxplot,
+ struct box_whisker *bw, const char *label)
+{
+ struct box *box;
+ if (boxplot->n_boxes >= boxplot->boxes_allocated)
+ boxplot->boxes = x2nrealloc (boxplot->boxes, &boxplot->boxes_allocated,
+ sizeof *boxplot->boxes);
+ box = &boxplot->boxes[boxplot->n_boxes++];
+ box->bw = bw;
+ box->label = xstrdup (label);
+}
+
+struct chart *
+boxplot_get_chart (struct boxplot *boxplot)
+{
+ return &boxplot->chart;
+}
+
+/* Draw an OUTLIER on the plot CH
+ * at CENTRELINE
+ */
+static void
+draw_case (cairo_t *cr, const struct chart_geometry *geom, double centreline,
+ const struct outlier *outlier)
+{
+ double y = geom->data_bottom + (outlier->value - geom->y_min) * geom->ordinate_scale;
+ chart_draw_marker (cr, centreline, y,
+ outlier->extreme ? MARKER_ASTERISK : MARKER_CIRCLE,
+ 20);
+
+ cairo_move_to (cr, centreline + 10, y);
+ chart_label (cr, 'l', 'c', geom->font_size, ds_cstr (&outlier->label));
+}
+
+static void
+boxplot_draw_box (cairo_t *cr, const struct chart_geometry *geom,
+ double box_centre,
+ double box_width,
+ const struct box_whisker *bw,
+ const char *name)
+{
+ double whisker[2];
+ double hinge[3];
+ struct ll *ll;
+
+ const struct ll_list *outliers;
+
+ const double box_left = box_centre - box_width / 2.0;
+
+ const double box_right = box_centre + box_width / 2.0;
+
+ double box_bottom ;
+ double box_top ;
+ double bottom_whisker ;
+ double top_whisker ;
+
+ box_whisker_whiskers (bw, whisker);
+ box_whisker_hinges (bw, hinge);
+
+ box_bottom = geom->data_bottom + (hinge[0] - geom->y_min ) * geom->ordinate_scale;
+
+ box_top = geom->data_bottom + (hinge[2] - geom->y_min ) * geom->ordinate_scale;
+
+ bottom_whisker = geom->data_bottom + (whisker[0] - geom->y_min) *
+ geom->ordinate_scale;
+
+ top_whisker = geom->data_bottom + (whisker[1] - geom->y_min) * geom->ordinate_scale;
+
+ /* Draw the box */
+ cairo_rectangle (cr,
+ box_left,
+ box_bottom,
+ box_right - box_left,
+ box_top - box_bottom);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr,
+ geom->fill_colour.red / 255.0,
+ geom->fill_colour.green / 255.0,
+ geom->fill_colour.blue / 255.0);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ cairo_stroke (cr);
+
+ /* Draw the median */
+ cairo_save (cr);
+ cairo_set_line_width (cr, cairo_get_line_width (cr) * 5);
+ cairo_move_to (cr,
+ box_left,
+ geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale);
+ cairo_line_to (cr,
+ box_right,
+ geom->data_bottom + (hinge[1] - geom->y_min) * geom->ordinate_scale);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ /* Draw the bottom whisker */
+ cairo_move_to (cr, box_left, bottom_whisker);
+ cairo_line_to (cr, box_right, bottom_whisker);
+ cairo_stroke (cr);
+
+ /* Draw top whisker */
+ cairo_move_to (cr, box_left, top_whisker);
+ cairo_line_to (cr, box_right, top_whisker);
+ cairo_stroke (cr);
+
+ /* Draw centre line.
+ (bottom half) */
+ cairo_move_to (cr, box_centre, bottom_whisker);
+ cairo_line_to (cr, box_centre, box_bottom);
+ cairo_stroke (cr);
+
+ /* (top half) */
+ cairo_move_to (cr, box_centre, top_whisker);
+ cairo_line_to (cr, box_centre, box_top);
+ cairo_stroke (cr);
+
+ outliers = box_whisker_outliers (bw);
+ for (ll = ll_head (outliers);
+ ll != ll_null (outliers); ll = ll_next (ll))
+ {
+ const struct outlier *outlier = ll_data (ll, struct outlier, ll);
+ draw_case (cr, geom, box_centre, outlier);
+ }
+
+ /* Draw tick mark on x axis */
+ draw_tick(cr, geom, TICK_ABSCISSA, box_centre - geom->data_left, "%s", name);
+}
+
+static void
+boxplot_draw_yscale (cairo_t *cr, struct chart_geometry *geom,
+ double y_max, double y_min)
+{
+ double y_tick;
+ double d;
+
+ geom->y_max = y_max;
+ geom->y_min = y_min;
+
+ y_tick = chart_rounded_tick (fabs (geom->y_max - geom->y_min) / 5.0);
+
+ geom->y_min = (ceil (geom->y_min / y_tick) - 1.0) * y_tick;
+
+ geom->y_max = (floor (geom->y_max / y_tick) + 1.0) * y_tick;
+
+ geom->ordinate_scale = (fabs (geom->data_top - geom->data_bottom)
+ / fabs (geom->y_max - geom->y_min));
+
+ for (d = geom->y_min; d <= geom->y_max; d += y_tick)
+ draw_tick (cr, geom, TICK_ORDINATE,
+ (d - geom->y_min) * geom->ordinate_scale, "%g", d);
+}
+
+static void
+boxplot_chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ const struct boxplot *boxplot = UP_CAST (chart, struct boxplot, chart);
+ double box_width;
+ size_t i;
+
+ boxplot_draw_yscale (cr, geom, boxplot->y_max, boxplot->y_min);
+ chart_write_title (cr, geom, "%s", boxplot->title);
+
+ box_width = (geom->data_right - geom->data_left) / boxplot->n_boxes / 2.0;
+ for (i = 0; i < boxplot->n_boxes; i++)
+ {
+ const struct box *box = &boxplot->boxes[i];
+ const double box_centre = (i * 2 + 1) * box_width + geom->data_left;
+ boxplot_draw_box (cr, geom, box_centre, box_width, box->bw, box->label);
+ }
+}
+
+static void
+boxplot_chart_destroy (struct chart *chart)
+{
+ struct boxplot *boxplot = UP_CAST (chart, struct boxplot, chart);
+ size_t i;
+
+ free (boxplot->title);
+ for (i = 0; i < boxplot->n_boxes; i++)
+ {
+ struct box *box = &boxplot->boxes[i];
+ struct statistic *statistic = &box->bw->parent.parent;
+ statistic->destroy (statistic);
+ free (box->label);
+ }
+ free (boxplot->boxes);
+ free (boxplot);
+}
+
+static const struct chart_class boxplot_chart_class =
+ {
+ boxplot_chart_draw,
+ boxplot_chart_destroy
+ };
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CHARTS_BOXPLOT_H
+#define OUTPUT_CHARTS_BOXPLOT_H 1
+
+struct box_whisker;
+
+struct boxplot *boxplot_create (double y_min, double y_max, const char *title);
+void boxplot_add_box (struct boxplot *,
+ struct box_whisker *, const char *label);
+struct chart *boxplot_get_chart (struct boxplot *);
+
+#endif /* output/charts/boxplot.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <config.h>
+#include <output/charts/cartesian.h>
+
+#include <cairo/cairo.h>
#include <math.h>
#include <assert.h>
#include <output/chart.h>
-
+#include <output/chart-provider.h>
#include <output/charts/plot-chart.h>
-#include <output/charts/cartesian.h>
#include <libpspp/compiler.h>
+#include "xalloc.h"
/* Start a new vector called NAME */
void
-chart_vector_start (struct chart *ch, const char *name)
+chart_vector_start (cairo_t *cr, struct chart_geometry *geom, const char *name)
{
- if ( ! ch )
- return ;
+ const struct chart_colour *colour;
- pl_savestate_r (ch->lp);
+ cairo_save (cr);
- pl_colorname_r (ch->lp, data_colour [ch->n_datasets % N_CHART_COLOURS]);
+ colour = &data_colour[geom->n_datasets % N_CHART_COLOURS];
+ cairo_set_source_rgb (cr,
+ colour->red / 255.0,
+ colour->green / 255.0,
+ colour->blue / 255.0);
- ch->n_datasets++;
- ch->dataset = xrealloc (ch->dataset, ch->n_datasets * sizeof (*ch->dataset));
+ geom->n_datasets++;
+ geom->dataset = xrealloc (geom->dataset,
+ geom->n_datasets * sizeof (*geom->dataset));
- ch->dataset[ch->n_datasets - 1] = strdup (name);
+ geom->dataset[geom->n_datasets - 1] = strdup (name);
}
/* Plot a data point */
void
-chart_datum (struct chart *ch, int dataset UNUSED, double x, double y)
+chart_datum (cairo_t *cr, const struct chart_geometry *geom,
+ int dataset UNUSED, double x, double y)
{
- if ( ! ch )
- return ;
-
- {
- const double x_pos =
- (x - ch->x_min) * ch->abscissa_scale + ch->data_left ;
+ double x_pos = (x - geom->x_min) * geom->abscissa_scale + geom->data_left;
+ double y_pos = (y - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
- const double y_pos =
- (y - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-
- pl_savestate_r(ch->lp);
-
- pl_fmarker_r(ch->lp, x_pos, y_pos, 6, 15);
-
- pl_restorestate_r(ch->lp);
- }
+ chart_draw_marker (cr, x_pos, y_pos, MARKER_SQUARE, 15);
}
void
-chart_vector_end (struct chart *ch)
+chart_vector_end (cairo_t *cr, struct chart_geometry *geom)
{
- pl_endpath_r (ch->lp);
- pl_colorname_r (ch->lp, "black");
- ch->in_path = false;
- pl_restorestate_r (ch->lp);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ geom->in_path = false;
}
/* Plot a data point */
void
-chart_vector (struct chart *ch, double x, double y)
+chart_vector (cairo_t *cr, struct chart_geometry *geom, double x, double y)
{
- if ( ! ch )
- return ;
-
- {
- const double x_pos =
- (x - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-
- const double y_pos =
- (y - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
-
- if ( ch->in_path)
- pl_fcont_r (ch->lp, x_pos, y_pos);
- else
- {
- pl_fmove_r (ch->lp, x_pos, y_pos);
- ch->in_path = true;
- }
- }
+ const double x_pos =
+ (x - geom->x_min) * geom->abscissa_scale + geom->data_left ;
+
+ const double y_pos =
+ (y - geom->y_min) * geom->ordinate_scale + geom->data_bottom ;
+
+ if (geom->in_path)
+ cairo_line_to (cr, x_pos, y_pos);
+ else
+ {
+ cairo_move_to (cr, x_pos, y_pos);
+ geom->in_path = true;
+ }
}
y axis otherwise the x axis
*/
void
-chart_line (struct chart *ch, double slope, double intercept,
+chart_line(cairo_t *cr, const struct chart_geometry *geom,
+ double slope, double intercept,
double limit1, double limit2, enum CHART_DIM lim_dim)
{
double x1, y1;
- double x2, y2 ;
-
- if ( ! ch )
- return ;
-
+ double x2, y2;
if ( lim_dim == CHART_DIM_Y )
{
- x1 = ( limit1 - intercept ) / slope ;
- x2 = ( limit2 - intercept ) / slope ;
+ x1 = ( limit1 - intercept ) / slope;
+ x2 = ( limit2 - intercept ) / slope;
y1 = limit1;
y2 = limit2;
}
y2 = slope * x2 + intercept;
}
- y1 = (y1 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
- y2 = (y2 - ch->y_min) * ch->ordinate_scale + ch->data_bottom ;
- x1 = (x1 - ch->x_min) * ch->abscissa_scale + ch->data_left ;
- x2 = (x2 - ch->x_min) * ch->abscissa_scale + ch->data_left ;
-
- pl_savestate_r(ch->lp);
-
- pl_fline_r(ch->lp, x1, y1, x2, y2);
+ y1 = (y1 - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
+ y2 = (y2 - geom->y_min) * geom->ordinate_scale + geom->data_bottom;
+ x1 = (x1 - geom->x_min) * geom->abscissa_scale + geom->data_left;
+ x2 = (x2 - geom->x_min) * geom->abscissa_scale + geom->data_left;
- pl_restorestate_r(ch->lp);
+ cairo_move_to (cr, x1, y1);
+ cairo_line_to (cr, x2, y2);
+ cairo_stroke (cr);
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#ifndef CARTESIAN_H
#define CARTESIAN_H
+#include <cairo/cairo.h>
+#include <libpspp/compiler.h>
+#include <output/chart.h>
enum CHART_DIM
{
CHART_DIM_Y
};
+struct chart_geometry;
-void chart_vector_start (struct chart *ch, const char *name);
-void chart_vector (struct chart *ch, double x, double y);
-void chart_vector_end (struct chart *ch);
+void chart_vector_start (cairo_t *, struct chart_geometry *,
+ const char *name);
+void chart_vector_end (cairo_t *, struct chart_geometry *);
+void chart_vector (cairo_t *, struct chart_geometry *, double x, double y);
/* Plot a data point */
-void chart_datum (struct chart *ch, int dataset UNUSED, double x, double y);
+void chart_datum(cairo_t *, const struct chart_geometry *,
+ int dataset UNUSED, double x, double y);
/* Draw a line with slope SLOPE and intercept INTERCEPT.
between the points limit1 and limit2.
If lim_dim is CHART_DIM_Y then the limit{1,2} are on the
y axis otherwise the x axis
*/
-void chart_line (struct chart *ch, double slope, double intercept,
+void chart_line(cairo_t *, const struct chart_geometry *,
+ double slope, double intercept,
double limit1, double limit2, enum CHART_DIM lim_dim);
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2005 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-
-/* Stubs for plotting routines.
- This module is linked only when charts are not supported */
-
-#include "config.h"
-#include <output/chart.h>
-#include <output/charts/box-whisker.h>
-#include <output/charts/piechart.h>
-#include <output/charts/plot-chart.h>
-#include <output/charts/plot-hist.h>
-#include <output/charts/cartesian.h>
-#include <gsl/gsl_histogram.h>
-#include <libpspp/compiler.h>
-
-#ifndef NO_CHARTS
-#error This file should be used only when compiling without charts.
-#endif
-
-void
-chart_write_legend (struct chart *ch UNUSED)
-{
-}
-
-void
-chart_vector (struct chart *ch UNUSED, double x UNUSED, double y UNUSED)
-{
-}
-
-void
-chart_vector_end (struct chart *ch UNUSED)
-{
-}
-
-void
-chart_vector_start (struct chart *ch UNUSED, const char *name UNUSED)
-{
-}
-
-void
-chart_write_title (struct chart *chart UNUSED, const char *title UNUSED, ...)
-{
-}
-
-
-void
-chart_write_xscale (struct chart *ch UNUSED,
- double min UNUSED, double max UNUSED, int ticks UNUSED)
-{
-}
-
-
-void
-chart_write_yscale (struct chart *ch UNUSED UNUSED,
- double smin UNUSED, double smax UNUSED, int ticks UNUSED)
-{
-}
-
-
-void
-chart_write_xlabel (struct chart *ch UNUSED, const char *label UNUSED)
-{
-}
-
-void
-chart_write_ylabel (struct chart *ch UNUSED, const char *label UNUSED)
-{
-}
-
-
-void
-chart_line (struct chart *ch UNUSED,
- double slope UNUSED, double intercept UNUSED,
- double limit1 UNUSED, double limit2 UNUSED,
- enum CHART_DIM lim_dim UNUSED)
-{
-}
-
-
-void
-chart_datum (struct chart *ch UNUSED, int dataset UNUSED UNUSED,
- double x UNUSED, double y UNUSED)
-{
-}
-
-void
-histogram_plot (const struct histogram *hist UNUSED,
- const char *label UNUSED,
- const struct moments1 *m UNUSED)
-{
-}
-
-void
-histogram_plot_n (const struct histogram *hist UNUSED,
- const char *label UNUSED,
- double n UNUSED, double mean UNUSED, double stddev UNUSED,
- bool show_normal UNUSED)
-{
-}
-
-
-void
-boxplot_draw_yscale (struct chart *ch UNUSED,
- double y_max UNUSED, double y_min UNUSED)
-{
-}
-
-void
-boxplot_draw_boxplot (struct chart *ch UNUSED,
- double box_centre UNUSED,
- double box_width UNUSED,
- const struct box_whisker *w UNUSED,
- const char *name UNUSED)
-{
-}
-
-
-
-
-void
-piechart_plot (const char *title UNUSED,
- const struct slice *slices UNUSED, int n_slices UNUSED)
-{
-}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <output/charts/np-plot.h>
+
+#include <gsl/gsl_cdf.h>
+
+#include <data/casereader.h>
+#include <data/casewriter.h>
+#include <libpspp/cast.h>
+#include <libpspp/message.h>
+#include <math/np.h>
+#include <output/chart-provider.h>
+#include <output/charts/cartesian.h>
+#include <output/charts/plot-chart.h>
+
+#include "gl/minmax.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* An NP or DNP plot. */
+struct np_plot_chart
+ {
+ struct chart chart;
+ char *label;
+ struct casereader *data;
+
+ /* Copied directly from struct np. */
+ double y_min, y_max;
+ double dns_min, dns_max;
+
+ /* Calculated. */
+ double slope, intercept;
+ double y_first, y_last;
+ double x_lower, x_upper;
+ double slack;
+ };
+
+static const struct chart_class np_plot_chart_class;
+static const struct chart_class dnp_plot_chart_class;
+
+static struct chart *
+make_np_plot (const struct chart_class *class,
+ const struct np *np, const struct casereader *reader,
+ const char *label)
+{
+ struct np_plot_chart *npp;
+
+ if (np->n < 1.0)
+ return NULL;
+
+ npp = xmalloc (sizeof *npp);
+ chart_init (&npp->chart, class);
+ npp->label = xstrdup (label);
+ npp->data = casereader_clone (reader);
+ npp->y_min = np->y_min;
+ npp->y_max = np->y_max;
+ npp->dns_min = np->dns_min;
+ npp->dns_max = np->dns_max;
+
+ /* Slope and intercept of the ideal normal probability line. */
+ npp->slope = 1.0 / np->stddev;
+ npp->intercept = -np->mean / np->stddev;
+
+ npp->y_first = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
+ npp->y_last = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
+
+ /* Need to make sure that both the scatter plot and the ideal fit into the
+ plot. */
+ npp->x_lower = MIN (np->y_min, (npp->y_first - npp->intercept) / npp->slope);
+ npp->x_upper = MAX (np->y_max, (npp->y_last - npp->intercept) / npp->slope);
+ npp->slack = (npp->x_upper - npp->x_lower) * 0.05;
+
+ return &npp->chart;
+}
+
+/* Creates and returns a normal probability plot corresponding to
+ the calculations in NP and the data in READER, and label the
+ plot with LABEL. The data in READER must have Y-values in
+ value index NP_IDX_Y and NS-values in value index NP_IDX_NS.
+
+ Returns a null pointer if the data set is empty.
+
+ The caller retains ownership of NP and READER. */
+struct chart *
+np_plot_create (const struct np *np, const struct casereader *reader,
+ const char *label)
+{
+ return make_np_plot (&np_plot_chart_class, np, reader, label);
+}
+
+/* Creates and returns a detrended normal probability plot
+ corresponding to the calculations in NP and the data in
+ READER, and label the plot with LABEL. The data in READER
+ must have Y-values in value index NP_IDX_Y and DNS-values in
+ value index NP_IDX_DNS.
+
+ Returns a null pointer if the data set is empty.
+
+ The caller retains ownership of NP and READER. */
+struct chart *
+dnp_plot_create (const struct np *np, const struct casereader *reader,
+ const char *label)
+{
+ return make_np_plot (&dnp_plot_chart_class, np, reader, label);
+}
+
+static void
+np_plot_chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ const struct np_plot_chart *npp = UP_CAST (chart, struct np_plot_chart,
+ chart);
+ struct casereader *data;
+ struct ccase *c;
+
+ chart_write_title (cr, geom, _("Normal Q-Q Plot of %s"), npp->label);
+ chart_write_xlabel (cr, geom, _("Observed Value"));
+ chart_write_ylabel (cr, geom, _("Expected Normal"));
+ chart_write_xscale (cr, geom,
+ npp->x_lower - npp->slack,
+ npp->x_upper + npp->slack, 5);
+ chart_write_yscale (cr, geom, npp->y_first, npp->y_last, 5);
+
+ data = casereader_clone (npp->data);
+ for (; (c = casereader_read (data)) != NULL; case_unref (c))
+ chart_datum (cr, geom, 0,
+ case_data_idx (c, NP_IDX_Y)->f,
+ case_data_idx (c, NP_IDX_NS)->f);
+ casereader_destroy (data);
+
+ chart_line (cr, geom, npp->slope, npp->intercept,
+ npp->y_first, npp->y_last, CHART_DIM_Y);
+}
+
+static void
+dnp_plot_chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ const struct np_plot_chart *dnpp = UP_CAST (chart, struct np_plot_chart,
+ chart);
+ struct casereader *data;
+ struct ccase *c;
+
+ chart_write_title (cr, geom, _("Detrended Normal Q-Q Plot of %s"),
+ dnpp->label);
+ chart_write_xlabel (cr, geom, _("Observed Value"));
+ chart_write_ylabel (cr, geom, _("Dev from Normal"));
+ chart_write_xscale (cr, geom, dnpp->y_min, dnpp->y_max, 5);
+ chart_write_yscale (cr, geom, dnpp->dns_min, dnpp->dns_max, 5);
+
+ data = casereader_clone (dnpp->data);
+ for (; (c = casereader_read (data)) != NULL; case_unref (c))
+ chart_datum (cr, geom, 0, case_data_idx (c, NP_IDX_Y)->f,
+ case_data_idx (c, NP_IDX_DNS)->f);
+ casereader_destroy (data);
+
+ chart_line (cr, geom, 0, 0, dnpp->y_min, dnpp->y_max, CHART_DIM_X);
+}
+
+static void
+np_plot_chart_destroy (struct chart *chart)
+{
+ struct np_plot_chart *npp = UP_CAST (chart, struct np_plot_chart, chart);
+ casereader_destroy (npp->data);
+ free (npp->label);
+ free (npp);
+}
+
+static const struct chart_class np_plot_chart_class =
+ {
+ np_plot_chart_draw,
+ np_plot_chart_destroy
+ };
+
+static const struct chart_class dnp_plot_chart_class =
+ {
+ dnp_plot_chart_draw,
+ np_plot_chart_destroy
+ };
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2004, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CHARTS_NP_PLOT_H
+#define OUTPUT_CHARTS_NP_PLOT_H 1
+
+struct casereader;
+struct np;
+
+struct chart *np_plot_create (const struct np *, const struct casereader *,
+ const char *label);
+struct chart *dnp_plot_create (const struct np *, const struct casereader *,
+ const char *label);
+
+#endif /* output/charts/np-plot.h */
#include <config.h>
-#include <float.h>
+#include <output/charts/piechart.h>
+
#include <assert.h>
+#include <float.h>
+#include <gsl/gsl_math.h>
#include <math.h>
#include <stdio.h>
-
-#include <output/charts/piechart.h>
-#include <output/charts/plot-chart.h>
-
-#include <output/chart.h>
-#include <libpspp/str.h>
#include <data/value-labels.h>
+#include <libpspp/cast.h>
+#include <libpspp/str.h>
+#include <output/charts/plot-chart.h>
+#include <output/chart-provider.h>
#include "minmax.h"
+struct piechart
+ {
+ struct chart chart;
+ char *title;
+ struct slice *slices;
+ int n_slices;
+ };
-/* Pie charts of course need to know Pi :) */
-#ifndef M_PI
-#define M_PI ( 22.0 / 7.0 )
-#endif
-
-
+static const struct chart_class piechart_class;
/* Draw a single slice of the pie */
static void
-draw_segment(struct chart *ch,
+draw_segment(cairo_t *,
double centre_x, double centre_y,
double radius,
double start_angle, double segment_angle,
- const char *colour) ;
+ const struct chart_colour *) ;
-/* Draw a piechart */
-void
-piechart_plot(const char *title, const struct slice *slices, int n_slices)
+/* Creates and returns a chart that will render a piechart with
+ the given TITLE and the N_SLICES described in SLICES. */
+struct chart *
+piechart_create (const char *title, const struct slice *slices, int n_slices)
{
+ struct piechart *pie;
int i;
- double total_magnetude=0;
-
- struct chart *ch;
- double left_label;
- double right_label;
+ pie = xmalloc (sizeof *pie);
+ chart_init (&pie->chart, &piechart_class);
+ pie->title = xstrdup (title);
+ pie->slices = xnmalloc (n_slices, sizeof *pie->slices);
+ for (i = 0; i < n_slices; i++)
+ {
+ const struct slice *src = &slices[i];
+ struct slice *dst = &pie->slices[i];
- double centre_x;
- double centre_y;
+ ds_init_string (&dst->label, &src->label);
+ dst->magnitude = src->magnitude;
+ }
+ pie->n_slices = n_slices;
+ return &pie->chart;
+}
+static void
+piechart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ const struct piechart *pie = UP_CAST (chart, struct piechart, chart);
+ double total_magnitude;
+ double left_label, right_label;
+ double centre_x, centre_y;
double radius;
+ double angle;
+ int i;
- ch = chart_create ();
- if (ch == NULL)
- return;
+ centre_x = (geom->data_right + geom->data_left) / 2.0 ;
+ centre_y = (geom->data_top + geom->data_bottom) / 2.0 ;
- left_label = ch->data_left + (ch->data_right - ch->data_left)/10.0;
- right_label = ch->data_right - (ch->data_right - ch->data_left)/10.0;
- centre_x = (ch->data_right + ch->data_left ) / 2.0;
- centre_y = (ch->data_top + ch->data_bottom ) / 2.0;
- radius = MIN (5.0 / 12.0 * (ch->data_top - ch->data_bottom),
- 1.0 / 4.0 * (ch->data_right - ch->data_left));
+ left_label = geom->data_left + (geom->data_right - geom->data_left)/10.0;
+ right_label = geom->data_right - (geom->data_right - geom->data_left)/10.0;
- chart_write_title(ch, "%s", title);
+ radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
+ 1.0 / 4.0 * (geom->data_right - geom->data_left));
- for (i = 0 ; i < n_slices ; ++i )
- total_magnetude += slices[i].magnetude;
+ radius = MIN (5.0 / 12.0 * (geom->data_top - geom->data_bottom),
+ 1.0 / 4.0 * (geom->data_right - geom->data_left));
- for (i = 0 ; i < n_slices ; ++i )
- {
- static double angle=0.0;
+ chart_write_title (cr, geom, "%s", pie->title);
+ total_magnitude = 0.0;
+ for (i = 0; i < pie->n_slices; i++)
+ total_magnitude += pie->slices[i].magnitude;
+
+ angle = 0.0;
+ for (i = 0; i < pie->n_slices ; ++i )
+ {
const double segment_angle =
- slices[i].magnetude / total_magnetude * 2 * M_PI ;
+ pie->slices[i].magnitude / total_magnitude * 2 * M_PI ;
const double label_x = centre_x -
radius * sin(angle + segment_angle/2.0);
radius * cos(angle + segment_angle/2.0);
/* Fill the segment */
- draw_segment(ch,
- centre_x, centre_y, radius,
- angle, segment_angle,
- data_colour[i % N_CHART_COLOURS]);
+ draw_segment (cr,
+ centre_x, centre_y, radius,
+ angle, segment_angle,
+ &data_colour[i % N_CHART_COLOURS]);
/* Now add the labels */
if ( label_x < centre_x )
{
- pl_line_r(ch->lp, label_x, label_y,
- left_label, label_y );
- pl_moverel_r(ch->lp,0,5);
- pl_alabel_r (ch->lp, 0, 0, ds_cstr (&slices[i].label));
+ cairo_move_to (cr, label_x, label_y);
+ cairo_line_to (cr, left_label, label_y);
+ cairo_stroke (cr);
+ cairo_move_to (cr, left_label, label_y + 5);
+ chart_label (cr, 'l', 'x', geom->font_size,
+ ds_cstr (&pie->slices[i].label));
}
else
{
- pl_line_r(ch->lp,
- label_x, label_y,
- right_label, label_y
- );
- pl_moverel_r(ch->lp,0,5);
- pl_alabel_r (ch->lp, 'r', 0, ds_cstr (&slices[i].label));
+ cairo_move_to (cr, label_x, label_y);
+ cairo_line_to (cr, right_label, label_y);
+ cairo_stroke (cr);
+ cairo_move_to (cr, right_label, label_y + 5);
+ chart_label (cr, 'r', 'x', geom->font_size,
+ ds_cstr (&pie->slices[i].label));
}
angle += segment_angle;
-
}
/* Draw an outline to the pie */
- pl_filltype_r(ch->lp,0);
- pl_fcircle_r (ch->lp, centre_x, centre_y, radius);
-
- chart_submit(ch);
+ cairo_arc (cr, centre_x, centre_y, radius, 0, 2 * M_PI);
+ cairo_stroke (cr);
}
+/* Draw a single slice of the pie */
static void
-fill_segment(struct chart *ch,
- double x0, double y0,
- double radius,
- double start_angle, double segment_angle) ;
-
-
-/* Fill a segment with the current fill colour */
-static void
-fill_segment(struct chart *ch,
+draw_segment(cairo_t *cr,
double x0, double y0,
double radius,
- double start_angle, double segment_angle)
+ double start_angle, double segment_angle,
+ const struct chart_colour *colour)
{
-
- const double start_x = x0 - radius * sin(start_angle);
- const double start_y = y0 + radius * cos(start_angle);
-
- const double stop_x =
- x0 - radius * sin(start_angle + segment_angle);
-
- const double stop_y =
- y0 + radius * cos(start_angle + segment_angle);
-
- assert(segment_angle <= 2 * M_PI);
- assert(segment_angle >= 0);
-
- if ( segment_angle > M_PI )
- {
- /* Then we must draw it in two halves */
- fill_segment(ch, x0, y0, radius, start_angle, segment_angle / 2.0 );
- fill_segment(ch, x0, y0, radius, start_angle + segment_angle / 2.0,
- segment_angle / 2.0 );
- }
- else
- {
- pl_move_r(ch->lp, x0, y0);
-
- pl_cont_r(ch->lp, stop_x, stop_y);
- pl_cont_r(ch->lp, start_x, start_y);
-
- pl_arc_r(ch->lp,
- x0, y0,
- stop_x, stop_y,
- start_x, start_y
- );
-
- pl_endpath_r(ch->lp);
- }
+ cairo_move_to (cr, x0, y0);
+ cairo_arc (cr, x0, y0, radius, start_angle, start_angle + segment_angle);
+ cairo_line_to (cr, x0, y0);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr,
+ colour->red / 255.0,
+ colour->green / 255.0,
+ colour->blue / 255.0);
+ cairo_fill_preserve (cr);
+ cairo_restore (cr);
+ cairo_stroke (cr);
}
-
-
-/* Draw a single slice of the pie */
static void
-draw_segment(struct chart *ch,
- double x0, double y0,
- double radius,
- double start_angle, double segment_angle,
- const char *colour)
+piechart_destroy (struct chart *chart)
{
- const double start_x = x0 - radius * sin(start_angle);
- const double start_y = y0 + radius * cos(start_angle);
-
- pl_savestate_r(ch->lp);
-
- pl_savestate_r(ch->lp);
- pl_colorname_r(ch->lp, colour);
-
- pl_pentype_r(ch->lp,1);
- pl_filltype_r(ch->lp,1);
-
- fill_segment(ch, x0, y0, radius, start_angle, segment_angle);
- pl_restorestate_r(ch->lp);
-
- /* Draw line dividing segments */
- pl_pentype_r(ch->lp, 1);
- pl_fline_r(ch->lp, x0, y0, start_x, start_y);
-
+ struct piechart *pie = UP_CAST (chart, struct piechart, chart);
+ int i;
- pl_restorestate_r(ch->lp);
+ free (pie->title);
+ for (i = 0; i < pie->n_slices; i++)
+ {
+ struct slice *slice = &pie->slices[i];
+ ds_destroy (&slice->label);
+ }
+ free (pie->slices);
+ free (pie);
}
+static const struct chart_class piechart_class =
+ {
+ piechart_draw,
+ piechart_destroy
+ };
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
struct slice {
struct string label;
- double magnetude;
+ double magnitude;
};
-/* Draw a piechart */
-void piechart_plot(const char *title,
- const struct slice *slices, int n_slices);
+struct chart *piechart_create (const char *title,
+ const struct slice *, int n_slices);
#endif
#include <config.h>
-#include <stdio.h>
-#include <plot.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdio.h>
-#include <float.h>
-#include <assert.h>
-#include <math.h>
-
#include <output/charts/plot-chart.h>
-#include <math/chart-geometry.h>
-
-
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+#include <pango/pango-font.h>
+#include <pango/pango-layout.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdio.h>
+#include <string.h>
-#include <libpspp/str.h>
#include <libpspp/assertion.h>
+#include <libpspp/str.h>
+#include <math/chart-geometry.h>
+#include <output/chart-provider.h>
#include <output/manager.h>
#include <output/output.h>
#include "xalloc.h"
-const char *const data_colour[N_CHART_COLOURS] =
+#if ! PANGO_VERSION_CHECK (2, 22, 0)
+int pango_layout_get_baseline (PangoLayout *layout);
+
+/* Shamelessly copied from the pango source */
+int
+pango_layout_get_baseline (PangoLayout *layout)
+{
+ int baseline;
+
+ /* XXX this is so inefficient */
+ PangoLayoutIter *iter = pango_layout_get_iter (layout);
+ baseline = pango_layout_iter_get_baseline (iter);
+ pango_layout_iter_free (iter);
+
+ return baseline;
+}
+#endif
+
+
+
+const struct chart_colour data_colour[N_CHART_COLOURS] =
{
- "brown",
- "red",
- "orange",
- "yellow",
- "green",
- "blue",
- "violet",
- "grey",
- "pink"
+ { 165, 42, 42 }, /* brown */
+ { 255, 0, 0 }, /* red */
+ { 255, 165, 0 }, /* orange */
+ { 255, 255, 0 }, /* yellow */
+ { 0, 255, 0 }, /* green */
+ { 0, 0, 255 }, /* blue */
+ { 238, 130, 238 }, /* violet */
+ { 190, 190, 190 }, /* grey */
+ { 255, 192, 203 }, /* pink */
};
+void
+chart_draw_marker (cairo_t *cr, double x, double y, enum marker_type marker,
+ double size)
+{
+ cairo_save (cr);
+ cairo_translate (cr, x, y);
+ cairo_scale (cr, size / 2.0, size / 2.0);
+ cairo_set_line_width (cr, cairo_get_line_width (cr) / (size / 2.0));
+ switch (marker)
+ {
+ case MARKER_CIRCLE:
+ cairo_arc (cr, 0, 0, 1.0, 0, 2 * M_PI);
+ cairo_stroke (cr);
+ break;
+
+ case MARKER_ASTERISK:
+ cairo_move_to (cr, 0, -1.0); /* | */
+ cairo_line_to (cr, 0, 1.0);
+ cairo_move_to (cr, -M_SQRT1_2, -M_SQRT1_2); /* / */
+ cairo_line_to (cr, M_SQRT1_2, M_SQRT1_2);
+ cairo_move_to (cr, -M_SQRT1_2, M_SQRT1_2); /* \ */
+ cairo_line_to (cr, M_SQRT1_2, -M_SQRT1_2);
+ cairo_stroke (cr);
+ break;
+
+ case MARKER_SQUARE:
+ cairo_rectangle (cr, -1.0, -1.0, 2.0, 2.0);
+ cairo_stroke (cr);
+ break;
+ }
+ cairo_restore (cr);
+}
+void
+chart_label (cairo_t *cr, int horz_justify, int vert_justify, double font_size,
+ const char *string)
+{
+ PangoFontDescription *desc;
+ PangoLayout *layout;
+ double x, y;
+
+ desc = pango_font_description_from_string ("sans serif");
+ if (desc == NULL)
+ {
+ cairo_new_path (cr);
+ return;
+ }
+ pango_font_description_set_absolute_size (desc, font_size * PANGO_SCALE);
+
+ cairo_save (cr);
+ cairo_get_current_point (cr, &x, &y);
+ cairo_translate (cr, x, y);
+ cairo_move_to (cr, 0, 0);
+ cairo_scale (cr, 1.0, -1.0);
+
+ layout = pango_cairo_create_layout (cr);
+ pango_layout_set_font_description (layout, desc);
+ pango_layout_set_text (layout, string, -1);
+ if (horz_justify != 'l')
+ {
+ int width_pango;
+ double width;
+
+ pango_layout_get_size (layout, &width_pango, NULL);
+ width = (double) width_pango / PANGO_SCALE;
+ if (horz_justify == 'r')
+ cairo_rel_move_to (cr, -width, 0);
+ else
+ cairo_rel_move_to (cr, -width / 2.0, 0);
+ }
+ if (vert_justify == 'x')
+ {
+ int baseline_pango = pango_layout_get_baseline (layout);
+ double baseline = (double) baseline_pango / PANGO_SCALE;
+ cairo_rel_move_to (cr, 0, -baseline);
+ }
+ else if (vert_justify != 't')
+ {
+ int height_pango;
+ double height;
+
+ pango_layout_get_size (layout, NULL, &height_pango);
+ height = (double) height_pango / PANGO_SCALE;
+ if (vert_justify == 'b')
+ cairo_rel_move_to (cr, 0, -height);
+ else if (vert_justify == 'c')
+ cairo_rel_move_to (cr, 0, -height / 2.0);
+ }
+ pango_cairo_show_layout (cr, layout);
+ g_object_unref (layout);
+
+ cairo_restore (cr);
+
+ cairo_new_path (cr);
+
+ pango_font_description_free (desc);
+}
/* Draw a tick mark at position
If label is non zero, then print it at the tick mark
*/
void
-draw_tick(struct chart *chart,
- enum tick_orientation orientation,
- double position,
- const char *label, ...)
+draw_tick (cairo_t *cr, const struct chart_geometry *geom,
+ enum tick_orientation orientation,
+ double position,
+ const char *label, ...)
{
const int tickSize = 10;
+ double x, y;
- assert(chart);
-
- pl_savestate_r(chart->lp);
+ cairo_move_to (cr, geom->data_left, geom->data_bottom);
- pl_move_r(chart->lp, chart->data_left, chart->data_bottom);
-
- if ( orientation == TICK_ABSCISSA )
- pl_flinerel_r(chart->lp, position, 0, position, -tickSize);
- else if (orientation == TICK_ORDINATE )
- pl_flinerel_r(chart->lp, 0, position, -tickSize, position);
+ if (orientation == TICK_ABSCISSA)
+ {
+ cairo_rel_move_to (cr, position, 0);
+ cairo_rel_line_to (cr, 0, -tickSize);
+ }
+ else if (orientation == TICK_ORDINATE)
+ {
+ cairo_rel_move_to (cr, 0, position);
+ cairo_rel_line_to (cr, -tickSize, 0);
+ }
else
NOT_REACHED ();
+ cairo_get_current_point (cr, &x, &y);
- if ( label ) {
- char buf[10];
- va_list ap;
- va_start(ap,label);
- vsnprintf(buf,10,label,ap);
+ cairo_stroke (cr);
- if ( orientation == TICK_ABSCISSA )
- pl_alabel_r(chart->lp, 'c','t', buf);
- else if (orientation == TICK_ORDINATE )
- {
- if ( fabs(position) < DBL_EPSILON )
- pl_moverel_r(chart->lp, 0, 10);
-
- pl_alabel_r(chart->lp, 'r','c', buf);
- }
-
- va_end(ap);
- }
-
- pl_restorestate_r(chart->lp);
+ if (label != NULL)
+ {
+ va_list ap;
+ char *s;
+
+ cairo_move_to (cr, x, y);
+
+ va_start (ap, label);
+ s = xvasprintf (label, ap);
+ if (orientation == TICK_ABSCISSA)
+ chart_label (cr, 'c', 't', geom->font_size, s);
+ else if (orientation == TICK_ORDINATE)
+ {
+ if (fabs (position) < DBL_EPSILON)
+ cairo_rel_move_to (cr, 0, 10);
+ chart_label (cr, 'r', 'c', geom->font_size, s);
+ }
+ free (s);
+ va_end (ap);
+ }
}
/* Write the title on a chart*/
void
-chart_write_title(struct chart *chart, const char *title, ...)
+chart_write_title (cairo_t *cr, const struct chart_geometry *geom,
+ const char *title, ...)
{
va_list ap;
- char buf[100];
-
- if ( ! chart )
- return ;
+ char *s;
- pl_savestate_r(chart->lp);
- pl_ffontsize_r(chart->lp,chart->font_size * 1.5);
- pl_move_r(chart->lp,chart->data_left, chart->title_bottom);
+ cairo_save (cr);
+ cairo_move_to (cr, geom->data_left, geom->title_bottom);
- va_start(ap,title);
- vsnprintf(buf,100,title,ap);
- pl_alabel_r(chart->lp,0,0,buf);
- va_end(ap);
+ va_start(ap, title);
+ s = xvasprintf (title, ap);
+ chart_label (cr, 'l', 'x', geom->font_size * 1.5, s);
+ free (s);
+ va_end (ap);
- pl_restorestate_r(chart->lp);
+ cairo_restore (cr);
}
/* Set the scale for the abscissa */
void
-chart_write_xscale(struct chart *ch, double min, double max, int ticks)
+chart_write_xscale (cairo_t *cr, struct chart_geometry *geom,
+ double min, double max, int ticks)
{
double x;
const double tick_interval =
- chart_rounded_tick( (max - min) / (double) ticks);
+ chart_rounded_tick ((max - min) / (double) ticks);
- assert ( ch );
-
-
- ch->x_max = ceil( max / tick_interval ) * tick_interval ;
- ch->x_min = floor ( min / tick_interval ) * tick_interval ;
-
-
- ch->abscissa_scale = fabs(ch->data_right - ch->data_left) /
- fabs(ch->x_max - ch->x_min);
-
- for(x = ch->x_min ; x <= ch->x_max; x += tick_interval )
- {
- draw_tick (ch, TICK_ABSCISSA,
- (x - ch->x_min) * ch->abscissa_scale, "%g", x);
- }
+ geom->x_max = ceil (max / tick_interval) * tick_interval;
+ geom->x_min = floor (min / tick_interval) * tick_interval;
+ geom->abscissa_scale = fabs(geom->data_right - geom->data_left) /
+ fabs(geom->x_max - geom->x_min);
+ for (x = geom->x_min; x <= geom->x_max; x += tick_interval)
+ draw_tick (cr, geom, TICK_ABSCISSA,
+ (x - geom->x_min) * geom->abscissa_scale, "%g", x);
}
/* Set the scale for the ordinate */
void
-chart_write_yscale(struct chart *ch, double smin, double smax, int ticks)
+chart_write_yscale (cairo_t *cr, struct chart_geometry *geom,
+ double smin, double smax, int ticks)
{
double y;
const double tick_interval =
- chart_rounded_tick( (smax - smin) / (double) ticks);
-
- if ( !ch )
- return;
+ chart_rounded_tick ((smax - smin) / (double) ticks);
- ch->y_max = ceil ( smax / tick_interval ) * tick_interval ;
- ch->y_min = floor ( smin / tick_interval ) * tick_interval ;
+ geom->y_max = ceil (smax / tick_interval) * tick_interval;
+ geom->y_min = floor (smin / tick_interval) * tick_interval;
- ch->ordinate_scale =
- fabs(ch->data_top - ch->data_bottom) / fabs(ch->y_max - ch->y_min) ;
+ geom->ordinate_scale =
+ (fabs (geom->data_top - geom->data_bottom)
+ / fabs (geom->y_max - geom->y_min));
- for(y = ch->y_min ; y <= ch->y_max; y += tick_interval )
- {
- draw_tick (ch, TICK_ORDINATE,
- (y - ch->y_min) * ch->ordinate_scale, "%g", y);
- }
+ for (y = geom->y_min; y <= geom->y_max; y += tick_interval)
+ draw_tick (cr, geom, TICK_ORDINATE,
+ (y - geom->y_min) * geom->ordinate_scale, "%g", y);
}
-
/* Write the abscissa label */
void
-chart_write_xlabel(struct chart *ch, const char *label)
+chart_write_xlabel (cairo_t *cr, const struct chart_geometry *geom,
+ const char *label)
{
- if ( ! ch )
- return ;
-
- pl_savestate_r(ch->lp);
-
- pl_move_r(ch->lp,ch->data_left, ch->abscissa_top);
- pl_alabel_r(ch->lp,0,'t',label);
-
- pl_restorestate_r(ch->lp);
-
+ cairo_move_to (cr, geom->data_left, geom->abscissa_top);
+ chart_label (cr, 'l', 't', geom->font_size, label);
}
-
-
/* Write the ordinate label */
void
-chart_write_ylabel(struct chart *ch, const char *label)
+chart_write_ylabel (cairo_t *cr, const struct chart_geometry *geom,
+ const char *label)
{
- if ( ! ch )
- return ;
-
- pl_savestate_r(ch->lp);
-
- pl_move_r(ch->lp, ch->data_bottom, ch->ordinate_right);
- pl_textangle_r(ch->lp, 90);
- pl_alabel_r(ch->lp, 0, 0, label);
-
- pl_restorestate_r(ch->lp);
+ cairo_save (cr);
+ cairo_translate (cr, -geom->data_bottom, -geom->ordinate_right);
+ cairo_move_to (cr, 0, 0);
+ cairo_rotate (cr, M_PI / 2.0);
+ chart_label (cr, 'l', 'x', geom->font_size, label);
+ cairo_restore (cr);
}
void
-chart_write_legend (struct chart *ch)
+chart_write_legend (cairo_t *cr, const struct chart_geometry *geom)
{
int i;
- const int vstep = ch->font_size * 2;
+ const int vstep = geom->font_size * 2;
const int xpad = 10;
const int ypad = 10;
const int swatch = 20;
- const int legend_top = ch->data_top;
+ const int legend_top = geom->data_top;
const int legend_bottom = legend_top -
- (vstep * ch->n_datasets + 2 * ypad );
-
- if ( ! ch )
- return ;
+ (vstep * geom->n_datasets + 2 * ypad );
- pl_savestate_r (ch->lp);
+ cairo_save (cr);
- pl_box_r (ch->lp, ch->legend_left, legend_top,
- ch->legend_right - xpad, legend_bottom);
+ cairo_rectangle (cr, geom->legend_left, legend_top,
+ geom->legend_right - xpad - geom->legend_left,
+ legend_bottom - legend_top);
+ cairo_stroke (cr);
- for (i = 0 ; i < ch->n_datasets ; ++i )
+ for (i = 0 ; i < geom->n_datasets ; ++i )
{
- const int ypos = vstep * (i + 1);
- const int xpos = ch->legend_left + xpad;
- pl_move_r (ch->lp, xpos, legend_top - ypos);
-
- pl_savestate_r(ch->lp);
- pl_fillcolorname_r (ch->lp, data_colour [ i % N_CHART_COLOURS]);
-
- pl_pentype_r (ch->lp, 1);
- pl_filltype_r (ch->lp, 1);
- pl_boxrel_r (ch->lp, 0, 0, swatch, swatch);
-
-
- pl_moverel_r (ch->lp, swatch, 0);
- pl_alabel_r (ch->lp, 0, 0, ch->dataset[i]);
-
- pl_restorestate_r (ch->lp);
+ const int ypos = legend_top - vstep * (i + 1);
+ const int xpos = geom->legend_left + xpad;
+ const struct chart_colour *colour;
+
+ cairo_move_to (cr, xpos, ypos);
+
+ cairo_save (cr);
+ colour = &data_colour [ i % N_CHART_COLOURS];
+ cairo_set_source_rgb (cr,
+ colour->red / 255.0,
+ colour->green / 255.0,
+ colour->blue / 255.0);
+ cairo_rectangle (cr, xpos, ypos, swatch, swatch);
+ cairo_fill_preserve (cr);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ cairo_move_to (cr, xpos + swatch * 1.5, ypos);
+ chart_label (cr, 'l', 'x', geom->font_size, geom->dataset[i]);
}
- pl_restorestate_r (ch->lp);
+ cairo_restore (cr);
}
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef PLOT_CHART_H
+#define PLOT_CHART_H
+
+#include <cairo/cairo.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math/chart-geometry.h>
#include <output/chart.h>
+#include <output/chart-provider.h>
#include <libpspp/compiler.h>
#include <libpspp/str.h>
#include <output/manager.h>
#include <output/output.h>
-#include "xalloc.h"
-
-#ifndef PLOT_CHART_H
-#define PLOT_CHART_H
-
#define N_CHART_COLOURS 9
-extern const char *const data_colour[];
+extern const struct chart_colour data_colour[];
enum tick_orientation
{
TICK_ORDINATE
};
+struct chart_geometry;
+
+
+enum marker_type
+ {
+ MARKER_CIRCLE, /* Hollow circle. */
+ MARKER_ASTERISK, /* Asterisk (*). */
+ MARKER_SQUARE /* Hollow square. */
+ };
+
+void chart_draw_marker (cairo_t *, double x, double y, enum marker_type,
+ double size);
+
+void chart_label (cairo_t *, int horz_justify, int vert_justify,
+ double font_size, const char *);
/* Draw a tick mark at position
If label is non zero, then print it at the tick mark
*/
-void draw_tick(struct chart *chart,
+void draw_tick(cairo_t *, const struct chart_geometry *,
enum tick_orientation orientation,
double position,
const char *label, ...)
- PRINTF_FORMAT (4, 5);
+ PRINTF_FORMAT (5, 6);
/* Write the title on a chart*/
-void chart_write_title(struct chart *chart, const char *title, ...)
- PRINTF_FORMAT (2, 3);
+void chart_write_title(cairo_t *, const struct chart_geometry *,
+ const char *title, ...)
+ PRINTF_FORMAT (3, 4);
/* Set the scale for the abscissa */
-void chart_write_xscale(struct chart *ch, double min, double max, int ticks);
+void chart_write_xscale(cairo_t *, struct chart_geometry *,
+ double min, double max, int ticks);
/* Set the scale for the ordinate */
-void chart_write_yscale(struct chart *ch, double smin, double smax, int ticks);
+void chart_write_yscale(cairo_t *, struct chart_geometry *,
+ double smin, double smax, int ticks);
-void chart_write_xlabel(struct chart *ch, const char *label) ;
+void chart_write_xlabel(cairo_t *, const struct chart_geometry *,
+ const char *label) ;
/* Write the ordinate label */
-void chart_write_ylabel(struct chart *ch, const char *label);
+void chart_write_ylabel(cairo_t *, const struct chart_geometry *,
+ const char *label);
-void chart_write_legend (struct chart *ch);
+void chart_write_legend (cairo_t *, const struct chart_geometry *);
#endif
#include <config.h>
#include <stdio.h>
-#include <plot.h>
#include <math.h>
#include <gsl/gsl_histogram.h>
#include <gsl/gsl_randist.h>
#include <output/charts/plot-hist.h>
#include <output/charts/plot-chart.h>
+#include <output/chart-provider.h>
#include <data/variable.h>
+#include <libpspp/cast.h>
#include <libpspp/hash.h>
#include <output/chart.h>
#include <math/histogram.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
+static const struct chart_class histogram_chart_class;
+
/* Write the legend of the chart */
static void
-histogram_write_legend (struct chart *ch, double n, double mean, double stddev)
+histogram_write_legend (cairo_t *cr, const struct chart_geometry *geom,
+ double n, double mean, double stddev)
{
- char buf[100];
-
- if (!ch)
- return ;
-
- pl_savestate_r (ch->lp);
+ double y = geom->data_bottom;
+ cairo_save (cr);
- sprintf (buf, "N = %.2f", n);
- pl_move_r (ch->lp, ch->legend_left, ch->data_bottom);
- pl_alabel_r (ch->lp, 0, 'b', buf);
+ if (n != SYSMIS)
+ {
+ char *buf = xasprintf ("N = %.2f", n);
+ cairo_move_to (cr, geom->legend_left, y);
+ chart_label (cr, 'l', 'b', geom->font_size, buf);
+ y += geom->font_size * 1.5;
+ free (buf);
+ }
- sprintf (buf, "Mean = %.1f", mean);
- pl_fmove_r (ch->lp,ch->legend_left,ch->data_bottom + ch->font_size * 1.5);
- pl_alabel_r (ch->lp, 0, 'b', buf);
+ if (mean != SYSMIS)
+ {
+ char *buf = xasprintf ("Mean = %.1f", mean);
+ cairo_move_to (cr,geom->legend_left, y);
+ chart_label (cr, 'l', 'b', geom->font_size, buf);
+ y += geom->font_size * 1.5;
+ free (buf);
+ }
- sprintf (buf, "Std. Dev = %.2f", stddev);
- pl_fmove_r (ch->lp, ch->legend_left, ch->data_bottom + ch->font_size * 1.5 * 2);
- pl_alabel_r (ch->lp, 0, 'b', buf);
+ if (stddev != SYSMIS)
+ {
+ char *buf = xasprintf ("Std. Dev = %.2f", stddev);
+ cairo_move_to (cr, geom->legend_left, y);
+ chart_label (cr, 'l', 'b', geom->font_size, buf);
+ free (buf);
+ }
- pl_restorestate_r (ch->lp);
+ cairo_restore (cr);
}
-static void hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar);
-
-
static void
-hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar)
+hist_draw_bar (cairo_t *cr, const struct chart_geometry *geom,
+ const gsl_histogram *h, int bar)
{
- if (!ch)
- return ;
-
- {
- double upper;
- double lower;
- double height;
-
- const size_t bins = gsl_histogram_bins (hist->gsl_hist);
- const double x_pos = (ch->data_right - ch->data_left) * bar / (double) bins ;
- const double width = (ch->data_right - ch->data_left) / (double) bins ;
-
- assert ( 0 == gsl_histogram_get_range (hist->gsl_hist, bar, &lower, &upper));
-
- assert ( upper >= lower);
-
- height = gsl_histogram_get (hist->gsl_hist, bar) *
- (ch->data_top - ch->data_bottom) / gsl_histogram_max_val (hist->gsl_hist);
-
- pl_savestate_r (ch->lp);
- pl_move_r (ch->lp,ch->data_left, ch->data_bottom);
- pl_fillcolorname_r (ch->lp, ch->fill_colour);
- pl_filltype_r (ch->lp,1);
-
-
- pl_fboxrel_r (ch->lp,
- x_pos, 0,
- x_pos + width, height);
-
- pl_restorestate_r (ch->lp);
-
- draw_tick (ch, TICK_ABSCISSA,
- x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
- }
+ double upper;
+ double lower;
+ double height;
+
+ const size_t bins = gsl_histogram_bins (h);
+ const double x_pos = (geom->data_right - geom->data_left) * bar / (double) bins ;
+ const double width = (geom->data_right - geom->data_left) / (double) bins ;
+
+ assert ( 0 == gsl_histogram_get_range (h, bar, &lower, &upper));
+
+ assert ( upper >= lower);
+
+ height = gsl_histogram_get (h, bar) *
+ (geom->data_top - geom->data_bottom) / gsl_histogram_max_val (h);
+
+ cairo_rectangle (cr, geom->data_left + x_pos, geom->data_bottom,
+ width, height);
+ cairo_save (cr);
+ cairo_set_source_rgb (cr,
+ geom->fill_colour.red / 255.0,
+ geom->fill_colour.green / 255.0,
+ geom->fill_colour.blue / 255.0);
+ cairo_fill_preserve (cr);
+ cairo_restore (cr);
+ cairo_stroke (cr);
+
+ draw_tick (cr, geom, TICK_ABSCISSA,
+ x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
}
-
-
-void
-histogram_plot (const struct histogram *hist,
- const char *label,
- const struct moments1 *m)
+struct histogram_chart
+ {
+ struct chart chart;
+ gsl_histogram *gsl_hist;
+ char *label;
+ double n;
+ double mean;
+ double stddev;
+ bool show_normal;
+ };
+
+/* Plots a histogram of the data in HIST with the given LABEL.
+ Labels the histogram with each of N, MEAN, and STDDEV that is
+ not SYSMIS. If all three are not SYSMIS and SHOW_NORMAL is
+ true, also draws a normal curve on the histogram. */
+struct chart *
+histogram_chart_create (const struct histogram *hist, const char *label,
+ double n, double mean, double stddev,
+ bool show_normal)
{
- double mean, var, n;
-
- moments1_calculate (m, &n, &mean, &var, NULL, NULL);
-
- histogram_plot_n (hist, label, n, mean, sqrt(var), m);
+ struct histogram_chart *h;
+
+ h = xmalloc (sizeof *h);
+ chart_init (&h->chart, &histogram_chart_class);
+ h->gsl_hist = hist->gsl_hist ? gsl_histogram_clone (hist->gsl_hist) : NULL;
+ h->label = xstrdup (label);
+ h->n = n;
+ h->mean = mean;
+ h->stddev = stddev;
+ h->show_normal = show_normal;
+ return &h->chart;
}
-
-/* This function is deprecated. Don't use it in new code */
-void
-histogram_plot_n (const struct histogram *hist,
- const char *label,
- double n, double mean, double stddev,
- bool show_normal)
+static void
+histogram_chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
{
+ struct histogram_chart *h = UP_CAST (chart, struct histogram_chart, chart);
int i;
int bins;
- struct chart *ch = chart_create ();
-
- chart_write_title (ch, _("HISTOGRAM"));
+ chart_write_title (cr, geom, _("HISTOGRAM"));
- chart_write_ylabel (ch, _("Frequency"));
- chart_write_xlabel (ch, label);
+ chart_write_ylabel (cr, geom, _("Frequency"));
+ chart_write_xlabel (cr, geom, h->label);
- if ( ! hist ) /* If this happens, probably all values are SYSMIS */
+ if (h->gsl_hist == NULL)
{
- chart_submit (ch);
+ /* Probably all values are SYSMIS. */
return;
}
- else
- {
- bins = gsl_histogram_bins (hist->gsl_hist);
- }
- chart_write_yscale (ch, 0, gsl_histogram_max_val (hist->gsl_hist), 5);
+ bins = gsl_histogram_bins (h->gsl_hist);
+
+ chart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist), 5);
- for ( i = 0 ; i < bins ; ++i )
- hist_draw_bar (ch, hist, i);
+ for (i = 0; i < bins; i++)
+ hist_draw_bar (cr, geom, h->gsl_hist, i);
- histogram_write_legend (ch, n, mean, stddev);
+ histogram_write_legend (cr, geom, h->n, h->mean, h->stddev);
- if (show_normal)
+ if (h->show_normal
+ && h->n != SYSMIS && h->mean != SYSMIS && h->stddev != SYSMIS)
{
/* Draw the normal curve */
+ double d;
+ double x_min, x_max, not_used;
+ double abscissa_scale;
+ double ordinate_scale;
+ double range;
- double d ;
- double x_min, x_max, not_used ;
- double abscissa_scale ;
- double ordinate_scale ;
- double range ;
-
- gsl_histogram_get_range (hist->gsl_hist, 0, &x_min, ¬_used);
+ gsl_histogram_get_range (h->gsl_hist, 0, &x_min, ¬_used);
range = not_used - x_min;
- gsl_histogram_get_range (hist->gsl_hist, bins - 1, ¬_used, &x_max);
+ gsl_histogram_get_range (h->gsl_hist, bins - 1, ¬_used, &x_max);
- abscissa_scale = (ch->data_right - ch->data_left) / (x_max - x_min);
- ordinate_scale = (ch->data_top - ch->data_bottom) /
- gsl_histogram_max_val (hist->gsl_hist) ;
+ abscissa_scale = (geom->data_right - geom->data_left) / (x_max - x_min);
+ ordinate_scale = (geom->data_top - geom->data_bottom) /
+ gsl_histogram_max_val (h->gsl_hist);
- pl_move_r (ch->lp, ch->data_left, ch->data_bottom);
- for ( d = ch->data_left;
- d <= ch->data_right ;
- d += (ch->data_right - ch->data_left) / 100.0)
+ cairo_move_to (cr, geom->data_left, geom->data_bottom);
+ for (d = geom->data_left;
+ d <= geom->data_right;
+ d += (geom->data_right - geom->data_left) / 100.0)
{
- const double x = (d - ch->data_left) / abscissa_scale + x_min ;
- const double y = n * range *
- gsl_ran_gaussian_pdf (x - mean, stddev);
+ const double x = (d - geom->data_left) / abscissa_scale + x_min;
+ const double y = h->n * range *
+ gsl_ran_gaussian_pdf (x - h->mean, h->stddev);
- pl_fcont_r (ch->lp, d, ch->data_bottom + y * ordinate_scale);
+ cairo_line_to (cr, d, geom->data_bottom + y * ordinate_scale);
}
- pl_endpath_r (ch->lp);
+ cairo_stroke (cr);
}
-
- chart_submit (ch);
}
+static void
+histogram_chart_destroy (struct chart *chart)
+{
+ struct histogram_chart *h = UP_CAST (chart, struct histogram_chart, chart);
+ if (h->gsl_hist != NULL)
+ gsl_histogram_free (h->gsl_hist);
+ free (h->label);
+ free (h);
+}
+
+static const struct chart_class histogram_chart_class =
+ {
+ histogram_chart_draw,
+ histogram_chart_destroy
+ };
/* PSPP - a program for statistical analysis.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#ifndef PLOT_HIST_H
-#define PLOT_HIST_H
+#ifndef OUTPUT_PLOT_HIST_H
+#define OUTPUT_PLOT_HIST_H
#include <stdbool.h>
struct chart;
-struct moments1;
struct histogram;
-/* Plot M onto histogram HIST and label it with LABEL */
-void histogram_plot (const struct histogram *hist,
- const char *label, const struct moments1 *m);
-
-
-/* A wrapper aroud histogram_plot.
- Don't use this function. It's legacy only */
-void histogram_plot_n (const struct histogram *hist,
- const char *label,
- double n, double mean, double var,
- bool show_normal);
-
-
-#endif
+/* Creates and returns a new chart that depicts a histogram of
+ the data in HIST with the given LABEL. Labels the histogram
+ with each of N, MEAN, and STDDEV that is not SYSMIS. If all
+ three are not SYSMIS and SHOW_NORMAL is true, also draws a
+ normal curve on the histogram. */
+struct chart *histogram_chart_create (const struct histogram *hist,
+ const char *label,
+ double n, double mean, double stddev,
+ bool show_normal);
+
+#endif /* output/plot-hist.h */
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <output/charts/roc-chart.h>
+
+#include <output/chart-provider.h>
+#include <output/charts/cartesian.h>
+#include <output/charts/plot-chart.h>
+#include <data/casereader.h>
+#include <language/stats/roc.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct roc_var
+ {
+ char *name;
+ struct casereader *cutpoint_reader;
+ };
+
+struct roc_chart
+ {
+ struct chart chart;
+ bool reference;
+ struct roc_var *vars;
+ size_t n_vars;
+ size_t allocated_vars;
+ };
+
+static const struct chart_class roc_chart_class;
+
+struct roc_chart *
+roc_chart_create (bool reference)
+{
+ struct roc_chart *rc = xmalloc (sizeof *rc);
+ chart_init (&rc->chart, &roc_chart_class);
+ rc->reference = reference;
+ rc->vars = NULL;
+ rc->n_vars = 0;
+ rc->allocated_vars = 0;
+ return rc;
+}
+
+void
+roc_chart_add_var (struct roc_chart *rc, const char *var_name,
+ const struct casereader *cutpoint_reader)
+{
+ struct roc_var *rv;
+
+ if (rc->n_vars >= rc->allocated_vars)
+ rc->vars = x2nrealloc (rc->vars, &rc->allocated_vars, sizeof *rc->vars);
+
+ rv = &rc->vars[rc->n_vars++];
+ rv->name = xstrdup (var_name);
+ rv->cutpoint_reader = casereader_clone (cutpoint_reader);
+}
+
+struct chart *
+roc_chart_get_chart (struct roc_chart *rc)
+{
+ return &rc->chart;
+}
+
+static void
+roc_chart_draw (const struct chart *chart, cairo_t *cr,
+ struct chart_geometry *geom)
+{
+ const struct roc_chart *rc = UP_CAST (chart, struct roc_chart, chart);
+ size_t i;
+
+ chart_write_title (cr, geom, _("ROC Curve"));
+ chart_write_xlabel (cr, geom, _("1 - Specificity"));
+ chart_write_ylabel (cr, geom, _("Sensitivity"));
+
+ chart_write_xscale (cr, geom, 0, 1, 5);
+ chart_write_yscale (cr, geom, 0, 1, 5);
+
+ if ( rc->reference )
+ {
+ chart_line (cr, geom, 1.0, 0,
+ 0.0, 1.0,
+ CHART_DIM_X);
+ }
+
+ for (i = 0; i < rc->n_vars; ++i)
+ {
+ const struct roc_var *rv = &rc->vars[i];
+ struct casereader *r = casereader_clone (rv->cutpoint_reader);
+ struct ccase *cc;
+
+ chart_vector_start (cr, geom, rv->name);
+ for (; (cc = casereader_read (r)) != NULL; case_unref (cc))
+ {
+ double se = case_data_idx (cc, ROC_TP)->f;
+ double sp = case_data_idx (cc, ROC_TN)->f;
+
+ se /= case_data_idx (cc, ROC_FN)->f + case_data_idx (cc, ROC_TP)->f ;
+ sp /= case_data_idx (cc, ROC_TN)->f + case_data_idx (cc, ROC_FP)->f ;
+
+ chart_vector (cr, geom, 1 - sp, se);
+ }
+ chart_vector_end (cr, geom);
+ casereader_destroy (r);
+ }
+
+ chart_write_legend (cr, geom);
+}
+
+static void
+roc_chart_destroy (struct chart *chart)
+{
+ struct roc_chart *rc = UP_CAST (chart, struct roc_chart, chart);
+ size_t i;
+
+ for (i = 0; i < rc->n_vars; i++)
+ {
+ struct roc_var *rv = &rc->vars[i];
+ free (rv->name);
+ casereader_destroy (rv->cutpoint_reader);
+ }
+ free (rc->vars);
+ free (rc);
+}
+
+static const struct chart_class roc_chart_class =
+ {
+ roc_chart_draw,
+ roc_chart_destroy
+ };
+
+
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef OUTPUT_CHARTS_ROC_CHART_H
+#define OUTPUT_CHARTS_ROC_CHART_H 1
+
+#include <stdbool.h>
+
+struct casereader;
+
+struct roc_chart *roc_chart_create (bool reference);
+void roc_chart_add_var (struct roc_chart *, const char *var_name,
+ const struct casereader *cutpoint_reader);
+struct chart *roc_chart_get_chart (struct roc_chart *);
+
+#endif /* output/charts/roc-chart.h */
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
#include <data/file-name.h>
-#include "error.h"
-#include "output.h"
-#include "manager.h"
-#include "table.h"
+#include <output/chart-provider.h>
+#include <output/output.h>
+#include <output/manager.h>
+#include <output/table.h>
#include <libpspp/version.h>
+#include "error.h"
#include "xalloc.h"
#include "gettext.h"
static void escape_string (FILE *file,
const char *text, size_t length,
const char *space);
-static bool handle_option (struct outp_driver *this,
+static bool handle_option (void *this,
const char *key, const struct string *val);
static void print_title_tag (FILE *file, const char *name,
const char *content);
static bool
-html_open_driver (struct outp_driver *this, struct substring options)
+html_open_driver (const char *name, int types, struct substring options)
{
+ struct outp_driver *this;
struct html_driver_ext *x;
+ this = outp_allocate_driver (&html_class, name, types);
this->ext = x = xmalloc (sizeof *x);
x->file_name = xstrdup ("pspp.html");
x->chart_file_name = xstrdup ("pspp-#.png");
x->file = NULL;
- x->chart_cnt = 0;
+ x->chart_cnt = 1;
- outp_parse_options (options, handle_option, this);
+ outp_parse_options (name, options, handle_option, this);
x->file = fn_open (x->file_name, "w");
if (x->file == NULL)
print_title_tag (x->file, "H1", outp_title);
print_title_tag (x->file, "H2", outp_subtitle);
+ outp_register_driver (this);
return true;
error:
this->class->close_driver (this);
+ outp_free_driver (this);
return false;
}
return ok;
}
-/* Link the image contained in FILE_NAME to the
- HTML stream in FILE. */
-static void
-link_image (FILE *file, char *file_name)
-{
- fprintf (file, "<IMG SRC=\"%s\"/>", file_name);
- }
-
/* Generic option types. */
enum
{
};
static bool
-handle_option (struct outp_driver *this,
- const char *key, const struct string *val)
+handle_option (void *this_, const char *key, const struct string *val)
{
+ struct outp_driver *this = this_;
struct html_driver_ext *x = this->ext;
int subcat;
static void output_tab_table (struct outp_driver *, struct tab_table *);
+static void
+html_output_chart (struct outp_driver *this, const struct chart *chart)
+{
+ struct html_driver_ext *x = this->ext;
+ char *file_name;
+
+ file_name = chart_draw_png (chart, x->chart_file_name, x->chart_cnt++);
+ fprintf (x->file, "<IMG SRC=\"%s\"/>", file_name);
+ free (file_name);
+}
+
static void
html_submit (struct outp_driver *this, struct som_entity *s)
{
extern struct som_table_class tab_table_class;
- struct html_driver_ext *x = this->ext;
assert (s->class == &tab_table_class ) ;
case SOM_TABLE:
output_tab_table ( this, (struct tab_table *) s->ext);
break;
- case SOM_CHART:
- link_image (x->file, ((struct chart *)s->ext)->file_name);
- break;
default:
NOT_REACHED ();
}
{
struct html_driver_ext *x = this->ext;
- if (t->nr == 1 && t->nc == 1)
+ if (tab_nr (t) == 1 && tab_nc (t) == 1)
{
fputs ("<P>", x->file);
html_put_cell_contents (this, t->ct[0], *t->cc);
int r;
unsigned char *ct = t->ct;
- for (r = 0; r < t->nr; r++)
+ for (r = 0; r < tab_nr (t); r++)
{
int c;
fputs (" <TR>\n", x->file);
- for (c = 0; c < t->nc; c++, ct++)
+ for (c = 0; c < tab_nc (t); c++, ct++)
{
struct substring *cc;
const char *tag;
struct tab_joined_cell *j = NULL;
- cc = t->cc + c + r * t->nc;
+ cc = t->cc + c + r * tab_nc (t);
if (*ct & TAB_JOIN)
{
j = (struct tab_joined_cell *) ss_data (*cc);
}
/* Output <TD> or <TH> tag. */
- tag = (r < t->t || r >= t->nr - t->b
- || c < t->l || c >= t->nc - t->r) ? "TH" : "TD";
+ tag = (r < tab_t (t) || r >= tab_nr (t) - tab_b (t)
+ || c < tab_l (t) || c >= tab_nc (t) - tab_r (t)) ? "TH" : "TD";
fprintf (x->file, " <%s ALIGN=%s",
tag,
(*ct & TAB_ALIGN_MASK) == TAB_LEFT ? "LEFT"
fputs ("</TABLE>\n\n", x->file);
}
-static void
-html_initialise_chart (struct outp_driver *this UNUSED, struct chart *ch)
-{
- struct html_driver_ext *x = this->ext;
- chart_init_separate (ch, "png", x->chart_file_name, ++x->chart_cnt);
-}
-
-static void
-html_finalise_chart(struct outp_driver *d UNUSED, struct chart *ch)
-{
- chart_finalise_separate (ch);
-}
-
/* HTML driver class. */
NULL,
NULL,
+ html_output_chart,
+
html_submit,
NULL,
NULL,
NULL,
- html_initialise_chart,
- html_finalise_chart
};
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include "manager.h"
+
+#include <output/manager.h>
+
#include <stdio.h>
#include <stdlib.h>
+
#include <libpspp/assertion.h>
-#include "output.h"
+#include <output/output.h>
+
+#include "gl/xalloc.h"
/* Table. */
-int table_num = 1;
-int subtable_num;
+static int table_num = 1;
+static int subtable_num;
+
+/* Name of PSPP's current command, or NULL if outside a command. */
+static char *command_name;
\f
+struct som_entity *
+som_entity_clone (struct som_entity *entity)
+{
+ struct som_entity *copy = xmemdup (entity, sizeof *entity);
+ copy->command_name = xstrdup (entity->command_name);
+ return copy;
+}
+
+void
+som_entity_destroy (struct som_entity *entity)
+{
+ if (entity != NULL)
+ {
+ free (entity->command_name);
+ free (entity);
+ }
+}
+
/* Increments table_num so different procedures' output can be
distinguished. */
void
}
}
+/* Sets COMMAND_NAME as the name of the current command,
+ for embedding in output. */
+void
+som_set_command_name (const char *command_name_)
+{
+ free (command_name);
+ command_name = command_name_ ? xstrdup (command_name_) : NULL;
+}
+
/* Ejects the paper for all active devices. */
void
som_eject_page (void)
d->cp_y += d->font_height;
}
\f
-/* Driver. */
-static struct outp_driver *d = 0;
-
-/* Table. */
-static struct som_entity *t = 0;
-
-/* Flags. */
-static unsigned flags;
-
-/* Number of columns, rows. */
-static int nc, nr;
-
-/* Number of columns or rows in left, right, top, bottom headers. */
-static int hl, hr, ht, hb;
-
-/* Column style. */
-static int cs;
-
-/* Table height, width. */
-static int th, tw;
-
-static void render_columns (void);
-static void render_simple (void);
-static void render_segments (void);
+static void render_columns (void *r, struct outp_driver *, struct som_entity *,
+ int tw, int th,
+ int hl, int hr, int ht, int hb);
+static void render_simple (void *r, struct outp_driver *, struct som_entity *,
+ int tw, int th,
+ int hl, int hr, int ht, int hb);
+static void render_segments (void *r, struct outp_driver *,
+ struct som_entity *,
+ int tw, int th,
+ int hl, int hr, int ht, int hb);
static void output_entity (struct outp_driver *, struct som_entity *);
void
som_submit (struct som_entity *t)
{
+ struct outp_driver *d;
+ unsigned int flags;
+
#if DEBUGGING
static int entry;
assert (entry++ == 0);
#endif
- if ( t->type == SOM_TABLE)
- {
- t->class->table (t);
- t->class->flags (&flags);
- t->class->count (&nc, &nr);
- t->class->headers (&hl, &hr, &ht, &hb);
+ t->class->flags (t, &flags);
+ if (!(flags & SOMF_NO_TITLE))
+ subtable_num++;
+ t->table_num = table_num;
+ t->subtable_num = subtable_num;
+ t->command_name = command_name ? xstrdup (command_name) : NULL;
+ if (t->type == SOM_TABLE)
+ {
+ int hl, hr, ht, hb;
+ int nc, nr;
-#if DEBUGGING
+ t->class->count (t, &nc, &nr);
+ t->class->headers (t, &hl, &hr, &ht, &hb);
if (hl + hr > nc || ht + hb > nr)
{
- printf ("headers: (l,r)=(%d,%d), (t,b)=(%d,%d) in table size (%d,%d)\n",
- hl, hr, ht, hb, nc, nr);
+ fprintf (stderr, "headers: (l,r)=(%d,%d), (t,b)=(%d,%d) "
+ "in table size (%d,%d)\n",
+ hl, hr, ht, hb, nc, nr);
NOT_REACHED ();
}
else if (hl + hr == nc)
- printf ("warning: headers (l,r)=(%d,%d) in table width %d\n", hl, hr, nc);
+ fprintf (stderr, "warning: headers (l,r)=(%d,%d) in table width %d\n",
+ hl, hr, nc);
else if (ht + hb == nr)
- printf ("warning: headers (t,b)=(%d,%d) in table height %d\n", ht, hb, nr);
-#endif
+ fprintf (stderr, "warning: headers (t,b)=(%d,%d) in table height %d\n",
+ ht, hb, nr);
+ }
+
+ for (d = outp_drivers (NULL); d; d = outp_drivers (d))
+ output_entity (d, t);
- t->class->columns (&cs);
+#if DEBUGGING
+ assert (--entry == 0);
+#endif
+}
- if (!(flags & SOMF_NO_TITLE))
- subtable_num++;
+static bool
+check_fits_width (struct som_entity *t, const struct outp_driver *d, void *r)
+{
+ int hl, hr, ht, hb;
+ int nc, nr;
+ int i;
+ t->class->headers (t, &hl, &hr, &ht, &hb);
+ t->class->count (t, &nc, &nr);
+ for (i = hl; i < nc - hr; i++)
+ {
+ int end, actual;
+ t->class->cumulate (r, SOM_COLUMNS, i, &end, d->width, &actual);
+ if (end == i)
+ return false;
}
- {
- struct outp_driver *d;
+ return true;
+}
- for (d = outp_drivers (NULL); d; d = outp_drivers (d))
- output_entity (d, t);
+static bool
+check_fits_length (struct som_entity *t, const struct outp_driver *d, void *r)
+{
+ int hl, hr, ht, hb;
+ int nc, nr;
+ int i;
- }
+ t->class->headers (t, &hl, &hr, &ht, &hb);
+ t->class->count (t, &nc, &nr);
+ for (i = ht; i < nr - hb; i++)
+ {
+ int end, actual;
+ t->class->cumulate (r, SOM_ROWS, i, &end, d->length, &actual);
+ if (end == i)
+ return false;
+ }
-#if DEBUGGING
- assert (--entry == 0);
-#endif
+ return true;
}
-/* Output entity ENTITY to driver DRIVER. */
+/* Output entity T to driver D. */
static void
-output_entity (struct outp_driver *driver, struct som_entity *entity)
+output_entity (struct outp_driver *d, struct som_entity *t)
{
bool fits_width, fits_length;
- d = driver;
+ unsigned int flags;
+ int hl, hr, ht, hb;
+ int tw, th;
+ int nc, nr;
+ int cs;
+ void *r;
outp_open_page (d);
- if (d->class->special || entity->type == SOM_CHART)
+ if (d->class->special)
{
- driver->class->submit (d, entity);
+ d->class->submit (d, t);
return;
}
- t = entity;
+ t->class->headers (t, &hl, &hr, &ht, &hb);
+ t->class->count (t, &nc, &nr);
+ t->class->columns (t, &cs);
+ t->class->flags (t, &flags);
+
+ r = t->class->render_init (t, d, hl, hr, ht, hb);
- t->class->driver (d);
- t->class->area (&tw, &th);
- fits_width = t->class->fits_width (d->width);
- fits_length = t->class->fits_length (d->length);
+ fits_width = check_fits_width (t, d, r);
+ fits_length = check_fits_length (t, d, r);
if (!fits_width || !fits_length)
{
- int tl, tr, tt, tb;
- tl = fits_width ? hl : 0;
- tr = fits_width ? hr : 0;
- tt = fits_length ? ht : 0;
- tb = fits_length ? hb : 0;
- t->class->set_headers (tl, tr, tt, tb);
- t->class->driver (d);
- t->class->area (&tw, &th);
+ t->class->render_free (r);
+
+ if (!fits_width)
+ hl = hr = 0;
+ if (!fits_length)
+ ht = hb = 0;
+
+ r = t->class->render_init (t, d, hl, hr, ht, hb);
}
+ t->class->area (r, &tw, &th);
if (!(flags & SOMF_NO_SPACING) && d->cp_y != 0)
d->cp_y += d->font_height;
if (cs != SOM_COL_NONE
&& 2 * (tw + d->prop_em_width) <= d->width
&& nr - (ht + hb) > 5)
- render_columns ();
+ render_columns (r, d, t, tw, th, hl, hr, ht, hb);
else if (tw < d->width && th + d->cp_y < d->length)
- render_simple ();
+ render_simple (r, d, t, tw, th, hl, hr, ht, hb);
else
- render_segments ();
+ render_segments (r, d, t, tw, th, hl, hr, ht, hb);
- t->class->set_headers (hl, hr, ht, hb);
+ t->class->render_free (r);
}
/* Render the table into multiple columns. */
static void
-render_columns (void)
+render_columns (void *r, struct outp_driver *d, struct som_entity *t,
+ int tw, int th UNUSED,
+ int hl UNUSED, int hr UNUSED, int ht, int hb)
{
int y0, y1;
int max_len = 0;
int index = 0;
+ int nc, nr;
+ int cs;
+
+ t->class->count (t, &nc, &nr);
+ t->class->columns (t, &cs);
assert (cs == SOM_COL_DOWN);
assert (d->cp_x == 0);
{
int len;
- t->class->cumulate (SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
+ t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
if (y0 == y1)
{
if (len > max_len)
max_len = len;
- t->class->title (index++, 0);
- t->class->render (0, y0, nc, y1);
+ t->class->title (r, index++, 0, t->table_num, t->subtable_num,
+ t->command_name);
+ t->class->render (r, 0, y0, nc, y1);
d->cp_x += tw + 2 * d->prop_em_width;
if (d->cp_x + tw > d->width)
/* Render the table by itself on the current page. */
static void
-render_simple (void)
+render_simple (void *r, struct outp_driver *d, struct som_entity *t,
+ int tw, int th,
+ int hl, int hr, int ht, int hb)
{
+ int nc, nr;
+
+ t->class->count (t, &nc, &nr);
+
assert (d->cp_x == 0);
assert (tw < d->width && th + d->cp_y < d->length);
- t->class->title (0, 0);
- t->class->render (hl, ht, nc - hr, nr - hb);
+ t->class->title (r, 0, 0, t->table_num, t->subtable_num, t->command_name);
+ t->class->render (r, hl, ht, nc - hr, nr - hb);
d->cp_y += th;
}
/* General table breaking routine. */
static void
-render_segments (void)
+render_segments (void *r, struct outp_driver *d, struct som_entity *t,
+ int tw UNUSED, int th UNUSED,
+ int hl, int hr, int ht, int hb)
{
int count = 0;
int x_index;
int x0, x1;
+ int nc, nr;
+
assert (d->cp_x == 0);
+ t->class->count (t, &nc, &nr);
for (x_index = 0, x0 = hl; x0 < nc - hr; x0 = x1, x_index++)
{
int y_index;
int y0, y1;
- t->class->cumulate (SOM_COLUMNS, x0, &x1, d->width, NULL);
+ t->class->cumulate (r, SOM_COLUMNS, x0, &x1, d->width, NULL);
if (x_index == 0 && x1 != nc - hr)
x_index++;
if (count++ != 0 && d->cp_y != 0)
d->cp_y += d->font_height;
- t->class->cumulate (SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
+ t->class->cumulate (r, SOM_ROWS, y0, &y1, d->length - d->cp_y, &len);
if (y_index == 0 && y1 != nr - hb)
y_index++;
}
else
{
- t->class->title (x_index ? x_index : y_index,
- x_index ? y_index : 0);
- t->class->render (x0, y0, x1, y1);
+ t->class->title (r, x_index ? x_index : y_index,
+ x_index ? y_index : 0,
+ t->table_num, t->subtable_num, t->command_name);
+ t->class->render (r, x0, y0, x1, y1);
d->cp_y += len;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
enum som_type
{
- SOM_TABLE,
- SOM_CHART
+ SOM_TABLE
} ;
/* Entity (Table or Chart) . */
{
const struct som_table_class *class; /* Table class. */
enum som_type type; /* Table or Chart */
- void *ext; /* Owned by */
+ void *ext; /* Owned by table or chart class. */
+ int table_num; /* Table number. */
+ int subtable_num; /* Sub-table number. */
+ char *command_name; /* Command that yielded this output. */
};
+struct som_entity *som_entity_clone (struct som_entity *);
+void som_entity_destroy (struct som_entity *);
+
/* Group styles. */
enum
{
/* Cumulation types. */
enum
{
- SOM_ROWS, SOM_ROW = SOM_ROWS, /* Rows. */
- SOM_COLUMNS, SOM_COLUMN = SOM_COLUMNS /* Columns. */
+ SOM_ROWS, /* Rows. */
+ SOM_COLUMNS /* Columns. */
};
/* Flags. */
struct outp_driver;
struct som_table_class
{
- /* Set table, driver. */
- void (*table) (struct som_entity *);
- void (*driver) (struct outp_driver *);
-
- /* Query columns and rows. */
- void (*count) (int *n_columns, int *n_rows);
- void (*area) (int *horiz, int *vert);
- void (*width) (int *columns);
- void (*height) (int *rows);
- void (*columns) (int *style);
- int (*breakable) (int row); /* ? */
- void (*headers) (int *l, int *r, int *t, int *b);
- void (*join) (int *(column[2]), int *(row[2])); /* ? */
- void (*cumulate) (int cumtype, int start, int *end, int max, int *actual);
- void (*flags) (unsigned *);
- bool (*fits_width) (int width);
- bool (*fits_length) (int length);
-
- /* Set columns and rows. */
- void (*set_width) (int column, int width); /* ? */
- void (*set_height) (int row, int height); /* ? */
- void (*set_headers) (int l, int r, int t, int b);
-
- /* Rendering. */
- void (*title) (int x, int y);
- void (*render) (int x1, int y1, int x2, int y2);
+ /* Operations on tables. */
+ void (*count) (struct som_entity *, int *n_columns, int *n_rows);
+ void (*columns) (struct som_entity *, int *style);
+ void (*headers) (struct som_entity *, int *l, int *r, int *t, int *b);
+ void (*flags) (struct som_entity *, unsigned *);
+
+ /* Creating and freeing driver-specific table rendering data. */
+ void *(*render_init) (struct som_entity *, struct outp_driver *,
+ int l, int r, int t, int b);
+ void (*render_free) (void *);
+
+ /* Rendering operations. */
+ void (*area) (void *, int *horiz, int *vert);
+ void (*cumulate) (void *, int cumtype, int start, int *end,
+ int max, int *actual);
+ void (*title) (void *, int x, int y, int table_num, int subtable_num,
+ const char *command_name);
+ void (*render) (void *, int x1, int y1, int x2, int y2);
};
-/* Table indexes. */
-extern int table_num;
-extern int subtable_num;
-
/* Submission. */
void som_new_series (void);
+void som_set_command_name (const char *);
void som_submit (struct som_entity *t);
/* Miscellaneous. */
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+/* A driver for creating OpenDocument Format text files from PSPP's output */
+
+#include <libpspp/assertion.h>
+#include <libpspp/version.h>
+
+#include <output/manager.h>
+#include <output/output.h>
+#include <output/table.h>
+
+#include <time.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <libgen.h>
+
+#include <libxml/xmlwriter.h>
+
+#include "xalloc.h"
+
+#include "error.h"
+
+#define _xml(X) (const xmlChar *)(X)
+
+
+struct odf_driver_options
+{
+ struct outp_driver *driver;
+
+ char *file_name; /* Output file name. */
+ bool debug;
+};
+
+
+struct odt_driver_ext
+{
+ /* The name of the temporary directory used to construct the ODF */
+ char *dirname;
+
+ /* Writer for the content.xml file */
+ xmlTextWriterPtr content_wtr;
+
+ /* Writer fot the manifest.xml file */
+ xmlTextWriterPtr manifest_wtr;
+
+ struct odf_driver_options opts;
+};
+
+
+
+/* Create the "mimetype" file needed by ODF */
+static void
+create_mimetype (const char *dirname)
+{
+ FILE *fp;
+ struct string filename;
+ ds_init_cstr (&filename, dirname);
+ ds_put_cstr (&filename, "/mimetype");
+ fp = fopen (ds_cstr (&filename), "w");
+ ds_destroy (&filename);
+
+ assert (fp);
+ fprintf (fp, "application/vnd.oasis.opendocument.text");
+ fclose (fp);
+}
+
+/* Create a new XML file called FILENAME in the temp directory, and return a writer for it */
+static xmlTextWriterPtr
+create_writer (const struct odt_driver_ext *driver, const char *filename)
+{
+ char *copy = NULL;
+ xmlTextWriterPtr w;
+ struct string str;
+ ds_init_cstr (&str, driver->dirname);
+ ds_put_cstr (&str, "/");
+ ds_put_cstr (&str, filename);
+
+ /* dirname modifies its argument, so we must copy it */
+ copy = xstrdup (ds_cstr (&str));
+ mkdir (dirname (copy), 0700);
+ free (copy);
+
+ w = xmlNewTextWriterFilename (ds_cstr (&str), 0);
+
+ ds_destroy (&str);
+
+ xmlTextWriterStartDocument (w, NULL, "UTF-8", NULL);
+
+ return w;
+}
+
+
+static void
+register_file (struct odt_driver_ext *x, const char *filename)
+{
+ assert (x->manifest_wtr);
+ xmlTextWriterStartElement (x->manifest_wtr, _xml("manifest:file-entry"));
+ xmlTextWriterWriteAttribute (x->manifest_wtr, _xml("manifest:media-type"), _xml("text/xml"));
+ xmlTextWriterWriteAttribute (x->manifest_wtr, _xml("manifest:full-path"), _xml (filename));
+ xmlTextWriterEndElement (x->manifest_wtr);
+}
+
+static void
+write_style_data (struct odt_driver_ext *x)
+{
+ xmlTextWriterPtr w = create_writer (x, "styles.xml");
+ register_file (x, "styles.xml");
+
+ xmlTextWriterStartElement (w, _xml ("office:document-styles"));
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:office"),
+ _xml ("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:style"),
+ _xml ("urn:oasis:names:tc:opendocument:xmlns:style:1.0"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:fo"),
+ _xml ("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0") );
+
+ xmlTextWriterWriteAttribute (w, _xml ("office:version"), _xml ("1.1"));
+
+
+
+ xmlTextWriterStartElement (w, _xml ("office:styles"));
+
+
+ {
+ xmlTextWriterStartElement (w, _xml ("style:style"));
+ xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+ _xml ("Standard"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+ _xml ("paragraph"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+ _xml ("text"));
+
+ xmlTextWriterEndElement (w); /* style:style */
+ }
+
+ {
+ xmlTextWriterStartElement (w, _xml ("style:style"));
+ xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+ _xml ("Table_20_Contents"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:display-name"),
+ _xml ("Table Contents"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+ _xml ("paragraph"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:parent-style-name"),
+ _xml ("Standard"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+ _xml ("extra"));
+
+ xmlTextWriterEndElement (w); /* style:style */
+ }
+
+ {
+ xmlTextWriterStartElement (w, _xml ("style:style"));
+ xmlTextWriterWriteAttribute (w, _xml ("style:name"),
+ _xml ("Table_20_Heading"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:display-name"),
+ _xml ("Table Heading"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:family"),
+ _xml ("paragraph"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:parent-style-name"),
+ _xml ("Table_20_Contents"));
+
+ xmlTextWriterWriteAttribute (w, _xml ("style:class"),
+ _xml ("extra"));
+
+
+ xmlTextWriterStartElement (w, _xml ("style:text-properties"));
+ xmlTextWriterWriteAttribute (w, _xml ("fo:font-weight"), _xml ("bold"));
+ xmlTextWriterWriteAttribute (w, _xml ("style:font-weight-asian"), _xml ("bold"));
+ xmlTextWriterWriteAttribute (w, _xml ("style:font-weight-complex"), _xml ("bold"));
+ xmlTextWriterEndElement (w); /* style:text-properties */
+
+ xmlTextWriterEndElement (w); /* style:style */
+ }
+
+
+ xmlTextWriterEndElement (w); /* office:styles */
+ xmlTextWriterEndElement (w); /* office:document-styles */
+
+ xmlTextWriterEndDocument (w);
+ xmlFreeTextWriter (w);
+}
+
+static void
+write_meta_data (struct odt_driver_ext *x)
+{
+ xmlTextWriterPtr w = create_writer (x, "meta.xml");
+ register_file (x, "meta.xml");
+
+ xmlTextWriterStartElement (w, _xml ("office:document-meta"));
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:office"), _xml ("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:dc"), _xml ("http://purl.org/dc/elements/1.1/"));
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:meta"), _xml ("urn:oasis:names:tc:opendocument:xmlns:meta:1.0"));
+ xmlTextWriterWriteAttribute (w, _xml ("xmlns:ooo"), _xml("http://openoffice.org/2004/office"));
+ xmlTextWriterWriteAttribute (w, _xml ("office:version"), _xml("1.1"));
+
+ xmlTextWriterStartElement (w, _xml ("office:meta"));
+ {
+ xmlTextWriterStartElement (w, _xml ("meta:generator"));
+ xmlTextWriterWriteString (w, _xml (stat_version));
+ xmlTextWriterEndElement (w);
+ }
+
+
+ {
+ char buf[30];
+ struct passwd *pw = getpwuid (getuid ());
+ time_t t = time (NULL);
+ struct tm *tm = localtime (&t);
+
+ strftime (buf, 30, "%Y-%m-%dT%H:%M:%S", tm);
+
+ xmlTextWriterStartElement (w, _xml ("meta:initial-creator"));
+ xmlTextWriterWriteString (w, _xml (strtok (pw->pw_gecos, ",")));
+ xmlTextWriterEndElement (w);
+
+ xmlTextWriterStartElement (w, _xml ("meta:creation-date"));
+ xmlTextWriterWriteString (w, _xml (buf));
+ xmlTextWriterEndElement (w);
+
+ xmlTextWriterStartElement (w, _xml ("dc:creator"));
+ xmlTextWriterWriteString (w, _xml (strtok (pw->pw_gecos, ",")));
+
+ xmlTextWriterEndElement (w);
+
+ xmlTextWriterStartElement (w, _xml ("dc:date"));
+ xmlTextWriterWriteString (w, _xml (buf));
+ xmlTextWriterEndElement (w);
+ }
+
+ xmlTextWriterEndElement (w);
+ xmlTextWriterEndElement (w);
+ xmlTextWriterEndDocument (w);
+ xmlFreeTextWriter (w);
+}
+
+enum
+{
+ output_file_arg,
+ boolean_arg,
+};
+
+static const struct outp_option option_tab[] =
+{
+ {"output-file", output_file_arg,0},
+
+ {"debug", boolean_arg, 1},
+
+ {NULL, 0, 0},
+};
+
+static bool
+handle_option (void *options_, const char *key, const struct string *val)
+{
+ struct odf_driver_options *options = options_;
+ struct outp_driver *this = options->driver;
+ int subcat;
+ char *value = ds_cstr (val);
+
+ switch (outp_match_keyword (key, option_tab, &subcat))
+ {
+ case -1:
+ error (0, 0,
+ _("unknown configuration parameter `%s' for %s device "
+ "driver"), key, this->class->name);
+ break;
+ case output_file_arg:
+ free (options->file_name);
+ options->file_name = xstrdup (value);
+ break;
+ case boolean_arg:
+ if (!strcmp (value, "on") || !strcmp (value, "true")
+ || !strcmp (value, "yes") || atoi (value))
+ options->debug = true;
+ else if (!strcmp (value, "off") || !strcmp (value, "false")
+ || !strcmp (value, "no") || !strcmp (value, "0"))
+ options->debug = false;
+ else
+ {
+ error (0, 0, _("boolean value expected for %s"), key);
+ return false;
+ }
+ break;
+
+ default:
+ NOT_REACHED ();
+ }
+
+ return true;
+}
+
+
+static bool
+odt_open_driver (const char *name, int types, struct substring option_string)
+{
+ struct odt_driver_ext *x;
+ struct outp_driver *this = outp_allocate_driver (&odt_class, name, types);
+
+ this->ext = x = xmalloc (sizeof *x);
+
+ x->opts.driver = this;
+ x->opts.file_name = xstrdup ("pspp.pdt");
+ x->opts.debug = false;
+
+ outp_parse_options (this->name, option_string, handle_option, &x->opts);
+
+ outp_register_driver (this);
+
+ x->dirname = xstrdup ("odt-XXXXXX");
+ mkdtemp (x->dirname);
+
+ create_mimetype (x->dirname);
+
+ /* Create the manifest */
+ x->manifest_wtr = create_writer (x, "META-INF/manifest.xml");
+
+ xmlTextWriterStartElement (x->manifest_wtr, _xml("manifest:manifest"));
+ xmlTextWriterWriteAttribute (x->manifest_wtr, _xml("xmlns:manifest"),
+ _xml("urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"));
+
+
+ /* Add a manifest entry for the document as a whole */
+ xmlTextWriterStartElement (x->manifest_wtr, _xml("manifest:file-entry"));
+ xmlTextWriterWriteAttribute (x->manifest_wtr, _xml("manifest:media-type"), _xml("application/vnd.oasis.opendocument.text"));
+ xmlTextWriterWriteAttribute (x->manifest_wtr, _xml("manifest:full-path"), _xml("/"));
+ xmlTextWriterEndElement (x->manifest_wtr);
+
+
+ write_meta_data (x);
+ write_style_data (x);
+
+ x->content_wtr = create_writer (x, "content.xml");
+ register_file (x, "content.xml");
+
+
+ /* Some necessary junk at the start */
+ xmlTextWriterStartElement (x->content_wtr, _xml("office:document-content"));
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("xmlns:office"),
+ _xml("urn:oasis:names:tc:opendocument:xmlns:office:1.0"));
+
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("xmlns:text"),
+ _xml("urn:oasis:names:tc:opendocument:xmlns:text:1.0"));
+
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("xmlns:table"),
+ _xml("urn:oasis:names:tc:opendocument:xmlns:table:1.0"));
+
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("office:version"), _xml("1.1"));
+
+ xmlTextWriterStartElement (x->content_wtr, _xml("office:body"));
+ xmlTextWriterStartElement (x->content_wtr, _xml("office:text"));
+
+
+
+ /* Close the manifest */
+ xmlTextWriterEndElement (x->manifest_wtr);
+ xmlTextWriterEndDocument (x->manifest_wtr);
+ xmlFreeTextWriter (x->manifest_wtr);
+
+ return true;
+}
+
+static bool
+odt_close_driver (struct outp_driver *this)
+{
+ struct string zip_cmd;
+ struct string rm_cmd;
+ struct odt_driver_ext *x = this->ext;
+
+ xmlTextWriterEndElement (x->content_wtr); /* office:text */
+ xmlTextWriterEndElement (x->content_wtr); /* office:body */
+ xmlTextWriterEndElement (x->content_wtr); /* office:document-content */
+
+ xmlTextWriterEndDocument (x->content_wtr);
+ xmlFreeTextWriter (x->content_wtr);
+
+ /* Zip up the directory */
+ ds_init_empty (&zip_cmd);
+ ds_put_format (&zip_cmd,
+ "cd %s ; rm -f ../%s; zip -q -X ../%s mimetype; zip -q -X -u -r ../pspp.odt .",
+ x->dirname, x->opts.file_name, x->opts.file_name);
+ system (ds_cstr (&zip_cmd));
+ ds_destroy (&zip_cmd);
+
+
+ if ( !x->opts.debug )
+ {
+ /* Remove the temp dir */
+ ds_init_empty (&rm_cmd);
+ ds_put_format (&rm_cmd, "rm -r %s", x->dirname);
+ system (ds_cstr (&rm_cmd));
+ ds_destroy (&rm_cmd);
+ }
+ else
+ fprintf (stderr, "Not removing directory %s\n", x->dirname);
+
+ free (x->dirname);
+ free (x);
+
+ return true;
+}
+
+static void
+odt_open_page (struct outp_driver *this UNUSED)
+{
+}
+
+static void
+odt_close_page (struct outp_driver *this UNUSED)
+{
+}
+
+static void
+odt_output_chart (struct outp_driver *this UNUSED, const struct chart *chart UNUSED)
+{
+ printf ("%s\n", __FUNCTION__);
+}
+
+
+/* Submit a table to the ODT driver */
+static void
+odt_submit (struct outp_driver *this, struct som_entity *e)
+{
+ int r, c;
+
+ struct odt_driver_ext *x = this->ext;
+ struct tab_table *tab = e->ext;
+
+
+ /* Write a heading for the table */
+ xmlTextWriterStartElement (x->content_wtr, _xml("text:h"));
+ xmlTextWriterWriteFormatAttribute (x->content_wtr, _xml("text:level"), "%d", e->subtable_num == 1 ? 2 : 3);
+ xmlTextWriterWriteString (x->content_wtr, _xml (tab->title) );
+ xmlTextWriterEndElement (x->content_wtr);
+
+ /* Start table */
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table"));
+ xmlTextWriterWriteFormatAttribute (x->content_wtr, _xml("table:name"),
+ "TABLE-%d.%d", e->table_num, e->subtable_num);
+
+
+ /* Start column definitions */
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table-column"));
+ xmlTextWriterWriteFormatAttribute (x->content_wtr, _xml("table:number-columns-repeated"), "%d", tab_nc (tab));
+ xmlTextWriterEndElement (x->content_wtr);
+
+
+ /* Deal with row headers */
+ if ( tab_t (tab) > 0)
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table-header-rows"));
+
+
+ /* Write all the rows */
+ for (r = 0 ; r < tab_nr (tab); ++r)
+ {
+ int spanned_columns = 0;
+ /* Start row definition */
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table-row"));
+
+ /* Write all the columns */
+ for (c = 0 ; c < tab_nc (tab) ; ++c)
+ {
+ char *s = NULL;
+ unsigned int opts = tab->ct[tab_nc (tab) * r + c];
+ struct substring ss = tab->cc[tab_nc (tab) * r + c];
+
+ if (opts & TAB_EMPTY)
+ {
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table-cell"));
+ xmlTextWriterEndElement (x->content_wtr);
+ continue;
+ }
+
+ if ( opts & TAB_JOIN)
+ {
+ if ( spanned_columns == 0)
+ {
+ struct tab_joined_cell *j = (struct tab_joined_cell*) ss_data (ss);
+ s = ss_xstrdup (j->contents);
+ }
+ }
+ else
+ s = ss_xstrdup (ss);
+
+ if ( spanned_columns == 0 )
+ {
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:table-cell"));
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("office:value-type"), _xml("string"));
+
+ if ( opts & TAB_JOIN )
+ {
+ struct tab_joined_cell *j = (struct tab_joined_cell*) ss_data (ss);
+ spanned_columns = j->x2 - j->x1;
+
+ xmlTextWriterWriteFormatAttribute (x->content_wtr,
+ _xml("table:number-columns-spanned"),
+ "%d", spanned_columns);
+ }
+
+ xmlTextWriterStartElement (x->content_wtr, _xml("text:p"));
+
+ if ( r < tab_t (tab) || c < tab_l (tab) )
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("text:style-name"), _xml("Table_20_Heading"));
+ else
+ xmlTextWriterWriteAttribute (x->content_wtr, _xml("text:style-name"), _xml("Table_20_Contents"));
+
+ xmlTextWriterWriteString (x->content_wtr, _xml (s));
+
+ xmlTextWriterEndElement (x->content_wtr); /* text:p */
+ xmlTextWriterEndElement (x->content_wtr); /* table:table-cell */
+ }
+ else
+ {
+ xmlTextWriterStartElement (x->content_wtr, _xml("table:covered-table-cell"));
+ xmlTextWriterEndElement (x->content_wtr);
+ }
+ if ( opts & TAB_JOIN )
+ spanned_columns --;
+
+ free (s);
+ }
+
+ xmlTextWriterEndElement (x->content_wtr); /* row */
+
+ if ( tab_t (tab) > 0 && r == tab_t (tab) - 1)
+ xmlTextWriterEndElement (x->content_wtr); /* table-header-rows */
+ }
+
+ xmlTextWriterEndElement (x->content_wtr); /* table */
+}
+
+
+/* ODT driver class. */
+const struct outp_class odt_class =
+{
+ "odf",
+ 1,
+
+ odt_open_driver,
+ odt_close_driver,
+
+ odt_open_page,
+ odt_close_page,
+ NULL,
+
+ odt_output_chart,
+ odt_submit,
+
+ NULL,
+ NULL,
+ NULL,
+};
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* FIXME? Should the output configuration format be changed to
- drivername:classname:devicetype:options, where devicetype is zero
- or more of screen, printer, listing? */
-
-/* FIXME: Have the reentrancy problems been solved? */
-
/* Where the output driver name came from. */
enum
{
};
static struct outp_driver_class_list *outp_class_list;
-static struct outp_driver *outp_driver_list;
+static struct ll_list outp_driver_list = LL_INITIALIZER (outp_driver_list);
char *outp_title;
char *outp_subtitle;
return getenv (key);
}
+static void
+insert_defn_value (const char *var, struct string *dst, void *aux UNUSED)
+{
+ const char *value = find_defn_value (var);
+ if (value != NULL)
+ ds_put_cstr (dst, value);
+}
+
/* Initializes global variables. */
void
outp_init (void)
{
- extern struct outp_class ascii_class;
- extern struct outp_class postscript_class;
-
char def[] = "default";
add_class (&html_class);
- add_class (&postscript_class);
add_class (&ascii_class);
+#ifdef HAVE_CAIRO
+ add_class (&cairo_class);
+#endif
+ add_class (&odt_class);
add_name (def, &def[strlen (def)], OUTP_S_INIT_FILE);
}
if (result)
{
- if (outp_driver_list == NULL)
+ if (ll_is_empty (&outp_driver_list))
error (0, 0, _("no active output drivers"));
}
else
error (0, 0, _("error reading device definition file"));
- if (!result || outp_driver_list == NULL)
+ if (!result || ll_is_empty (&outp_driver_list))
init_default_drivers ();
}
ep++;
ds_init_cstr (&d->value, ep);
- fn_interp_vars (ds_ss (&d->value), find_defn_value, &d->value);
+ fn_interp_vars (ds_ss (&d->value), insert_defn_value, NULL, &d->value);
d->next = outp_macros;
d->prev = NULL;
if (outp_macros)
outp_macros = d;
}
-/* Destroys all the drivers in driver list *DL and sets *DL to
- NULL. */
-static void
-destroy_list (struct outp_driver ** dl)
-{
- struct outp_driver *d, *next;
-
- for (d = *dl; d; d = next)
- {
- destroy_driver (d);
- next = d->next;
- free (d);
- }
- *dl = NULL;
-}
-
/* Closes all the output drivers. */
void
outp_done (void)
{
struct outp_driver_class_list *n = outp_class_list ;
outp_configure_clear ();
- destroy_list (&outp_driver_list);
+ while (!ll_is_empty (&outp_driver_list))
+ {
+ struct outp_driver *d = ll_data (ll_head (&outp_driver_list),
+ struct outp_driver, node);
+ destroy_driver (d);
+ }
while (n)
{
}
bool
-outp_parse_options (struct substring options,
- bool (*callback) (struct outp_driver *, const char *key,
- const struct string *value),
- struct outp_driver *driver)
+outp_parse_options (const char *driver_name, struct substring options,
+ bool (*callback) (void *aux, const char *key,
+ const struct string *value), void *aux)
{
struct string key = DS_EMPTY_INITIALIZER;
struct string value = DS_EMPTY_INITIALIZER;
if (ss_is_empty (left))
break;
- if (!get_option_token (&left, driver->name, &key))
+ if (!get_option_token (&left, driver_name, &key))
break;
ss_ltrim (&left, ss_cstr (CC_SPACES));
{
error (0, 0, _("syntax error expecting `=' "
"parsing options for driver \"%s\""),
- driver->name);
+ driver_name);
break;
}
ss_ltrim (&left, ss_cstr (CC_SPACES));
- if (!get_option_token (&left, driver->name, &value))
+ if (!get_option_token (&left, driver_name, &value))
break;
- ok = callback (driver, ds_cstr (&key), &value);
+ ok = callback (aux, ds_cstr (&key), &value);
}
while (ok);
find_driver (char *name)
{
struct outp_driver *d;
-
- for (d = outp_driver_list; d; d = d->next)
+ ll_for_each (d, struct outp_driver, node, &outp_driver_list)
if (!strcmp (d->name, name))
return d;
return NULL;
configure_driver (struct substring driver_name, struct substring class_name,
struct substring device_type, struct substring options)
{
- struct outp_driver *d, *iter;
struct outp_driver_class_list *c;
-
struct substring token;
size_t save_idx = 0;
+ char *name;
int device;
/* Find class. */
error (0, 0, _("unknown device type `%.*s'"),
(int) ss_length (token), ss_data (token));
- /* Open the device. */
- d = xmalloc (sizeof *d);
- d->next = d->prev = NULL;
- d->class = c->class;
- d->name = ss_xstrdup (driver_name);
+ /* Open driver. */
+ name = ss_xstrdup (driver_name);
+ if (!c->class->open_driver (name, device, options))
+ error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
+ name, c->class->name);
+ free (name);
+}
+
+/* Allocates and returns a new outp_driver for a device with the
+ given NAME and CLASS and the OUTP_DEV_* type(s) in TYPES
+
+ This function is intended to be used by output drivers, not
+ by their clients. */
+struct outp_driver *
+outp_allocate_driver (const struct outp_class *class,
+ const char *name, int types)
+{
+ struct outp_driver *d = xmalloc (sizeof *d);
+ d->class = class;
+ d->name = xstrdup (name);
d->page_open = false;
- d->device = device;
+ d->device = types;
d->cp_x = d->cp_y = 0;
d->ext = NULL;
- d->prc = NULL;
+ return d;
+}
- /* Open driver. */
- if (!d->class->open_driver (d, options))
- {
- error (0, 0, _("cannot initialize output driver `%s' of class `%s'"),
- d->name, d->class->name);
- free (d->name);
- free (d);
- return;
- }
+/* Frees driver D and the data that it owns directly. The
+ driver's class must already have unregistered D (if it was
+ registered) and freed data private to its class.
+
+ This function is intended to be used by output drivers, not
+ by their clients. */
+void
+outp_free_driver (struct outp_driver *d)
+{
+ free (d->name);
+ free (d);
+}
+
+/* Adds D to the list of drivers that will be used for output. */
+void
+outp_register_driver (struct outp_driver *d)
+{
+ struct outp_driver *victim;
/* Find like-named driver and delete. */
- iter = find_driver (d->name);
- if (iter != NULL)
- destroy_driver (iter);
+ victim = find_driver (d->name);
+ if (victim != NULL)
+ destroy_driver (victim);
- /* Add to list. */
- d->next = outp_driver_list;
- d->prev = NULL;
- if (outp_driver_list != NULL)
- outp_driver_list->prev = d;
- outp_driver_list = d;
+ /* Add D to list. */
+ ll_push_tail (&outp_driver_list, &d->node);
+}
+
+/* Remove driver D from the list of drivers that will be used for
+ output. */
+void
+outp_unregister_driver (struct outp_driver *d)
+{
+ ll_remove (&d->node);
}
/* String LINE is in format:
size_t save_idx;
size_t i;
- fn_interp_vars (line_, find_defn_value, &line);
+ fn_interp_vars (line_, insert_defn_value, NULL, &line);
save_idx = 0;
for (i = 0; i < 4; i++)
destroy_driver (struct outp_driver *d)
{
outp_close_page (d);
- if (d->class)
- {
- struct outp_driver_class_list *c;
-
- d->class->close_driver (d);
-
- for (c = outp_class_list; c; c = c->next)
- if (c->class == d->class)
- break;
- assert (c != NULL);
- }
- free (d->name);
-
- /* Remove this driver from the global driver list. */
- if (d->prev)
- d->prev->next = d->next;
- if (d->next)
- d->next->prev = d->prev;
- if (d == outp_driver_list)
- outp_driver_list = d->next;
+ if (d->class && d->class->close_driver)
+ d->class->close_driver (d);
+ outp_unregister_driver (d);
+ outp_free_driver (d);
}
/* Tries to match S as one of the keywords in TAB, with
struct outp_driver *
outp_drivers (struct outp_driver *d)
{
- for (;;)
+ do
{
- if (d == NULL)
- d = outp_driver_list;
- else
- d = d->next;
+ struct ll *next;
+
+ next = d == NULL ? ll_head (&outp_driver_list) : ll_next (&d->node);
+ if (next == ll_null (&outp_driver_list))
+ return NULL;
- if (d == NULL
- || (d->device == 0 || (d->device & disabled_devices) != d->device))
- break;
+ d = ll_data (next, struct outp_driver, node);
}
+ while (d->device != 0 && (d->device & disabled_devices) == d->device);
return d;
}
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#ifndef OUTPUT_OUTPUT_H
#define OUTPUT_OUTPUT_H 1
+#include <libpspp/ll.h>
#include <libpspp/str.h>
-
/* Line styles. */
enum outp_line_style
{
const char *name; /* Name of this driver class. */
int special; /* Boolean value. */
- bool (*open_driver) (struct outp_driver *, struct substring options);
+ bool (*open_driver) (const char *name, int types,
+ struct substring options);
bool (*close_driver) (struct outp_driver *);
void (*open_page) (struct outp_driver *);
void (*flush) (struct outp_driver *);
+ void (*output_chart) (struct outp_driver *, const struct chart *);
+
/* special != 0 only. */
void (*submit) (struct outp_driver *, struct som_entity *);
void (*text_metrics) (struct outp_driver *, const struct outp_text *,
int *width, int *height);
void (*text_draw) (struct outp_driver *, const struct outp_text *);
- void (*initialise_chart)(struct outp_driver *, struct chart *);
- void (*finalise_chart)(struct outp_driver *, struct chart *);
};
/* Device types. */
/* Defines the configuration of an output driver. */
struct outp_driver
{
- struct outp_driver *next, *prev; /* List of drivers. */
+ struct ll node; /* Node in list of drivers. */
const struct outp_class *class; /* Driver class. */
char *name; /* Name of this driver. */
bool page_open; /* 1=page is open, 0=page is closed. */
int vert_line_width[OUTP_L_COUNT]; /* Width of vertical lines. */
void *ext; /* Private extension record. */
- void *prc; /* Per-procedure extension record. */
};
/* Option structure for the keyword recognizer. */
extern char *outp_subtitle;
void outp_init (void);
+void outp_done (void);
void outp_read_devices (void);
void outp_configure_driver_line (struct substring);
-void outp_done (void);
+
+struct outp_driver *outp_allocate_driver (const struct outp_class *class,
+ const char *name, int types);
+void outp_free_driver (struct outp_driver *);
+void outp_register_driver (struct outp_driver *);
+void outp_unregister_driver (struct outp_driver *);
void outp_configure_clear (void);
void outp_configure_add (char *);
void outp_enable_device (bool enable, int device);
struct outp_driver *outp_drivers (struct outp_driver *);
-bool outp_parse_options (struct substring options,
- bool (*) (struct outp_driver *, const char *key,
- const struct string *value),
- struct outp_driver *);
+bool outp_parse_options (const char *driver_name, struct substring options,
+ bool (*callback) (void *aux, const char *key,
+ const struct string *value),
+ void *aux);
int outp_match_keyword (const char *, const struct outp_option *, int *);
int outp_evaluate_dimension (const char *);
/* Imported from som-frnt.c. */
void som_destroy_driver (struct outp_driver *);
+/* Common drivers. */
+extern const struct outp_class ascii_class;
+#ifdef HAVE_CAIRO
+extern const struct outp_class cairo_class;
+#endif
+extern const struct outp_class odt_class;
+
#endif /* output/output.h */
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2007 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- 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, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <libpspp/assertion.h>
-#include <libpspp/bit-vector.h>
-#include <libpspp/compiler.h>
-#include <libpspp/freaderror.h>
-#include <libpspp/hash.h>
-#include <libpspp/misc.h>
-#include <libpspp/start-date.h>
-#include <libpspp/version.h>
-
-#include <data/file-name.h>
-
-#include "afm.h"
-#include "chart.h"
-#include "error.h"
-#include "manager.h"
-#include "output.h"
-
-#include "intprops.h"
-#include "minmax.h"
-#include "xalloc.h"
-
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
-/* PostScript driver options: (defaults listed first)
-
- output-file="pspp.ps"
-
- paper-size=letter (see "papersize" file)
- orientation=portrait|landscape
- headers=on|off
-
- left-margin=0.5in
- right-margin=0.5in
- top-margin=0.5in
- bottom-margin=0.5in
-
- prop-font=Times-Roman
- emph-font=Times-Italic
- fixed-font=Courier
- font-size=10000
-
- line-gutter=1pt
- line-spacing=1pt
- line-width=0.5pt
- */
-
-/* The number of `psus' (PostScript driver UnitS) per inch. */
-#define PSUS 72000
-
-/* A PostScript font. */
-struct font
- {
- struct afm *metrics; /* Metrics. */
- char *embed_fn; /* Name of file to embed. */
- char *encoding_fn; /* Name of file with encoding. */
- };
-
-/* PostScript output driver extension record. */
-struct ps_driver_ext
- {
- char *file_name; /* Output file name. */
- FILE *file; /* Output file. */
-
- bool draw_headers; /* Draw headers at top of page? */
- int page_number; /* Current page number. */
-
- bool portrait; /* Portrait mode? */
- int paper_width; /* Width of paper before dropping margins. */
- int paper_length; /* Length of paper before dropping margins. */
- int left_margin; /* Left margin in psus. */
- int right_margin; /* Right margin in psus. */
- int top_margin; /* Top margin in psus. */
- int bottom_margin; /* Bottom margin in psus. */
-
- int line_gutter; /* Space around lines. */
- int line_space; /* Space between lines. */
- int line_width; /* Width of lines. */
-
- struct font *fonts[OUTP_FONT_CNT];
- int last_font; /* Index of last font set with setfont. */
- };
-
-/* Transform logical y-ordinate Y into a page ordinate. */
-#define YT(Y) (this->length - (Y))
-
-static bool handle_option (struct outp_driver *this, const char *key,
- const struct string *val);
-static void draw_headers (struct outp_driver *this);
-
-static void write_ps_prologue (struct outp_driver *);
-
-static char *quote_ps_name (const char *string);
-
-static struct font *load_font (const char *string);
-static void free_font (struct font *);
-static void setup_font (struct outp_driver *this, struct font *, int index);
-\f
-/* Driver initialization. */
-
-static bool
-ps_open_driver (struct outp_driver *this, struct substring options)
-{
- struct ps_driver_ext *x;
- size_t i;
-
- this->width = this->length = 0;
- this->font_height = PSUS * 10 / 72;
-
- this->ext = x = xmalloc (sizeof *x);
- x->file_name = xstrdup ("pspp.ps");
- x->file = NULL;
- x->draw_headers = true;
- x->page_number = 0;
- x->portrait = true;
- outp_get_paper_size ("", &x->paper_width, &x->paper_length);
- x->left_margin = PSUS / 2;
- x->right_margin = PSUS / 2;
- x->top_margin = PSUS / 2;
- x->bottom_margin = PSUS / 2;
- x->line_gutter = PSUS / 72;
- x->line_space = PSUS / 72;
- x->line_width = PSUS / 144;
- for (i = 0; i < OUTP_FONT_CNT; i++)
- x->fonts[i] = NULL;
-
- outp_parse_options (options, handle_option, this);
-
- x->file = fn_open (x->file_name, "w");
- if (x->file == NULL)
- {
- error (0, errno, _("opening PostScript output file \"%s\""),
- x->file_name);
- goto error;
- }
-
- if (x->portrait)
- {
- this->width = x->paper_width;
- this->length = x->paper_length;
- }
- else
- {
- this->width = x->paper_length;
- this->length = x->paper_width;
- }
- this->width -= x->left_margin + x->right_margin;
- this->length -= x->top_margin + x->bottom_margin;
- if (x->draw_headers)
- {
- int header_length = 3 * this->font_height;
- this->length -= header_length;
- x->top_margin += header_length;
- }
-
- for (i = 0; i < OUTP_FONT_CNT; i++)
- if (x->fonts[i] == NULL)
- {
- const char *default_fonts[OUTP_FONT_CNT];
- default_fonts[OUTP_FIXED] = "Courier.afm";
- default_fonts[OUTP_PROPORTIONAL] = "Times-Roman.afm";
- default_fonts[OUTP_EMPHASIS] = "Times-Italic.afm";
- x->fonts[i] = load_font (default_fonts[i]);
- if (x->fonts[i] == NULL)
- goto error;
- }
-
- if (this->length / this->font_height < 15)
- {
- error (0, 0, _("The defined PostScript page is not long "
- "enough to hold margins and headers, plus least 15 "
- "lines of the default fonts. In fact, there's only "
- "room for %d lines of each font at the default size "
- "of %d.%03d points."),
- this->length / this->font_height,
- this->font_height / 1000, this->font_height % 1000);
- goto error;
- }
-
- this->fixed_width =
- afm_get_character (x->fonts[OUTP_FIXED]->metrics, '0')->width
- * this->font_height / 1000;
- this->prop_em_width =
- afm_get_character (x->fonts[OUTP_PROPORTIONAL]->metrics, '0')->width
- * this->font_height / 1000;
-
- this->horiz_line_width[OUTP_L_NONE] = 0;
- this->horiz_line_width[OUTP_L_SINGLE] = 2 * x->line_gutter + x->line_width;
- this->horiz_line_width[OUTP_L_DOUBLE] = (2 * x->line_gutter + x->line_space
- + 2 * x->line_width);
- memcpy (this->vert_line_width, this->horiz_line_width,
- sizeof this->vert_line_width);
-
- write_ps_prologue (this);
-
- return true;
-
- error:
- this->class->close_driver (this);
- return false;
-}
-
-static bool
-ps_close_driver (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
- bool ok = true;
- size_t i;
-
- if (x->file != NULL)
- {
- fprintf (x->file,
- "%%%%Trailer\n"
- "%%%%Pages: %d\n"
- "%%%%EOF\n",
- x->page_number);
-
- ok = fn_close (x->file_name, x->file) == 0;
- if (!ok)
- error (0, errno, _("closing PostScript output file \"%s\""),
- x->file_name);
- }
-
- free (x->file_name);
- for (i = 0; i < OUTP_FONT_CNT; i++)
- free_font (x->fonts[i]);
- free (x);
-
- return ok;
-}
-
-/* Generic option types. */
-enum
-{
- output_file_arg,
- paper_size_arg,
- orientation_arg,
- line_style_arg,
- boolean_arg,
- pos_int_arg,
- dimension_arg,
- string_arg,
- nonneg_int_arg
-};
-
-/* All the options that the PostScript driver supports. */
-static const struct outp_option option_tab[] =
-{
- {"output-file", output_file_arg,0},
- {"paper-size", paper_size_arg, 0},
- {"orientation", orientation_arg,0},
-
- {"headers", boolean_arg, 1},
-
- {"prop-font", string_arg, OUTP_PROPORTIONAL},
- {"emph-font", string_arg, OUTP_EMPHASIS},
- {"fixed-font", string_arg, OUTP_FIXED},
-
- {"left-margin", pos_int_arg, 0},
- {"right-margin", pos_int_arg, 1},
- {"top-margin", pos_int_arg, 2},
- {"bottom-margin", pos_int_arg, 3},
- {"font-size", pos_int_arg, 4},
-
- {"line-width", dimension_arg, 0},
- {"line-gutter", dimension_arg, 1},
- {"line-width", dimension_arg, 2},
- {NULL, 0, 0},
-};
-
-static bool
-handle_option (struct outp_driver *this, const char *key,
- const struct string *val)
-{
- struct ps_driver_ext *x = this->ext;
- int subcat;
- char *value = ds_cstr (val);
-
- switch (outp_match_keyword (key, option_tab, &subcat))
- {
- case -1:
- error (0, 0,
- _("unknown configuration parameter `%s' for PostScript device "
- "driver"), key);
- break;
- case output_file_arg:
- free (x->file_name);
- x->file_name = xstrdup (value);
- break;
- case paper_size_arg:
- outp_get_paper_size (value, &this->width, &this->length);
- break;
- case orientation_arg:
- if (!strcmp (value, "portrait"))
- x->portrait = true;
- else if (!strcmp (value, "landscape"))
- x->portrait = false;
- else
- error (0, 0, _("unknown orientation `%s' (valid orientations are "
- "`portrait' and `landscape')"), value);
- break;
- case boolean_arg:
- if (!strcmp (value, "on") || !strcmp (value, "true")
- || !strcmp (value, "yes") || atoi (value))
- x->draw_headers = true;
- else if (!strcmp (value, "off") || !strcmp (value, "false")
- || !strcmp (value, "no") || !strcmp (value, "0"))
- x->draw_headers = false;
- else
- {
- error (0, 0, _("boolean value expected for %s"), key);
- return false;
- }
- break;
- case pos_int_arg:
- {
- char *tail;
- int arg;
-
- errno = 0;
- arg = strtol (value, &tail, 0);
- if (arg < 1 || errno == ERANGE || *tail)
- {
- error (0, 0, _("positive integer value required for `%s'"), key);
- break;
- }
- if ((subcat == 4 || subcat == 5) && arg < 1000)
- {
- error (0, 0, _("default font size must be at least 1 point (value "
- "of 1000 for key `%s')"), key);
- break;
- }
- switch (subcat)
- {
- case 0:
- x->left_margin = arg;
- break;
- case 1:
- x->right_margin = arg;
- break;
- case 2:
- x->top_margin = arg;
- break;
- case 3:
- x->bottom_margin = arg;
- break;
- case 4:
- this->font_height = arg;
- break;
- default:
- NOT_REACHED ();
- }
- }
- break;
- case dimension_arg:
- {
- int dimension = outp_evaluate_dimension (value);
-
- if (dimension <= 0)
- break;
- switch (subcat)
- {
- case 0:
- x->line_width = dimension;
- break;
- case 1:
- x->line_gutter = dimension;
- break;
- case 2:
- x->line_width = dimension;
- break;
- default:
- NOT_REACHED ();
- }
- }
- break;
- case string_arg:
- {
- struct font *font = load_font (value);
- if (font != NULL)
- {
- struct font **dst = &x->fonts[subcat];
- if (*dst != NULL)
- free_font (*dst);
- *dst = font;
- }
- }
- break;
- default:
- NOT_REACHED ();
- }
-
- return true;
-}
-
-/* Looks for a PostScript font file or config file in all the
- appropriate places. Returns the file name on success, NULL on
- failure. */
-static char *
-find_ps_file (const char *name)
-{
- if (fn_is_absolute (name))
- return xstrdup (name);
- else
- {
- char *base_name = xasprintf ("psfonts/%s", name);
- char *file_name = fn_search_path (base_name, config_path);
- free (base_name);
- return file_name;
- }
-}
-\f
-/* Basic file operations. */
-
-/* Writes the PostScript prologue to file F. */
-static void
-write_ps_prologue (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
- size_t embedded_cnt, preloaded_cnt;
- size_t i;
-
- fputs ("%!PS-Adobe-3.0\n", x->file);
- fputs ("%%Pages: (atend)\n", x->file);
-
- embedded_cnt = preloaded_cnt = 0;
- for (i = 0; i < OUTP_FONT_CNT; i++)
- {
- bool embed = x->fonts[i]->embed_fn != NULL;
- embedded_cnt += embed;
- preloaded_cnt += !embed;
- }
- if (preloaded_cnt > 0)
- {
- fputs ("%%DocumentNeededResources: font", x->file);
- for (i = 0; i < OUTP_FONT_CNT; i++)
- {
- struct font *f = x->fonts[i];
- if (f->embed_fn == NULL)
- fprintf (x->file, " %s", afm_get_findfont_name (f->metrics));
- }
- fputs ("\n", x->file);
- }
- if (embedded_cnt > 0)
- {
- fputs ("%%DocumentSuppliedResources: font", x->file);
- for (i = 0; i < OUTP_FONT_CNT; i++)
- {
- struct font *f = x->fonts[i];
- if (f->embed_fn != NULL)
- fprintf (x->file, " %s", afm_get_findfont_name (f->metrics));
- }
- fputs ("\n", x->file);
- }
- fputs ("%%Copyright: This prologue is public domain.\n", x->file);
- fprintf (x->file, "%%%%Creator: %s\n", version);
- fprintf (x->file, "%%%%DocumentMedia: Plain %g %g 75 white ()\n",
- x->paper_width / (PSUS / 72.0), x->paper_length / (PSUS / 72.0));
- fprintf (x->file, "%%%%Orientation: %s\n",
- x->portrait ? "Portrait" : "Landscape");
- fputs ("%%EndComments\n", x->file);
- fputs ("%%BeginDefaults\n", x->file);
- fputs ("%%PageResources: font", x->file);
- for (i = 0; i < OUTP_FONT_CNT; i++)
- fprintf (x->file, " %s", afm_get_findfont_name (x->fonts[i]->metrics));
- fputs ("\n", x->file);
- fputs ("%%EndDefaults\n", x->file);
- fputs ("%%BeginProlog\n", x->file);
- fputs ("/ED{exch def}bind def\n", x->file);
- fputs ("/L{moveto lineto stroke}bind def\n", x->file);
- fputs ("/D{moveto lineto moveto lineto stroke}bind def\n", x->file);
- fputs ("/S{show}bind def\n", x->file);
- fputs ("/GS{glyphshow}def\n", x->file);
- fputs ("/RF{\n", x->file);
- fputs (" exch dup maxlength 1 add dict begin\n", x->file);
- fputs (" {\n", x->file);
- fputs (" 1 index/FID ne{def}{pop pop}ifelse\n", x->file);
- fputs (" }forall\n", x->file);
- fputs (" /Encoding ED\n", x->file);
- fputs (" currentdict end\n", x->file);
- fputs ("}bind def\n", x->file);
- fputs ("/F{setfont}bind def\n", x->file);
- fputs ("/EP{\n", x->file);
- fputs (" pg restore\n", x->file);
- fputs (" showpage\n", x->file);
- fputs ("}bind def\n", x->file);
- fputs ("/GB{\n", x->file);
- fputs (" /y2 ED/x2 ED/y1 ED/x1 ED\n", x->file);
- fputs (" x1 y1 moveto x2 y1 lineto x2 y2 lineto x1 y2 lineto closepath\n",
- x->file);
- fputs (" gsave 0.9 setgray fill grestore stroke\n", x->file);
- fputs ("}bind def\n", x->file);
- fputs ("/K{0 rmoveto}bind def\n", x->file);
- fputs ("%%EndProlog\n", x->file);
- fputs ("%%BeginSetup\n", x->file);
- for (i = 0; i < OUTP_FONT_CNT; i++)
- setup_font (this, x->fonts[i], i);
- fputs ("%%EndSetup\n", x->file);
-}
-
-/* Returns STRING as a Postscript name, which is just '/'
- followed by STRING unless characters need to be quoted.
- The caller must free the string. */
-static char *
-quote_ps_name (const char *string)
-{
- const char *cp;
-
- for (cp = string; *cp != '\0'; cp++)
- {
- unsigned char c = *cp;
- if (!isalpha (c) && strchr ("^_|!$&:;.,-+", c) == NULL
- && (cp == string || !isdigit (c)))
- {
- struct string out = DS_EMPTY_INITIALIZER;
- ds_put_char (&out, '<');
- for (cp = string; *cp != '\0'; cp++)
- {
- c = *cp;
- ds_put_format (&out, "%02x", c);
- }
- ds_put_cstr (&out, ">cvn");
- return ds_cstr (&out);
- }
- }
- return xasprintf ("/%s", string);
-}
-
-static void
-ps_open_page (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
-
- /* Assure page independence. */
- x->last_font = -1;
-
- x->page_number++;
-
- fprintf (x->file,
- "%%%%Page: %d %d\n"
- "%%%%BeginPageSetup\n"
- "/pg save def 0.001 dup scale\n",
- x->page_number, x->page_number);
-
- if (!x->portrait)
- fprintf (x->file,
- "%d 0 translate 90 rotate\n",
- x->paper_width);
-
- if (x->bottom_margin != 0 || x->left_margin != 0)
- fprintf (x->file,
- "%d %d translate\n",
- x->left_margin, x->bottom_margin);
-
- fprintf (x->file,
- "/LW %d def %d setlinewidth\n"
- "%%%%EndPageSetup\n",
- x->line_width, x->line_width);
-
- if (x->draw_headers)
- draw_headers (this);
-}
-
-static void
-ps_close_page (struct outp_driver *this)
-{
- struct ps_driver_ext *x = this->ext;
- fputs ("%%PageTrailer\n"
- "EP\n",
- x->file);
-}
-
-static void
-ps_submit (struct outp_driver *this UNUSED, struct som_entity *s)
-{
- switch (s->type)
- {
- case SOM_CHART:
- break;
- default:
- NOT_REACHED ();
- }
-}
-\f
-/* Draws a line from (x0,y0) to (x1,y1). */
-static void
-dump_line (struct outp_driver *this, int x0, int y0, int x1, int y1)
-{
- struct ps_driver_ext *ext = this->ext;
- fprintf (ext->file, "%d %d %d %d L\n", x0, YT (y0), x1, YT (y1));
-}
-
-/* Draws a horizontal line X0...X2 at Y if LEFT says so,
- shortening it to X0...X1 if SHORTEN is true.
- Draws a horizontal line X1...X3 at Y if RIGHT says so,
- shortening it to X2...X3 if SHORTEN is true. */
-static void
-horz_line (struct outp_driver *this,
- int x0, int x1, int x2, int x3, int y,
- enum outp_line_style left, enum outp_line_style right,
- bool shorten)
-{
- if (left != OUTP_L_NONE && right != OUTP_L_NONE && !shorten)
- dump_line (this, x0, y, x3, y);
- else
- {
- if (left != OUTP_L_NONE)
- dump_line (this, x0, y, shorten ? x1 : x2, y);
- if (right != OUTP_L_NONE)
- dump_line (this, shorten ? x2 : x1, y, x3, y);
- }
-}
-
-/* Draws a vertical line Y0...Y2 at X if TOP says so,
- shortening it to Y0...Y1 if SHORTEN is true.
- Draws a vertical line Y1...Y3 at X if BOTTOM says so,
- shortening it to Y2...Y3 if SHORTEN is true. */
-static void
-vert_line (struct outp_driver *this,
- int y0, int y1, int y2, int y3, int x,
- enum outp_line_style top, enum outp_line_style bottom,
- bool shorten)
-{
- if (top != OUTP_L_NONE && bottom != OUTP_L_NONE && !shorten)
- dump_line (this, x, y0, x, y3);
- else
- {
- if (top != OUTP_L_NONE)
- dump_line (this, x, y0, x, shorten ? y1 : y2);
- if (bottom != OUTP_L_NONE)
- dump_line (this, x, shorten ? y2 : y1, x, y3);
- }
-}
-
-/* Draws a generalized intersection of lines in the rectangle
- (X0,Y0)-(X3,Y3). The line coming from the top to the center
- is of style TOP, from left to center of style LEFT, from
- bottom to center of style BOTTOM, and from right to center of
- style RIGHT. */
-static void
-ps_line (struct outp_driver *this,
- int x0, int y0, int x3, int y3,
- enum outp_line_style top, enum outp_line_style left,
- enum outp_line_style bottom, enum outp_line_style right)
-{
- /* The algorithm here is somewhat subtle, to allow it to handle
- all the kinds of intersections that we need.
-
- Three additional ordinates are assigned along the x axis. The
- first is xc, midway between x0 and x3. The others are x1 and
- x2; for a single vertical line these are equal to xc, and for
- a double vertical line they are the ordinates of the left and
- right half of the double line.
-
- yc, y1, and y2 are assigned similarly along the y axis.
-
- The following diagram shows the coordinate system and output
- for double top and bottom lines, single left line, and no
- right line:
-
- x0 x1 xc x2 x3
- y0 ________________________
- | # # |
- | # # |
- | # # |
- | # # |
- | # # |
- y1 = y2 = yc |######### # |
- | # # |
- | # # |
- | # # |
- | # # |
- y3 |________#_____#_______|
- */
- struct ps_driver_ext *ext = this->ext;
-
- /* Offset from center of each line in a pair of double lines. */
- int double_line_ofs = (ext->line_space + ext->line_width) / 2;
-
- /* Are the lines along each axis single or double?
- (It doesn't make sense to have different kinds of line on the
- same axis, so we don't try to gracefully handle that case.) */
- bool double_vert = top == OUTP_L_DOUBLE || bottom == OUTP_L_DOUBLE;
- bool double_horz = left == OUTP_L_DOUBLE || right == OUTP_L_DOUBLE;
-
- /* When horizontal lines are doubled,
- the left-side line along y1 normally runs from x0 to x2,
- and the right-side line along y1 from x3 to x1.
- If the top-side line is also doubled, we shorten the y1 lines,
- so that the left-side line runs only to x1,
- and the right-side line only to x2.
- Otherwise, the horizontal line at y = y1 below would cut off
- the intersection, which looks ugly:
- x0 x1 x2 x3
- y0 ________________________
- | # # |
- | # # |
- | # # |
- | # # |
- y1 |######### ########|
- | |
- | |
- y2 |######################|
- | |
- | |
- y3 |______________________|
- It is more of a judgment call when the horizontal line is
- single. We actually choose to cut off the line anyhow, as
- shown in the first diagram above.
- */
- bool shorten_y1_lines = top == OUTP_L_DOUBLE;
- bool shorten_y2_lines = bottom == OUTP_L_DOUBLE;
- bool shorten_yc_line = shorten_y1_lines && shorten_y2_lines;
- int horz_line_ofs = double_vert ? double_line_ofs : 0;
- int xc = (x0 + x3) / 2;
- int x1 = xc - horz_line_ofs;
- int x2 = xc + horz_line_ofs;
-
- bool shorten_x1_lines = left == OUTP_L_DOUBLE;
- bool shorten_x2_lines = right == OUTP_L_DOUBLE;
- bool shorten_xc_line = shorten_x1_lines && shorten_x2_lines;
- int vert_line_ofs = double_horz ? double_line_ofs : 0;
- int yc = (y0 + y3) / 2;
- int y1 = yc - vert_line_ofs;
- int y2 = yc + vert_line_ofs;
-
- if (!double_horz)
- horz_line (this, x0, x1, x2, x3, yc, left, right, shorten_yc_line);
- else
- {
- horz_line (this, x0, x1, x2, x3, y1, left, right, shorten_y1_lines);
- horz_line (this, x0, x1, x2, x3, y2, left, right, shorten_y2_lines);
- }
-
- if (!double_vert)
- vert_line (this, y0, y1, y2, y3, xc, top, bottom, shorten_xc_line);
- else
- {
- vert_line (this, y0, y1, y2, y3, x1, top, bottom, shorten_x1_lines);
- vert_line (this, y0, y1, y2, y3, x2, top, bottom, shorten_x2_lines);
- }
-}
-
-/* Writes STRING at location (X,Y) trimmed to the given MAX_WIDTH
- and with the given JUSTIFICATION for THIS driver. */
-static int
-draw_text (struct outp_driver *this,
- const char *string, int x, int y, int max_width,
- enum outp_justification justification)
-{
- struct outp_text text;
- int width;
-
- text.font = OUTP_PROPORTIONAL;
- text.justification = justification;
- text.string = ss_cstr (string);
- text.h = max_width;
- text.v = this->font_height;
- text.x = x;
- text.y = y;
- this->class->text_metrics (this, &text, &width, NULL);
- this->class->text_draw (this, &text);
- return width;
-}
-
-/* Writes LEFT left-justified and RIGHT right-justified within
- (X0...X1) at Y. LEFT or RIGHT or both may be null. */
-static void
-draw_header_line (struct outp_driver *this,
- const char *left, const char *right,
- int x0, int x1, int y)
-{
- int right_width = 0;
- if (right != NULL)
- right_width = (draw_text (this, right, x0, y, x1 - x0, OUTP_RIGHT)
- + this->prop_em_width);
- if (left != NULL)
- draw_text (this, left, x0, y, x1 - x0 - right_width, OUTP_LEFT);
-}
-
-/* Draw top of page headers for THIS driver. */
-static void
-draw_headers (struct outp_driver *this)
-{
- struct ps_driver_ext *ext = this->ext;
- char *r1, *r2;
- int x0, x1;
- int y;
-
- y = -3 * this->font_height;
- x0 = this->prop_em_width;
- x1 = this->width - this->prop_em_width;
-
- /* Draw box. */
- fprintf (ext->file, "%d %d %d %d GB\n",
- 0, YT (y),
- this->width, YT (y + 2 * this->font_height + ext->line_gutter));
- y += ext->line_width + ext->line_gutter;
-
- r1 = xasprintf (_("%s - Page %d"), get_start_date (), ext->page_number);
- r2 = xasprintf ("%s - %s", version, host_system);
-
- draw_header_line (this, outp_title, r1, x0, x1, y);
- y += this->font_height;
-
- draw_header_line (this, outp_subtitle, r2, x0, x1, y);
-
- free (r1);
- free (r2);
-}
-\f
-/* Writes the CHAR_CNT characters in CHARS at (X0,Y0), using the
- given FONT.
- The characters are justified according to JUSTIFICATION in a
- field that has WIDTH_LEFT space remaining after the characters
- themselves are accounted for.
- Before character I is written, its x-position is adjusted by
- KERNS[I]. */
-static void
-write_text (struct outp_driver *this,
- int x0, int y0,
- enum outp_font font,
- enum outp_justification justification,
- const struct afm_character **chars, int *kerns, size_t char_cnt,
- int width_left)
-{
- struct ps_driver_ext *ext = this->ext;
- struct afm *afm = ext->fonts[font]->metrics;
- struct string out;
- size_t i, j;
-
- if (justification == OUTP_RIGHT)
- x0 += width_left;
- else if (justification == OUTP_CENTER)
- x0 += width_left / 2;
- y0 += afm_get_ascent (afm) * this->font_height / 1000;
-
- fprintf (ext->file, "\n%d %d moveto\n", x0, YT (y0));
-
- if (ext->last_font != font)
- {
- ext->last_font = font;
- fprintf (ext->file, "F%d setfont\n", font);
- }
-
- ds_init_empty (&out);
- for (i = 0; i < char_cnt; i = j)
- {
- for (j = i + 1; j < char_cnt; j++)
- if (kerns[j] != 0)
- break;
-
- if (kerns[i] != 0)
- fprintf (ext->file, "%d K", kerns[i]);
- while (i < j)
- {
- size_t encoded = afm_encode_string (afm, chars + i, j - i, &out);
- if (encoded > 0)
- {
- fprintf (ext->file, "%sS\n", ds_cstr (&out));
- ds_clear (&out);
- i += encoded;
- }
-
- if (i < j)
- {
- fprintf (ext->file, "/%s GS\n", chars[i]->name);
- i++;
- }
- }
- }
- ds_destroy (&out);
-}
-
-/* State of a text formatting operation. */
-struct text_state
- {
- /* Input. */
- const struct outp_text *text;
- bool draw;
-
- /* Output. */
- const struct afm_character **glyphs;
- int *glyph_kerns;
-
- /* State. */
- size_t glyph_cnt; /* Number of glyphs output. */
- int width_left; /* Width left over. */
- int height_left; /* Height left over. */
-
- /* State as of last space. */
- const char *space_char; /* Just past last space. */
- size_t space_glyph_cnt; /* Number of glyphs as of last space. */
- int space_width_left; /* Width left over as of last space. */
-
- /* Statistics. */
- int max_width; /* Widest line so far. */
- };
-
-/* Adjusts S to complete a line of text,
- and draws the current line if appropriate. */
-static void
-finish_line (struct outp_driver *this, struct text_state *s)
-{
- int width;
-
- if (s->draw)
- {
- write_text (this,
- s->text->x, s->text->y + (s->text->v - s->height_left),
- s->text->font,
- s->text->justification,
- s->glyphs, s->glyph_kerns, s->glyph_cnt,
- s->width_left);
- s->glyph_cnt = 0;
- }
-
- /* Update maximum width. */
- width = s->text->h - s->width_left;
- if (width > s->max_width)
- s->max_width = width;
-
- /* Move to next line. */
- s->width_left = s->text->h;
- s->height_left -= this->font_height;
-
- /* No spaces on this line yet. */
- s->space_char = NULL;
-}
-
-/* Format TEXT on THIS driver.
- If DRAW is nonzero, draw the text.
- The width of the widest line is stored into *WIDTH, if WIDTH
- is nonnull.
- The total height of the text written is stored into *HEIGHT,
- if HEIGHT is nonnull. */
-static void
-text (struct outp_driver *this, const struct outp_text *text, bool draw,
- int *width, int *height)
-{
- struct ps_driver_ext *ext = this->ext;
- struct afm *afm = ext->fonts[text->font]->metrics;
- const char *cp;
- size_t glyph_cap;
- struct text_state s;
-
- s.text = text;
- s.draw = draw;
-
- s.glyphs = NULL;
- s.glyph_kerns = NULL;
- glyph_cap = 0;
-
- s.glyph_cnt = 0;
- s.width_left = s.text->h;
- s.height_left = s.text->v;
-
- s.space_char = 0;
-
- s.max_width = 0;
-
- cp = ss_data (s.text->string);
- while (s.height_left >= this->font_height && cp < ss_end (s.text->string))
- {
- const struct afm_character *cur;
- int char_width;
- int kern_adjust;
-
- if (*cp == '\n')
- {
- finish_line (this, &s);
- cp++;
- continue;
- }
-
- /* Get character and resolve ligatures. */
- cur = afm_get_character (afm, *cp);
- while (++cp < ss_end (s.text->string))
- {
- const struct afm_character *next = afm_get_character (afm, *cp);
- const struct afm_character *ligature = afm_get_ligature (cur, next);
- if (ligature == NULL)
- break;
- cur = ligature;
- }
- char_width = cur->width * this->font_height / 1000;
-
- /* Get kern adjustment. */
- if (s.glyph_cnt > 0)
- kern_adjust = (afm_get_kern_adjustment (s.glyphs[s.glyph_cnt - 1], cur)
- * this->font_height / 1000);
- else
- kern_adjust = 0;
-
- /* Record the current status if this is a space character. */
- if (cur->code == ' ' && cp > ss_data (s.text->string))
- {
- s.space_char = cp;
- s.space_glyph_cnt = s.glyph_cnt;
- s.space_width_left = s.width_left;
- }
-
- /* Enough room on this line? */
- if (char_width + kern_adjust > s.width_left)
- {
- if (s.space_char == NULL)
- {
- finish_line (this, &s);
- kern_adjust = 0;
- }
- else
- {
- cp = s.space_char;
- s.glyph_cnt = s.space_glyph_cnt;
- s.width_left = s.space_width_left;
- finish_line (this, &s);
- continue;
- }
- }
-
- if (s.glyph_cnt >= glyph_cap)
- {
- glyph_cap = 2 * (glyph_cap + 8);
- s.glyphs = xnrealloc (s.glyphs, glyph_cap, sizeof *s.glyphs);
- s.glyph_kerns = xnrealloc (s.glyph_kerns,
- glyph_cap, sizeof *s.glyph_kerns);
- }
- s.glyphs[s.glyph_cnt] = cur;
- s.glyph_kerns[s.glyph_cnt] = kern_adjust;
- s.glyph_cnt++;
-
- s.width_left -= char_width + kern_adjust;
- }
- if (s.height_left >= this->font_height && s.glyph_cnt > 0)
- finish_line (this, &s);
-
- if (width != NULL)
- *width = s.max_width;
- if (height != NULL)
- *height = text->v - s.height_left;
- free (s.glyphs);
- free (s.glyph_kerns);
-}
-
-static void
-ps_text_metrics (struct outp_driver *this, const struct outp_text *t,
- int *width, int *height)
-{
- text (this, t, false, width, height);
-}
-
-static void
-ps_text_draw (struct outp_driver *this, const struct outp_text *t)
-{
- assert (this->page_open);
- text (this, t, true, NULL, NULL);
-}
-\f
-static void
-ps_chart_initialise (struct outp_driver *this UNUSED, struct chart *ch)
-{
-#ifdef NO_CHARTS
- ch->lp = NULL;
-#else
- struct ps_driver_ext *x = this->ext;
- char page_size[128];
- int size;
- int x_origin, y_origin;
-
- ch->file = tmpfile ();
- if (ch->file == NULL)
- {
- ch->lp = NULL;
- return;
- }
-
- size = this->width < this->length ? this->width : this->length;
- x_origin = x->left_margin + (size - this->width) / 2;
- y_origin = x->bottom_margin + (size - this->length) / 2;
-
- snprintf (page_size, sizeof page_size,
- "a,xsize=%.3f,ysize=%.3f,xorigin=%.3f,yorigin=%.3f",
- (double) size / PSUS, (double) size / PSUS,
- (double) x_origin / PSUS, (double) y_origin / PSUS);
-
- ch->pl_params = pl_newplparams ();
- pl_setplparam (ch->pl_params, "PAGESIZE", page_size);
- ch->lp = pl_newpl_r ("ps", NULL, ch->file, stderr, ch->pl_params);
-#endif
-}
-
-static void
-ps_chart_finalise (struct outp_driver *this UNUSED, struct chart *ch UNUSED)
-{
-#ifndef NO_CHARTS
- struct ps_driver_ext *x = this->ext;
- char buf[BUFSIZ];
- static int doc_num = 0;
-
- outp_eject_page (this);
- fprintf (x->file,
- "/sp save def\n"
- "%d %d translate 1000 dup scale\n"
- "userdict begin\n"
- "/showpage { } def\n"
- "0 setgray 0 setlinecap 1 setlinewidth\n"
- "0 setlinejoin 10 setmiterlimit [ ] 0 setdash newpath clear\n"
- "%%%%BeginDocument: %d\n",
- -x->left_margin, -x->bottom_margin,
- doc_num++);
-
- rewind (ch->file);
- while (fwrite (buf, 1, fread (buf, 1, sizeof buf, ch->file), x->file))
- continue;
- fclose (ch->file);
-
- fputs ("%%EndDocument\n"
- "end\n"
- "sp restore\n",
- x->file);
- outp_close_page (this);
-#endif
-}
-\f
-static void embed_font (struct outp_driver *this, struct font *font);
-static void reencode_font (struct outp_driver *this, struct font *font);
-
-/* Loads and returns the font for STRING, which has the format
- "AFM,PFA,ENC", where AFM is the AFM file's name, PFA is the
- PFA or PFB file's name, and ENC is the encoding file's name.
- PFA and ENC are optional.
- Returns a null pointer if unsuccessful. */
-static struct font *
-load_font (const char *string_)
-{
- char *string = xstrdup (string_);
- struct font *font;
- char *position = string;
- char *token;
- char *afm_file_name;
-
- font = xmalloc (sizeof *font);
- font->metrics = NULL;
- font->embed_fn = NULL;
- font->encoding_fn = NULL;
-
- token = strsep (&position, ",");
- if (token == NULL)
- {
- error (0, 0, _("\"%s\": bad font specification"), string);
- goto error;
- }
-
- /* Read AFM file. */
- afm_file_name = find_ps_file (token);
- if (afm_file_name == NULL)
- {
- error (0, 0, _("could not find AFM file \"%s\""), token);
- goto error;
- }
- font->metrics = afm_open (afm_file_name);
- free (afm_file_name);
- if (font->metrics == NULL)
- goto error;
-
- /* Find font file to embed. */
- token = strsep (&position, ",");
- if (token != NULL && *token != '\0')
- {
- font->embed_fn = find_ps_file (token);
- if (font->embed_fn == NULL)
- error (0, 0, _("could not find font \"%s\""), token);
- }
-
- /* Find encoding. */
- token = strsep (&position, ",");
- if (token != NULL && *token == '\0')
- {
- font->encoding_fn = find_ps_file (token);
- if (font->encoding_fn == NULL)
- error (0, 0, _("could not find encoding \"%s\""), token);
- }
-
- free (string);
- return font;
-
- error:
- free (string);
- free_font (font);
- return NULL;
-}
-
-/* Frees FONT. */
-static void
-free_font (struct font *font)
-{
- if (font != NULL)
- {
- afm_close (font->metrics);
- free (font->embed_fn);
- free (font->encoding_fn);
- free (font);
- }
-}
-
-/* Emits PostScript code to embed FONT (if necessary), scale it
- to the proper size, re-encode it (if necessary), and store the
- resulting font as an object named F#, where INDEX is
- substituted for #. */
-static void
-setup_font (struct outp_driver *this, struct font *font, int index)
-{
- struct ps_driver_ext *x = this->ext;
- char *ps_name;
-
- if (font->embed_fn != NULL)
- embed_font (this, font);
- else
- fprintf (x->file, "%%%%IncludeResource: font %s\n",
- afm_get_findfont_name (font->metrics));
-
- ps_name = quote_ps_name (afm_get_findfont_name (font->metrics));
- fprintf (x->file, "%s findfont %d scalefont\n", ps_name, this->font_height);
- free (ps_name);
-
- if (font->encoding_fn != NULL)
- reencode_font (this, font);
-
- fprintf (x->file, "/F%d ED\n", index);
-}
-
-/* Copies up to COPY_BYTES bytes from SRC to DST, stopping at
- end-of-file or on error. */
-static void
-copy_bytes_literally (FILE *src, FILE *dst, unsigned long copy_bytes)
-{
- while (copy_bytes > 0)
- {
- char buffer[BUFSIZ];
- unsigned long chunk_bytes = MIN (copy_bytes, sizeof buffer);
- size_t read_bytes = fread (buffer, 1, chunk_bytes, src);
- size_t write_bytes = fwrite (buffer, 1, read_bytes, dst);
- if (write_bytes != chunk_bytes)
- break;
- copy_bytes -= chunk_bytes;
- }
-}
-
-/* Copies up to COPY_BYTES bytes from SRC to DST, stopping at
- end-of-file or on error. The bytes are translated into
- hexadecimal during copying and broken into lines with
- new-line characters. */
-static void
-copy_bytes_as_hex (FILE *src, FILE *dst, unsigned long copy_bytes)
-{
- unsigned long i;
-
- for (i = 0; i < copy_bytes; i++)
- {
- int c = getc (src);
- if (c == EOF)
- break;
- if (i > 0 && i % 36 == 0)
- putc ('\n', dst);
- fprintf (dst, "%02X", c);
- }
- putc ('\n', dst);
-}
-
-/* Embeds the given FONT into THIS driver's output stream. */
-static void
-embed_font (struct outp_driver *this, struct font *font)
-{
- struct ps_driver_ext *x = this->ext;
- FILE *file;
- int c;
-
- file = fopen (font->embed_fn, "rb");
- if (file == NULL)
- {
- error (errno, 0, _("cannot open font file \"%s\""), font->embed_fn);
- return;
- }
-
- fprintf (x->file, "%%%%BeginResource: font %s\n",
- afm_get_findfont_name (font->metrics));
-
- c = getc (file);
- ungetc (c, file);
- if (c != 128)
- {
- /* PFA file. Copy literally. */
- copy_bytes_literally (file, x->file, ULONG_MAX);
- }
- else
- {
- /* PFB file. Translate as specified in Adobe Technical
- Note #5040. */
- while ((c = getc (file)) == 128)
- {
- int type;
- unsigned long length;
-
- type = getc (file);
- if (type == 3)
- break;
-
- length = getc (file);
- length |= (unsigned long) getc (file) << 8;
- length |= (unsigned long) getc (file) << 16;
- length |= (unsigned long) getc (file) << 24;
-
- if (type == 1)
- copy_bytes_literally (file, x->file, length);
- else if (type == 2)
- copy_bytes_as_hex (file, x->file, length);
- else
- break;
- }
- }
- if (freaderror (file))
- error (errno, 0, _("reading font file \"%s\""), font->embed_fn);
- fputs ("%%EndResource\n", x->file);
-}
-
-/* Re-encodes FONT according to the specified encoding. */
-static void
-reencode_font (struct outp_driver *this, struct font *font)
-{
- struct ps_driver_ext *x = this->ext;
-
- struct string line;
-
- int line_number;
- FILE *file;
-
- char *tab[256];
-
- int i;
-
- file = fopen (font->encoding_fn, "r");
- if (file == NULL)
- {
- error (errno, 0, _("cannot open font encoding file \"%s\""),
- font->encoding_fn);
- return;
- }
-
- for (i = 0; i < 256; i++)
- tab[i] = NULL;
-
- line_number = 0;
-
- ds_init_empty (&line);
- while (ds_read_config_line (&line, &line_number, file))
- {
- char *pschar, *code;
- char *save_ptr, *tail;
- int code_val;
-
- if (ds_is_empty (&line) == 0)
- continue;
-
- pschar = strtok_r (ds_cstr (&line), " \t\r\n", &save_ptr);
- code = strtok_r (NULL, " \t\r\n", &save_ptr);
- if (pschar == NULL || code == NULL)
- continue;
-
- code_val = strtol (code, &tail, 0);
- if (*tail)
- {
- error_at_line (0, 0, font->encoding_fn, line_number,
- _("invalid numeric format"));
- continue;
- }
- if (code_val < 0 || code_val > 255)
- continue;
- if (tab[code_val] != 0)
- free (tab[code_val]);
- tab[code_val] = xstrdup (pschar);
- }
- ds_destroy (&line);
-
- fputs ("[", x->file);
- for (i = 0; i < 256; i++)
- {
- char *name = quote_ps_name (tab[i] != NULL ? tab[i] : ".notdef");
- fprintf (x->file, "%s\n", name);
- free (name);
- free (tab[i]);
- }
- fputs ("] RF\n", x->file);
-
- if (freaderror (file) != 0)
- error (errno, 0, _("closing Postscript encoding \"%s\""),
- font->encoding_fn);
-}
-
-/* PostScript driver class. */
-const struct outp_class postscript_class =
-{
- "postscript",
- 0,
-
- ps_open_driver,
- ps_close_driver,
-
- ps_open_page,
- ps_close_page,
- NULL,
-
- ps_submit,
-
- ps_line,
- ps_text_metrics,
- ps_text_draw,
-
- ps_chart_initialise,
- ps_chart_finalise
-};
#include <data/settings.h>
+#include "error.h"
#include "minmax.h"
#include "xalloc.h"
#define _(msgid) gettext (msgid)
\f
const struct som_table_class tab_table_class;
-static char *command_name;
/* Returns the font to use for a cell with the given OPTIONS. */
static enum outp_font
/* Creates a table with NC columns and NR rows. */
struct tab_table *
-tab_create (int nc, int nr, int reallocable UNUSED)
+tab_create (int nc, int nr)
{
struct tab_table *t;
t = pool_create_container (struct tab_table, container);
+ t->ref_cnt = 1;
t->col_style = TAB_COL_NONE;
- t->col_group = 0;
t->title = NULL;
t->flags = SOMF_NONE;
t->nr = nr;
memset (t->rv, UCHAR_MAX, nr * (nc + 1));
t->dim = NULL;
- t->w = t->h = NULL;
t->col_ofs = t->row_ofs = 0;
return t;
}
-/* Destroys table T. */
+/* Increases T's reference count and, if this causes T's
+ reference count to reach 0, destroys T. */
void
tab_destroy (struct tab_table *t)
{
- assert (t != NULL);
+ assert (t->ref_cnt > 0);
+ if (--t->ref_cnt > 0)
+ return;
+ if (t->dim_free != NULL)
+ t->dim_free (t->dim_aux);
free (t->title);
pool_destroy (t->container);
}
+/* Increases T's reference count. */
+void
+tab_ref (struct tab_table *t)
+{
+ assert (t->ref_cnt > 0);
+ t->ref_cnt++;
+}
+
/* Sets the width and height of a table, in columns and rows,
respectively. Use only to reduce the size of a table, since it
does not change the amount of allocated memory. */
}
if (nr != -1)
{
- assert (nr + t->row_ofs <= t->nr);
+ assert (nr + t->row_ofs <= tab_nr (t));
t->nr = nr + t->row_ofs;
}
}
tab_offset (t, 0, 0);
if (nc == -1)
- nc = t->nc;
+ nc = tab_nc (t);
if (nr == -1)
- nr = t->nr;
+ nr = tab_nr (t);
- assert (nc == t->nc);
+ assert (nc == tab_nc (t));
if (nc > t->cf)
{
- int mr1 = MIN (nr, t->nr);
- int mc1 = MIN (nc, t->nc);
+ int mr1 = MIN (nr, tab_nr (t));
+ int mc1 = MIN (nc, tab_nc (t));
struct substring *new_cc;
unsigned char *new_ct;
new_ct = pool_malloc (t->container, nr * nc);
for (r = 0; r < mr1; r++)
{
- memcpy (&new_cc[r * nc], &t->cc[r * t->nc], mc1 * sizeof *t->cc);
- memcpy (&new_ct[r * nc], &t->ct[r * t->nc], mc1);
- memset (&new_ct[r * nc + t->nc], TAB_EMPTY, nc - t->nc);
+ memcpy (&new_cc[r * nc], &t->cc[r * tab_nc (t)], mc1 * sizeof *t->cc);
+ memcpy (&new_ct[r * nc], &t->ct[r * tab_nc (t)], mc1);
+ memset (&new_ct[r * nc + tab_nc (t)], TAB_EMPTY, nc - tab_nc (t));
}
pool_free (t->container, t->cc);
pool_free (t->container, t->ct);
t->ct = new_ct;
t->cf = nc;
}
- else if (nr != t->nr)
+ else if (nr != tab_nr (t))
{
t->cc = pool_nrealloc (t->container, t->cc, nr * nc, sizeof *t->cc);
t->ct = pool_realloc (t->container, t->ct, nr * nc);
t->rh = pool_nrealloc (t->container, t->rh, nc, nr + 1);
t->rv = pool_nrealloc (t->container, t->rv, nr, nc + 1);
- if (nr > t->nr)
+ if (nr > tab_nr (t))
{
- memset (&t->rh[nc * (t->nr + 1)], TAL_0, (nr - t->nr) * nc);
- memset (&t->rv[(nc + 1) * t->nr], UCHAR_MAX,
- (nr - t->nr) * (nc + 1));
+ memset (&t->rh[nc * (tab_nr (t) + 1)], TAL_0, (nr - tab_nr (t)) * nc);
+ memset (&t->rv[(nc + 1) * tab_nr (t)], UCHAR_MAX,
+ (nr - tab_nr (t)) * (nc + 1));
}
}
- memset (&t->ct[nc * t->nr], TAB_EMPTY, nc * (nr - t->nr));
+ memset (&t->ct[nc * tab_nr (t)], TAB_EMPTY, nc * (nr - tab_nr (t)));
t->nr = nr;
t->nc = nc;
/* Set up table T so that, when it is an appropriate size, it will be
displayed across the page in columns.
- STYLE is a TAB_COL_* constant. GROUP is the number of rows to take
- as a unit. */
+ STYLE is a TAB_COL_* constant. */
void
-tab_columns (struct tab_table *t, int style, int group)
+tab_columns (struct tab_table *t, int style)
{
assert (t != NULL);
t->col_style = style;
- t->col_group = group;
}
\f
/* Rules. */
assert (t != NULL);
#if DEBUGGING
- if (x + t->col_ofs < 0 || x + t->col_ofs > t->nc
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
+ if (x + t->col_ofs < 0 || x + t->col_ofs > tab_nc (t)
+ || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
+ || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
{
printf (_("bad vline: x=%d+%d=%d y=(%d+%d=%d,%d+%d=%d) in "
"table size (%d,%d)\n"),
x, t->col_ofs, x + t->col_ofs,
y1, t->row_ofs, y1 + t->row_ofs,
y2, t->row_ofs, y2 + t->row_ofs,
- t->nc, t->nr);
+ tab_nc (t), tab_nr (t));
return;
}
#endif
y2 += t->row_ofs;
assert (x > 0);
- assert (x < t->nc);
+ assert (x < tab_nc (t));
assert (y1 >= 0);
assert (y2 >= y1);
- assert (y2 <= t->nr);
+ assert (y2 <= tab_nr (t));
if (style != -1)
{
y += t->row_ofs;
assert (y >= 0);
- assert (y <= t->nr);
+ assert (y <= tab_nr (t));
assert (x2 >= x1 );
assert (x1 >= 0 );
- assert (x2 < t->nc);
+ assert (x2 < tab_nc (t));
if (style != -1)
{
assert (t != NULL);
#if DEBUGGING
- if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= t->nc
- || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= t->nc
- || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= t->nr
- || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= t->nr)
+ if (x1 + t->col_ofs < 0 || x1 + t->col_ofs >= tab_nc (t)
+ || x2 + t->col_ofs < 0 || x2 + t->col_ofs >= tab_nc (t)
+ || y1 + t->row_ofs < 0 || y1 + t->row_ofs >= tab_nr (t)
+ || y2 + t->row_ofs < 0 || y2 + t->row_ofs >= tab_nr (t))
{
printf (_("bad box: (%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) "
"in table size (%d,%d)\n"),
y1, t->row_ofs, y1 + t->row_ofs,
x2, t->col_ofs, x2 + t->col_ofs,
y2, t->row_ofs, y2 + t->row_ofs,
- t->nc, t->nr);
+ tab_nc (t), tab_nr (t));
NOT_REACHED ();
}
#endif
assert (y2 >= y1);
assert (x1 >= 0);
assert (y1 >= 0);
- assert (x2 < t->nc);
- assert (y2 < t->nr);
+ assert (x2 < tab_nc (t));
+ assert (y2 < tab_nr (t));
if (f_h != -1)
{
va_end (args);
}
-/* Set DIM_FUNC as the dimension function for table T. */
+/* Set DIM_FUNC, which will be passed auxiliary data AUX, as the
+ dimension function for table T.
+
+ DIM_FUNC must not assume that it is called from the same
+ context as tab_dim; for example, table T might be kept in
+ memory and, thus, DIM_FUNC might be called after the currently
+ running command completes. If it is non-null, FREE_FUNC is
+ called when the table is destroyed, to allow any data
+ allocated for use by DIM_FUNC to be freed. */
void
-tab_dim (struct tab_table *t, tab_dim_func *dim_func, void *aux)
+tab_dim (struct tab_table *t,
+ tab_dim_func *dim_func, tab_dim_free_func *free_func, void *aux)
{
- assert (t != NULL && t->dim == NULL);
+ assert (t->dim == NULL);
t->dim = dim_func;
+ t->dim_free = free_func;
t->dim_aux = aux;
}
wrapping. The width will be no larger than the page width minus
left and right rule widths. */
int
-tab_natural_width (struct tab_table *t, struct outp_driver *d, int c)
+tab_natural_width (const struct tab_rendering *r, int col)
{
- int width;
+ const struct tab_table *t = r->table;
+ int width, row, max_width;
- assert (t != NULL && c >= 0 && c < t->nc);
- {
- int r;
+ assert (col >= 0 && col < tab_nc (t));
- for (width = r = 0; r < t->nr; r++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[c + r * t->cf];
- int w;
+ width = 0;
+ for (row = 0; row < tab_nr (t); row++)
+ {
+ struct outp_text text;
+ unsigned char opt = t->ct[col + row * t->cf];
+ int w;
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
+ if (opt & (TAB_JOIN | TAB_EMPTY))
+ continue;
- text.string = t->cc[c + r * t->cf];
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = text.v = INT_MAX;
+ text.string = t->cc[col + row * t->cf];
+ text.justification = OUTP_LEFT;
+ text.font = options_to_font (opt);
+ text.h = text.v = INT_MAX;
- d->class->text_metrics (d, &text, &w, NULL);
- if (w > width)
- width = w;
- }
- }
+ r->driver->class->text_metrics (r->driver, &text, &w, NULL);
+ if (w > width)
+ width = w;
+ }
if (width == 0)
{
/* FIXME: This is an ugly kluge to compensate for the fact
that we don't let joined cells contribute to column
widths. */
- width = d->prop_em_width * 8;
+ width = r->driver->prop_em_width * 8;
}
- {
- const int clamp = d->width - t->wrv[0] - t->wrv[t->nc];
-
- if (width > clamp)
- width = clamp;
- }
-
- return width;
+ max_width = r->driver->width - r->wrv[0] - r->wrv[tab_nc (t)];
+ return MIN (width, max_width);
}
/* Returns the natural height of row R in table T for driver D, that
is, the minimum height necessary to display the information in the
cell at the widths set for each column. */
int
-tab_natural_height (struct tab_table *t, struct outp_driver *d, int r)
+tab_natural_height (const struct tab_rendering *r, int row)
{
- int height;
+ const struct tab_table *t = r->table;
+ int height, col;
- assert (t != NULL && r >= 0 && r < t->nr);
+ assert (row >= 0 && row < tab_nr (t));
- {
- int c;
-
- for (height = d->font_height, c = 0; c < t->nc; c++)
- {
- struct outp_text text;
- unsigned char opt = t->ct[c + r * t->cf];
- int h;
-
- if (opt & (TAB_JOIN | TAB_EMPTY))
- continue;
-
- text.string = t->cc[c + r * t->cf];
- text.justification = OUTP_LEFT;
- text.font = options_to_font (opt);
- text.h = t->w[c];
- text.v = INT_MAX;
- d->class->text_metrics (d, &text, NULL, &h);
-
- if (h > height)
- height = h;
- }
- }
+ height = r->driver->font_height;
+ for (col = 0; col < tab_nc (t); col++)
+ {
+ struct outp_text text;
+ unsigned char opt = t->ct[col + row * t->cf];
+ int h;
+
+ if (opt & (TAB_JOIN | TAB_EMPTY))
+ continue;
+
+ text.string = t->cc[col + row * t->cf];
+ text.justification = OUTP_LEFT;
+ text.font = options_to_font (opt);
+ text.h = r->w[col];
+ text.v = INT_MAX;
+ r->driver->class->text_metrics (r->driver, &text, NULL, &h);
+
+ if (h > height)
+ height = h;
+ }
return height;
}
/* Callback function to set all columns and rows to their natural
dimensions. Not really meant to be called directly. */
void
-tab_natural_dimensions (struct tab_table *t, struct outp_driver *d,
- void *aux UNUSED)
+tab_natural_dimensions (struct tab_rendering *r, void *aux UNUSED)
{
+ const struct tab_table *t = r->table;
int i;
- assert (t != NULL);
-
- for (i = 0; i < t->nc; i++)
- t->w[i] = tab_natural_width (t, d, i);
+ for (i = 0; i < tab_nc (t); i++)
+ r->w[i] = tab_natural_width (r, i);
- for (i = 0; i < t->nr; i++)
- t->h[i] = tab_natural_height (t, d, i);
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = tab_natural_height (r, i);
}
\f
assert (table != NULL && v != NULL && f != NULL);
#if DEBUGGING
if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
printf ("tab_value(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
"(%d,%d)\n",
c, table->col_ofs, c + table->col_ofs,
r, table->row_ofs, r + table->row_ofs,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
assert (table != NULL && w <= 40);
assert (c >= 0);
- assert (c < table->nc);
+ assert (c < tab_nc (table));
assert (r >= 0);
- assert (r < table->nr);
+ assert (r < tab_nr (table));
f = fmt_for_output (FMT_F, w, d);
#if DEBUGGING
if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
printf ("tab_fixed(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
"(%d,%d)\n",
c, table->col_ofs, c + table->col_ofs,
r, table->row_ofs, r + table->row_ofs,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
assert (table != NULL);
assert (c >= 0);
- assert (c < table->nc);
+ assert (c < tab_nc (table));
assert (r >= 0);
- assert (r < table->nr);
+ assert (r < tab_nr (table));
if ( fmt == NULL)
fmt = settings_get_format ();
#if DEBUGGING
if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
printf ("tab_double(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
"(%d,%d)\n",
c, table->col_ofs, c + table->col_ofs,
r, table->row_ofs, r + table->row_ofs,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
static void
do_tab_text (struct tab_table *table, int c, int r, unsigned opt, char *text)
{
- assert (c >= 0);
- assert (r >= 0);
- assert (c < table->nc);
- assert (r < table->nr);
+ assert (c >= 0 );
+ assert (r >= 0 );
+ assert (c < tab_nc (table));
+ assert (r < tab_nr (table));
#if DEBUGGING
if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
+ || c + table->col_ofs >= tab_nc (table)
+ || r + table->row_ofs >= tab_nr (table))
{
printf ("tab_text(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
"(%d,%d)\n",
c, table->col_ofs, c + table->col_ofs,
r, table->row_ofs, r + table->row_ofs,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
assert (y1 + table->row_ofs >= 0);
assert (y2 >= y1);
assert (x2 >= x1);
- assert (y2 + table->row_ofs < table->nr);
- assert (x2 + table->col_ofs < table->nc);
+ assert (y2 + table->row_ofs < tab_nr (table));
+ assert (x2 + table->col_ofs < tab_nc (table));
#if DEBUGGING
- if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= table->nc
- || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= table->nr
- || x2 < x1 || x2 + table->col_ofs >= table->nc
- || y2 < y2 || y2 + table->row_ofs >= table->nr)
+ if (x1 + table->col_ofs < 0 || x1 + table->col_ofs >= tab_nc (table)
+ || y1 + table->row_ofs < 0 || y1 + table->row_ofs >= tab_nr (table)
+ || x2 < x1 || x2 + table->col_ofs >= tab_nc (table)
+ || y2 < y2 || y2 + table->row_ofs >= tab_nr (table))
{
printf ("tab_joint_text(): bad cell "
"(%d+%d=%d,%d+%d=%d)-(%d+%d=%d,%d+%d=%d) in table size (%d,%d)\n",
y1, table->row_ofs, y1 + table->row_ofs,
x2, table->col_ofs, x2 + table->col_ofs,
y2, table->row_ofs, y2 + table->row_ofs,
- table->nc, table->nr);
+ tab_nc (table), tab_nr (table));
return;
}
#endif
tab_box (table, -1, -1, TAL_0, TAL_0, x1, y1, x2, y2);
j = pool_alloc (table->container, sizeof *j);
- j->hit = 0;
j->x1 = x1 + table->col_ofs;
j->y1 = y1 + table->row_ofs;
j->x2 = ++x2 + table->col_ofs;
pool_vasprintf (table->container, format, args));
va_end (args);
}
-
-/* Sets cell (C,R) in TABLE, with options OPT, to contents STRING. */
-void
-tab_raw (struct tab_table *table, int c, int r, unsigned opt,
- struct substring *string)
-{
- assert (table != NULL && string != NULL);
-
-#if DEBUGGING
- if (c + table->col_ofs < 0 || r + table->row_ofs < 0
- || c + table->col_ofs >= table->nc
- || r + table->row_ofs >= table->nr)
- {
- printf ("tab_raw(): bad cell (%d+%d=%d,%d+%d=%d) in table size "
- "(%d,%d)\n",
- c, table->col_ofs, c + table->col_ofs,
- r, table->row_ofs, r + table->row_ofs,
- table->nc, table->nr);
- return;
- }
-#endif
-
- table->cc[c + r * table->cf] = *string;
- table->ct[c + r * table->cf] = opt;
-}
\f
/* Miscellaneous. */
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-nowrap_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+nowrap_dim (struct tab_rendering *r, void *aux UNUSED)
{
- t->w[0] = tab_natural_width (t, d, 0);
- t->h[0] = d->font_height;
+ r->w[0] = tab_natural_width (r, 0);
+ r->h[0] = r->driver->font_height;
}
/* Sets the widths of all the columns and heights of all the rows in
table T for driver D. */
static void
-wrap_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
+wrap_dim (struct tab_rendering *r, void *aux UNUSED)
{
- t->w[0] = tab_natural_width (t, d, 0);
- t->h[0] = tab_natural_height (t, d, 0);
+ r->w[0] = tab_natural_width (r, 0);
+ r->h[0] = tab_natural_height (r, 0);
}
static void
{
do_tab_text (t, 0, 0, options, text);
tab_flags (t, SOMF_NO_TITLE | SOMF_NO_SPACING);
- tab_dim (t, options & TAT_NOWRAP ? nowrap_dim : wrap_dim, NULL);
+ tab_dim (t, options & TAT_NOWRAP ? nowrap_dim : wrap_dim, NULL, NULL);
tab_submit (t);
}
void
tab_output_text (int options, const char *text)
{
- struct tab_table *table = tab_create (1, 1, 0);
+ struct tab_table *table = tab_create (1, 1);
do_tab_output_text (table, options, pool_strdup (table->container, text));
}
struct tab_table *table;
va_list args;
- table = tab_create (1, 1, 0);
+ table = tab_create (1, 1);
va_start (args, format);
do_tab_output_text (table, options,
assert (t != NULL);
#if DEBUGGING
- if (row < -1 || row > t->nr)
+ if (row < -1 || row > tab_nr (t))
{
- printf ("tab_offset(): row=%d in %d-row table\n", row, t->nr);
+ printf ("tab_offset(): row=%d in %d-row table\n", row, tab_nr (t));
NOT_REACHED ();
}
- if (col < -1 || col > t->nc)
+ if (col < -1 || col > tab_nc (t))
{
- printf ("tab_offset(): col=%d in %d-column table\n", col, t->nc);
+ printf ("tab_offset(): col=%d in %d-column table\n", col, tab_nc (t));
NOT_REACHED ();
}
#endif
assert (t != NULL);
t->cc += t->cf;
t->ct += t->cf;
- if (++t->row_ofs >= t->nr)
- tab_realloc (t, -1, t->nr * 4 / 3);
+ if (++t->row_ofs >= tab_nr (t))
+ tab_realloc (t, -1, tab_nr (t) * 4 / 3);
}
\f
-static struct tab_table *t;
-static struct outp_driver *d;
-static int tab_hit;
+/* Return the number of columns and rows in the table into N_COLUMNS
+ and N_ROWS, respectively. */
+static void
+tabi_count (struct som_entity *t_, int *n_columns, int *n_rows)
+{
+ struct tab_table *t = t_->ext;
+ *n_columns = t->nc;
+ *n_rows = t->nr;
+}
-/* Set the current table to TABLE. */
+/* Return the column style for this table into STYLE. */
static void
-tabi_table (struct som_entity *table)
+tabi_columns (struct som_entity *t_, int *style)
{
- assert (table != NULL);
- assert (table->type == SOM_TABLE);
+ struct tab_table *t = t_->ext;
+ *style = t->col_style;
+}
- t = table->ext;
- tab_offset (t, 0, 0);
+/* Return the number of header rows/columns on the left, right, top,
+ and bottom sides into HL, HR, HT, and HB, respectively. */
+static void
+tabi_headers (struct som_entity *t_, int *hl, int *hr, int *ht, int *hb)
+{
+ struct tab_table *t = t_->ext;
+ *hl = t->l;
+ *hr = t->r;
+ *ht = t->t;
+ *hb = t->b;
+}
- assert (t->w == NULL && t->h == NULL);
- t->w = pool_nalloc (t->container, t->nc, sizeof *t->w);
- t->h = pool_nalloc (t->container, t->nr, sizeof *t->h);
- t->hrh = pool_nmalloc (t->container, t->nr + 1, sizeof *t->hrh);
- t->wrv = pool_nmalloc (t->container, t->nc + 1, sizeof *t->wrv);
+/* Return flags set for the current table into FLAGS. */
+static void
+tabi_flags (struct som_entity *t_, unsigned *flags)
+{
+ struct tab_table *t = t_->ext;
+ *flags = t->flags;
}
/* Returns the line style to use for spacing purposes for a rule
}
}
-/* Set the current output device to DRIVER. */
-static void
-tabi_driver (struct outp_driver *driver)
+static void *
+tabi_render_init (struct som_entity *t_, struct outp_driver *driver,
+ int hl, int hr, int ht, int hb)
{
- int c, r;
+ const struct tab_table *t = t_->ext;
+ struct tab_rendering *r;
+ int col, row;
int i;
- assert (driver != NULL);
- d = driver;
+ tab_offset (t_->ext, 0, 0);
+
+ r = xmalloc (sizeof *r);
+ r->table = t;
+ r->driver = driver;
+ r->w = xnmalloc (tab_nc (t), sizeof *r->w);
+ r->h = xnmalloc (tab_nr (t), sizeof *r->h);
+ r->hrh = xnmalloc (tab_nr (t) + 1, sizeof *r->hrh);
+ r->wrv = xnmalloc (tab_nc (t) + 1, sizeof *r->wrv);
+ r->l = hl;
+ r->r = hr;
+ r->t = ht;
+ r->b = hb;
/* Figure out sizes of rules. */
- for (r = 0; r <= t->nr; r++)
+ for (row = 0; row <= tab_nr (t); row++)
{
int width = 0;
- for (c = 0; c < t->nc; c++)
+ for (col = 0; col < tab_nc (t); col++)
{
- unsigned char rh = t->rh[c + r * t->cf];
+ unsigned char rh = t->rh[col + row * t->cf];
int w = driver->horiz_line_width[rule_to_spacing_type (rh)];
if (w > width)
width = w;
}
- t->hrh[r] = width;
+ r->hrh[row] = width;
}
- for (c = 0; c <= t->nc; c++)
+ for (col = 0; col <= tab_nc (t); col++)
{
int width = 0;
- for (r = 0; r < t->nr; r++)
+ for (row = 0; row < tab_nr (t); row++)
{
- unsigned char *rv = &t->rv[c + r * (t->cf + 1)];
+ unsigned char *rv = &t->rv[col + row * (t->cf + 1)];
int w;
if (*rv == UCHAR_MAX)
- *rv = c != 0 && c != t->nc ? TAL_GAP : TAL_0;
+ *rv = col != 0 && col != tab_nc (t) ? TAL_GAP : TAL_0;
w = driver->vert_line_width[rule_to_spacing_type (*rv)];
if (w > width)
width = w;
}
- t->wrv[c] = width;
+ r->wrv[col] = width;
}
-#if DEBUGGING
- for (i = 0; i < t->nr; i++)
- t->h[i] = -1;
- for (i = 0; i < t->nc; i++)
- t->w[i] = -1;
-#endif
-
- assert (t->dim != NULL);
- t->dim (t, d, t->dim_aux);
+ /* Determine row heights and columns widths. */
+ for (i = 0; i < tab_nr (t); i++)
+ r->h[i] = -1;
+ for (i = 0; i < tab_nc (t); i++)
+ r->w[i] = -1;
-#if DEBUGGING
- {
- int error = 0;
-
- for (i = 0; i < t->nr; i++)
- {
- if (t->h[i] == -1)
- {
- printf ("Table row %d height not initialized.\n", i);
- error = 1;
- }
- assert (t->h[i] > 0);
- }
+ t->dim (r, t->dim_aux);
- for (i = 0; i < t->nc; i++)
- {
- if (t->w[i] == -1)
- {
- printf ("Table column %d width not initialized.\n", i);
- error = 1;
- }
- assert (t->w[i] > 0);
- }
- }
-#endif
+ for (i = 0; i < tab_nr (t); i++)
+ if (r->h[i] < 0)
+ error (0, 0, "height of table row %d is %d (not initialized?)",
+ i, r->h[i]);
+ for (i = 0; i < tab_nc (t); i++)
+ if (r->w[i] < 0)
+ error (0, 0, "width of table column %d is %d (not initialized?)",
+ i, r->w[i]);
/* Add up header sizes. */
- for (i = 0, t->wl = t->wrv[0]; i < t->l; i++)
- t->wl += t->w[i] + t->wrv[i + 1];
- for (i = 0, t->ht = t->hrh[0]; i < t->t; i++)
- t->ht += t->h[i] + t->hrh[i + 1];
- for (i = t->nc - t->r, t->wr = t->wrv[i]; i < t->nc; i++)
- t->wr += t->w[i] + t->wrv[i + 1];
- for (i = t->nr - t->b, t->hb = t->hrh[i]; i < t->nr; i++)
- t->hb += t->h[i] + t->hrh[i + 1];
+ for (i = 0, r->wl = r->wrv[0]; i < r->l; i++)
+ r->wl += r->w[i] + r->wrv[i + 1];
+ for (i = 0, r->ht = r->hrh[0]; i < r->t; i++)
+ r->ht += r->h[i] + r->hrh[i + 1];
+ for (i = tab_nc (t) - r->r, r->wr = r->wrv[i]; i < tab_nc (t); i++)
+ r->wr += r->w[i] + r->wrv[i + 1];
+ for (i = tab_nr (t) - r->b, r->hb = r->hrh[i]; i < tab_nr (t); i++)
+ r->hb += r->h[i] + r->hrh[i + 1];
/* Title. */
if (!(t->flags & SOMF_NO_TITLE))
- t->ht += d->font_height;
+ r->ht += driver->font_height;
+
+ return r;
}
-/* Return the number of columns and rows in the table into N_COLUMNS
- and N_ROWS, respectively. */
static void
-tabi_count (int *n_columns, int *n_rows)
+tabi_render_free (void *r_)
{
- assert (n_columns != NULL && n_rows != NULL);
- *n_columns = t->nc;
- *n_rows = t->nr;
-}
+ struct tab_rendering *r = r_;
-static void tabi_cumulate (int cumtype, int start, int *end, int max, int *actual);
+ free (r->w);
+ free (r->h);
+ free (r->hrh);
+ free (r->wrv);
+ free (r);
+}
/* Return the horizontal and vertical size of the entire table,
including headers, for the current output device, into HORIZ and
VERT. */
static void
-tabi_area (int *horiz, int *vert)
+tabi_area (void *r_, int *horiz, int *vert)
{
- assert (horiz != NULL && vert != NULL);
-
- {
- int w, c;
-
- for (c = t->l + 1, w = t->wl + t->wr + t->w[t->l];
- c < t->nc - t->r; c++)
- w += t->w[c] + t->wrv[c];
- *horiz = w;
- }
-
- {
- int h, r;
- for (r = t->t + 1, h = t->ht + t->hb + t->h[t->t];
- r < t->nr - t->b; r++)
- h += t->h[r] + t->hrh[r];
- *vert = h;
- }
-}
-
-/* Return the column style for this table into STYLE. */
-static void
-tabi_columns (int *style)
-{
- assert (style != NULL);
- *style = t->col_style;
-}
-
-/* Return the number of header rows/columns on the left, right, top,
- and bottom sides into HL, HR, HT, and HB, respectively. */
-static void
-tabi_headers (int *hl, int *hr, int *ht, int *hb)
-{
- assert (hl != NULL && hr != NULL && ht != NULL && hb != NULL);
- *hl = t->l;
- *hr = t->r;
- *ht = t->t;
- *hb = t->b;
+ struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ int width, col;
+ int height, row;
+
+ width = 0;
+ for (col = r->l + 1, width = r->wl + r->wr + r->w[tab_l (t)];
+ col < tab_nc (t) - r->r; col++)
+ width += r->w[col] + r->wrv[col];
+ *horiz = width;
+
+ height = 0;
+ for (row = r->t + 1, height = r->ht + r->hb + r->h[tab_t (t)];
+ row < tab_nr (t) - tab_b (t); row++)
+ height += r->h[row] + r->hrh[row];
+ *vert = height;
}
/* Determines the number of rows or columns (including appropriate
space the selected rows/columns (including appropriate headers)
filled. */
static void
-tabi_cumulate (int cumtype, int start, int *end, int max, int *actual)
+tabi_cumulate (void *r_, int cumtype, int start, int *end,
+ int max, int *actual)
{
- int n;
- int *d;
- int *r;
+ const struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ int limit;
+ int *cells, *rules;
int total;
+ int idx;
assert (end != NULL && (cumtype == SOM_ROWS || cumtype == SOM_COLUMNS));
if (cumtype == SOM_ROWS)
{
- assert (start >= 0 && start < t->nr);
- n = t->nr - t->b;
- d = &t->h[start];
- r = &t->hrh[start + 1];
- total = t->ht + t->hb;
+ assert (start >= 0 && start < tab_nr (t));
+ limit = tab_nr (t) - r->b;
+ cells = &r->h[start];
+ rules = &r->hrh[start + 1];
+ total = r->ht + r->hb;
}
else
{
- assert (start >= 0 && start < t->nc);
- n = t->nc - t->r;
- d = &t->w[start];
- r = &t->wrv[start + 1];
- total = t->wl + t->wr;
+ assert (start >= 0 && start < tab_nc (t));
+ limit = tab_nc (t) - tab_r (t);
+ cells = &r->w[start];
+ rules = &r->wrv[start + 1];
+ total = r->wl + r->wr;
}
- total += *d++;
+ total += *cells++;
if (total > max)
{
if (end)
return;
}
- {
- int x;
-
- for (x = start + 1; x < n; x++)
- {
- int amt = *d++ + *r++;
-
- total += amt;
- if (total > max)
- {
- total -= amt;
- break;
- }
- }
-
- if (end)
- *end = x;
-
- if (actual)
- *actual = total;
- }
-}
-
-/* Return flags set for the current table into FLAGS. */
-static void
-tabi_flags (unsigned *flags)
-{
- assert (flags != NULL);
- *flags = t->flags;
-}
-
-/* Returns true if the table will fit in the given page WIDTH,
- false otherwise. */
-static bool
-tabi_fits_width (int width)
-{
- int i;
-
- for (i = t->l; i < t->nc - t->r; i++)
- if (t->wl + t->wr + t->w[i] > width)
- return false;
-
- return true;
-}
+ for (idx = start + 1; idx < limit; idx++)
+ {
+ int amt = *cells++ + *rules++;
-/* Returns true if the table will fit in the given page LENGTH,
- false otherwise. */
-static bool
-tabi_fits_length (int length)
-{
- int i;
+ total += amt;
+ if (total > max)
+ {
+ total -= amt;
+ break;
+ }
+ }
- for (i = t->t; i < t->nr - t->b; i++)
- if (t->ht + t->hb + t->h[i] > length)
- return false;
+ if (end)
+ *end = idx;
- return true;
-}
-
-/* Sets the number of header rows/columns on the left, right, top,
- and bottom sides to HL, HR, HT, and HB, respectively. */
-static void
-tabi_set_headers (int hl, int hr, int ht, int hb)
-{
- t->l = hl;
- t->r = hr;
- t->t = ht;
- t->b = hb;
+ if (actual)
+ *actual = total;
}
/* Render title for current table, with major index X and minor index
Y. Y may be zero, or X and Y may be zero, but X should be nonzero
if Y is nonzero. */
static void
-tabi_title (int x, int y)
+tabi_title (void *r_, int x, int y, int table_num, int subtable_num,
+ const char *command_name)
{
- char buf[1024];
- char *cp;
+ const struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ struct outp_text text;
+ struct string title;
if (t->flags & SOMF_NO_TITLE)
return;
- cp = spprintf (buf, "%d.%d", table_num, subtable_num);
+ ds_init_empty (&title);
+ ds_put_format (&title,"%d.%d", table_num, subtable_num);
if (x && y)
- cp = spprintf (cp, "(%d:%d)", x, y);
+ ds_put_format (&title, "(%d:%d)", x, y);
else if (x)
- cp = spprintf (cp, "(%d)", x);
+ ds_put_format (&title, "(%d)", x);
if (command_name != NULL)
- cp = spprintf (cp, " %s", command_name);
- cp = stpcpy (cp, ". ");
+ ds_put_format (&title, " %s", command_name);
+ ds_put_cstr (&title, ". ");
if (t->title != NULL)
- {
- size_t length = strlen (t->title);
- memcpy (cp, t->title, length);
- cp += length;
- }
- *cp = 0;
-
- {
- struct outp_text text;
-
- text.font = OUTP_PROPORTIONAL;
- text.justification = OUTP_LEFT;
- text.string = ss_buffer (buf, cp - buf);
- text.h = d->width;
- text.v = d->font_height;
- text.x = 0;
- text.y = d->cp_y;
- d->class->text_draw (d, &text);
- }
+ ds_put_cstr (&title, t->title);
+
+ text.font = OUTP_PROPORTIONAL;
+ text.justification = OUTP_LEFT;
+ text.string = ds_ss (&title);
+ text.h = r->driver->width;
+ text.v = r->driver->font_height;
+ text.x = 0;
+ text.y = r->driver->cp_y;
+ r->driver->class->text_draw (r->driver, &text);
+
+ ds_destroy (&title);
}
-static int render_strip (int x, int y, int r, int c1, int c2, int r1, int r2);
+static int render_strip (const struct tab_rendering *,
+ int x, int y, int r, int c1, int c2, int r1, int r2);
-/* Renders columns C0...C1, plus headers, of rows R0...R1,
- at the given vertical position Y.
- C0 and C1 count vertical rules as columns,
- but R0 and R1 do not count horizontal rules as rows.
- Returns the vertical position after rendering. */
-static int
-render_rows (int y, int c0, int c1, int r0, int r1)
+static void
+add_range (int ranges[][2], int *np, int start, int end)
{
- int r;
- for (r = r0; r < r1; r++)
+ int n = *np;
+ if (n == 0 || start > ranges[n - 1][1])
{
- int x = d->cp_x;
- x = render_strip (x, y, r, 0, t->l * 2 + 1, r0, r1);
- x = render_strip (x, y, r, c0 * 2 + 1, c1 * 2, r0, r1);
- x = render_strip (x, y, r, (t->nc - t->r) * 2, t->nc * 2 + 1, r0, r1);
- y += (r & 1) ? t->h[r / 2] : t->hrh[r / 2];
+ ranges[n][0] = start;
+ ranges[n][1] = end;
+ ++*np;
}
- return y;
+ else
+ ranges[n - 1][1] = end;
}
/* Draws table region (C0,R0)-(C1,R1), plus headers, at the
current position on the current output device. */
static void
-tabi_render (int c0, int r0, int c1, int r1)
+tabi_render (void *r_, int c0, int r0, int c1, int r1)
{
- int y;
+ const struct tab_rendering *r = r_;
+ const struct tab_table *t = r->table;
+ int rows[3][2], cols[3][2];
+ int n_row_ranges, n_col_ranges;
+ int y, i;
+
+ /* Rows to render, counting horizontal rules as rows. */
+ n_row_ranges = 0;
+ add_range (rows, &n_row_ranges, 0, tab_t (t) * 2 + 1);
+ add_range (rows, &n_row_ranges, r0 * 2 + 1, r1 * 2);
+ add_range (rows, &n_row_ranges, (tab_nr (t) - tab_b (t)) * 2,
+ tab_nr (t) * 2 + 1);
+
+ /* Columns to render, counting vertical rules as columns. */
+ n_col_ranges = 0;
+ add_range (cols, &n_col_ranges, 0, r->l * 2 + 1);
+ add_range (cols, &n_col_ranges, c0 * 2 + 1, c1 * 2);
+ add_range (cols, &n_col_ranges, (tab_nc (t) - r->r) * 2, tab_nc (t) * 2 + 1);
+
+ y = r->driver->cp_y;
+ if (!(t->flags & SOMF_NO_TITLE))
+ y += r->driver->font_height;
+ for (i = 0; i < n_row_ranges; i++)
+ {
+ int row;
- tab_hit++;
+ for (row = rows[i][0]; row < rows[i][1]; row++)
+ {
+ int x, j;
- y = d->cp_y;
- if (!(t->flags & SOMF_NO_TITLE))
- y += d->font_height;
+ x = r->driver->cp_x;
+ for (j = 0; j < n_col_ranges; j++)
+ x = render_strip (r, x, y, row,
+ cols[j][0], cols[j][1],
+ rows[i][0], rows[i][1]);
- y = render_rows (y, c0, c1, 0, t->t * 2 + 1);
- y = render_rows (y, c0, c1, r0 * 2 + 1, r1 * 2);
- y = render_rows (y, c0, c1, (t->nr - t->b) * 2, t->nr * 2 + 1);
+ y += (row & 1) ? r->h[row / 2] : r->hrh[row / 2];
+ }
+ }
}
const struct som_table_class tab_table_class =
{
- tabi_table,
- tabi_driver,
-
tabi_count,
- tabi_area,
- NULL,
- NULL,
tabi_columns,
- NULL,
tabi_headers,
- NULL,
- tabi_cumulate,
tabi_flags,
- tabi_fits_width,
- tabi_fits_length,
- NULL,
- NULL,
- tabi_set_headers,
+ tabi_render_init,
+ tabi_render_free,
+ tabi_area,
+ tabi_cumulate,
tabi_title,
tabi_render,
};
/* Returns the horizontal rule at the given column and row. */
static int
-get_hrule (int c, int r)
+get_hrule (const struct tab_table *t, int col, int row)
{
- return t->rh[c + r * t->cf];
+ return t->rh[col + row * t->cf];
}
/* Returns the vertical rule at the given column and row. */
static int
-get_vrule (int c, int r)
+get_vrule (const struct tab_table *t, int col, int row)
{
- return t->rv[c + r * (t->cf + 1)];
+ return t->rv[col + row * (t->cf + 1)];
}
/* Renders the horizontal rule at the given column and row
at (X,Y) on the page. */
static void
-render_horz_rule (int x, int y, int c, int r)
+render_horz_rule (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
- enum outp_line_style style = rule_to_draw_type (get_hrule (c, r));
+ enum outp_line_style style;
+ style = rule_to_draw_type (get_hrule (r->table, col, row));
if (style != OUTP_L_NONE)
- d->class->line (d, x, y, x + t->w[c], y + t->hrh[r],
- OUTP_L_NONE, style, OUTP_L_NONE, style);
+ r->driver->class->line (r->driver, x, y, x + r->w[col], y + r->hrh[row],
+ OUTP_L_NONE, style, OUTP_L_NONE, style);
}
/* Renders the vertical rule at the given column and row
at (X,Y) on the page. */
static void
-render_vert_rule (int x, int y, int c, int r)
+render_vert_rule (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
- enum outp_line_style style = rule_to_draw_type (get_vrule (c, r));
+ enum outp_line_style style;
+ style = rule_to_draw_type (get_vrule (r->table, col, row));
if (style != OUTP_L_NONE)
- d->class->line (d, x, y, x + t->wrv[c], y + t->h[r],
- style, OUTP_L_NONE, style, OUTP_L_NONE);
+ r->driver->class->line (r->driver, x, y, x + r->wrv[col], y + r->h[row],
+ style, OUTP_L_NONE, style, OUTP_L_NONE);
}
/* Renders the rule intersection at the given column and row
at (X,Y) on the page. */
static void
-render_rule_intersection (int x, int y, int c, int r)
+render_rule_intersection (const struct tab_rendering *r,
+ int x, int y, int col, int row)
{
+ const struct tab_table *t = r->table;
+
/* Bounds of intersection. */
int x0 = x;
int y0 = y;
- int x1 = x + t->wrv[c];
- int y1 = y + t->hrh[r];
+ int x1 = x + r->wrv[col];
+ int y1 = y + r->hrh[row];
/* Lines on each side of intersection. */
- int top = r > 0 ? get_vrule (c, r - 1) : TAL_0;
- int left = c > 0 ? get_hrule (c - 1, r) : TAL_0;
- int bottom = r < t->nr ? get_vrule (c, r) : TAL_0;
- int right = c < t->nc ? get_hrule (c, r) : TAL_0;
+ int top = row > 0 ? get_vrule (t, col, row - 1) : TAL_0;
+ int left = col > 0 ? get_hrule (t, col - 1, row) : TAL_0;
+ int bottom = row < tab_nr (t) ? get_vrule (t, col, row) : TAL_0;
+ int right = col < tab_nc (t) ? get_hrule (t, col, row) : TAL_0;
/* Output style for each line. */
enum outp_line_style o_top = rule_to_draw_type (top);
if (o_top != OUTP_L_NONE || o_left != OUTP_L_NONE
|| o_bottom != OUTP_L_NONE || o_right != OUTP_L_NONE)
- d->class->line (d, x0, y0, x1, y1, o_top, o_left, o_bottom, o_right);
+ r->driver->class->line (r->driver, x0, y0, x1, y1,
+ o_top, o_left, o_bottom, o_right);
}
/* Returns the width of columns C1...C2 exclusive,
including interior but not exterior rules. */
static int
-strip_width (int c1, int c2)
+strip_width (const struct tab_rendering *r, int c1, int c2)
{
int width = 0;
int c;
for (c = c1; c < c2; c++)
- width += t->w[c] + t->wrv[c + 1];
+ width += r->w[c] + r->wrv[c + 1];
if (c1 < c2)
- width -= t->wrv[c2];
+ width -= r->wrv[c2];
return width;
}
/* Returns the height of rows R1...R2 exclusive,
including interior but not exterior rules. */
static int
-strip_height (int r1, int r2)
+strip_height (const struct tab_rendering *r, int r1, int r2)
{
int height = 0;
- int r;
+ int row;
- for (r = r1; r < r2; r++)
- height += t->h[r] + t->hrh[r + 1];
+ for (row = r1; row < r2; row++)
+ height += r->h[row] + r->hrh[row + 1];
if (r1 < r2)
- height -= t->hrh[r2];
+ height -= r->hrh[r2];
return height;
}
page. Also renders joined cells that extend as far to the
right as C1 and as far down as R1. */
static void
-render_cell (int x, int y, int c, int r, int c1, int r1)
+render_cell (const struct tab_rendering *r,
+ int x, int y, int col, int row, int c1, int r1)
{
- const int index = c + (r * t->cf);
+ const struct tab_table *t = r->table;
+ const int index = col + (row * t->cf);
unsigned char type = t->ct[index];
struct substring *content = &t->cc[index];
text.font = options_to_font (type);
text.justification = translate_justification (type);
text.string = *content;
- text.h = t->w[c];
- text.v = t->h[r];
+ text.h = r->w[col];
+ text.v = r->h[row];
text.x = x;
text.y = y;
- d->class->text_draw (d, &text);
+ r->driver->class->text_draw (r->driver, &text);
}
}
else
struct tab_joined_cell *j
= (struct tab_joined_cell *) ss_data (*content);
- if (j->hit != tab_hit)
+ if (j->x1 == col && j->y1 == row)
{
- j->hit = tab_hit;
-
- if (j->x1 == c && j->y1 == r)
- {
- struct outp_text text;
- text.font = options_to_font (type);
- text.justification = translate_justification (type);
- text.string = j->contents;
- text.x = x;
- text.y = y;
- text.h = strip_width (j->x1, MIN (j->x2, c1));
- text.v = strip_height (j->y1, MIN (j->y2, r1));
- d->class->text_draw (d, &text);
- }
+ struct outp_text text;
+ text.font = options_to_font (type);
+ text.justification = translate_justification (type);
+ text.string = j->contents;
+ text.x = x;
+ text.y = y;
+ text.h = strip_width (r, j->x1, MIN (j->x2, c1));
+ text.v = strip_height (r, j->y1, MIN (j->y2, r1));
+ r->driver->class->text_draw (r->driver, &text);
}
}
}
/* Render contiguous strip consisting of columns C0...C1, exclusive,
- on row R, at (X,Y). Returns X position after rendering.
+ on row ROW, at (X,Y). Returns X position after rendering.
Also renders joined cells that extend beyond that strip,
cropping them to lie within rendering region (C0,R0)-(C1,R1).
C0 and C1 count vertical rules as columns.
- R counts horizontal rules as rows, but R0 and R1 do not. */
+ ROW counts horizontal rules as rows, but R0 and R1 do not. */
static int
-render_strip (int x, int y, int r, int c0, int c1, int r0 UNUSED, int r1)
+render_strip (const struct tab_rendering *r,
+ int x, int y, int row, int c0, int c1, int r0 UNUSED, int r1)
{
- int c;
+ int col;
- for (c = c0; c < c1; c++)
- if (c & 1)
+ for (col = c0; col < c1; col++)
+ if (col & 1)
{
- if (r & 1)
- render_cell (x, y, c / 2, r / 2, c1 / 2, r1);
+ if (row & 1)
+ render_cell (r, x, y, col / 2, row / 2, c1 / 2, r1);
else
- render_horz_rule (x, y, c / 2, r / 2);
- x += t->w[c / 2];
+ render_horz_rule (r, x, y, col / 2, row / 2);
+ x += r->w[col / 2];
}
else
{
- if (r & 1)
- render_vert_rule (x, y, c / 2, r / 2);
+ if (row & 1)
+ render_vert_rule (r, x, y, col / 2, row / 2);
else
- render_rule_intersection (x, y, c / 2, r / 2);
- x += t->wrv[c / 2];
+ render_rule_intersection (r, x, y, col / 2, row / 2);
+ x += r->wrv[col / 2];
}
return x;
}
-
-/* Sets COMMAND_NAME as the name of the current command,
- for embedding in output. */
-void
-tab_set_command_name (const char *command_name_)
-{
- free (command_name);
- command_name = command_name_ ? xstrdup (command_name_) : NULL;
-}
{
int x1, y1;
int x2, y2;
- int hit;
struct substring contents;
};
struct outp_driver;
struct tab_table;
-typedef void tab_dim_func (struct tab_table *, struct outp_driver *,
- void *aux);
+struct tab_rendering;
+
+typedef void tab_dim_func (struct tab_rendering *, void *aux);
+typedef void tab_dim_free_func (void *aux);
/* A table. */
struct tab_table
{
struct pool *container;
+ int ref_cnt; /* Reference count. */
/* Contents. */
int col_style; /* Columns: One of TAB_COL_*. */
- int col_group; /* Number of rows per column group. */
char *title; /* Table title. */
unsigned flags; /* SOMF_*. */
int nc, nr; /* Number of columns, rows. */
unsigned char *ct; /* Cell types; unsigned char[nr][nc]. */
unsigned char *rh; /* Horiz rules; unsigned char[nr+1][nc]. */
unsigned char *rv; /* Vert rules; unsigned char[nr][nc+1]. */
+
+ /* Calculating row and column dimensions. */
tab_dim_func *dim; /* Calculates cell widths and heights. */
+ tab_dim_free_func *dim_free; /* Frees space allocated for dim function. */
void *dim_aux; /* Auxiliary data for dim function. */
- /* Calculated during output. */
- int *w; /* Column widths; [nc]. */
- int *h; /* Row heights; [nr]. */
- int *hrh; /* Heights of horizontal rules; [nr+1]. */
- int *wrv; /* Widths of vertical rules; [nc+1]. */
- int wl, wr, ht, hb; /* Width/height of header rows/columns. */
-
/* Editing info. */
int col_ofs, row_ofs; /* X and Y offsets. */
};
-/* Number of rows in TABLE. */
-#define tab_nr(TABLE) ((TABLE)->nr)
-
-/* Number of columns in TABLE. */
-#define tab_nc(TABLE) ((TABLE)->nc)
+/* Number of rows or columns in TABLE. */
+static inline int tab_nr (const struct tab_table *table) { return table->nr; }
+static inline int tab_nc (const struct tab_table *table) { return table->nc; }
-/* Number of left header columns in TABLE. */
-#define tab_l(TABLE) ((TABLE)->l)
+/* Number of left/right/top/bottom header columns/rows in TABLE. */
+static inline int tab_l (const struct tab_table *table) { return table->l; }
+static inline int tab_r (const struct tab_table *table) { return table->r; }
+static inline int tab_t (const struct tab_table *table) { return table->t; }
+static inline int tab_b (const struct tab_table *table) { return table->b; }
-/* Number of right header columns in TABLE. */
-#define tab_r(TABLE) ((TABLE)->r)
+struct tab_rendering
+ {
+ const struct tab_table *table;
+ struct outp_driver *driver;
-/* Number of top header rows in TABLE. */
-#define tab_t(TABLE) ((TABLE)->t)
+ int *w; /* Column widths; [nc]. */
+ int *h; /* Row heights; [nr]. */
+ int *hrh; /* Heights of horizontal rules; [nr+1]. */
+ int *wrv; /* Widths of vertical rules; [nc+1]. */
-/* Number of bottom header rows in TABLE. */
-#define tab_b(TABLE) ((TABLE)->b)
+ /* These fields would be redundant with those in struct tab_table, except
+ that a table will be rendered with fewer header rows or columns than
+ requested when we are pressed for space. */
+ int l, r, t, b; /* Number of header rows/columns. */
+ int wl, wr, ht, hb; /* Width/height of header rows/columns. */
+ };
/* Tables. */
-struct tab_table *tab_create (int nc, int nr, int reallocable);
+struct tab_table *tab_create (int nc, int nr);
void tab_destroy (struct tab_table *);
+void tab_ref (struct tab_table *);
void tab_resize (struct tab_table *, int nc, int nr);
void tab_realloc (struct tab_table *, int nc, int nr);
void tab_headers (struct tab_table *, int l, int r, int t, int b);
-void tab_columns (struct tab_table *, int style, int group);
+void tab_columns (struct tab_table *, int style);
void tab_title (struct tab_table *, const char *, ...)
PRINTF_FORMAT (2, 3);
void tab_flags (struct tab_table *, unsigned);
/* Dimensioning. */
tab_dim_func tab_natural_dimensions;
-int tab_natural_width (struct tab_table *t, struct outp_driver *d, int c);
-int tab_natural_height (struct tab_table *t, struct outp_driver *d, int r);
-void tab_dim (struct tab_table *, tab_dim_func *, void *aux);
+int tab_natural_width (const struct tab_rendering *, int c);
+int tab_natural_height (const struct tab_rendering *, int r);
+void tab_dim (struct tab_table *,
+ tab_dim_func *, tab_dim_free_func *, void *aux);
/* Rules. */
void tab_hline (struct tab_table *, int style, int x1, int x2, int y);
unsigned opt, const char *, ...)
PRINTF_FORMAT (7, 8);
-/* Cell low-level access. */
-#define tab_alloc(TABLE, AMT) pool_alloc ((TABLE)->container, (AMT))
-void tab_raw (struct tab_table *, int c, int r, unsigned opt,
- struct substring *);
-
/* Editing. */
void tab_offset (struct tab_table *, int col, int row);
void tab_next_row (struct tab_table *);
void tab_output_text_format (int options, const char *, ...)
PRINTF_FORMAT (2, 3);
-/* Embedding the command name in the output. */
-void tab_set_command_name (const char *);
-
#endif /* tab_h */
## Process this file with automake to produce Makefile.in -*- makefile -*-
include $(top_srcdir)/src/ui/terminal/automake.mk
-if WITHGUI
+if HAVE_GUI
include $(top_srcdir)/src/ui/gui/automake.mk
endif
src/libpspp.la \
src/libpspp-core.la \
$(GTK_LIBS) \
+ $(CAIRO_LIBS) \
$(LIBINTL)
src_ui_gui_psppiredir = $(pkgdatadir)
som_flush ();
- psppire_output_window_reload ();
-
return retval;
}
#include <ctype.h>
#include <sys/types.h>
#include <regex.h>
+#include <libpspp/cast.h>
#include <libpspp/message.h>
#include <gtk/gtk.h>
static void
regexp_destroy (struct comparator *cmptr)
{
- struct regexp_comparator *rec = (struct regexp_comparator *) cmptr;
+ struct regexp_comparator *rec
+ = UP_CAST (cmptr, struct regexp_comparator, parent);
regfree (&rec->re);
}
static void
cmptr_value_destroy (struct comparator *cmptr)
{
- struct value_comparator *vc = (struct value_comparator *) cmptr;
+ struct value_comparator *vc
+ = UP_CAST (cmptr, struct value_comparator, parent);
value_destroy (&vc->pattern, var_get_width (cmptr->var));
}
value_comparator_create (const struct variable *var, const PsppireDict *dict, const char *target)
{
struct value_comparator *vc = xzalloc (sizeof (*vc));
- struct comparator *cmptr = (struct comparator *) vc;
+ struct comparator *cmptr = &vc->parent;
cmptr->flags = 0;
cmptr->var = var;
enum string_cmp_flags flags)
{
struct string_comparator *ssc = xzalloc (sizeof (*ssc));
- struct comparator *cmptr = (struct comparator *) ssc;
+ struct comparator *cmptr = &ssc->parent;
cmptr->flags = flags;
cmptr->var = var;
{
int code;
struct regexp_comparator *rec = xzalloc (sizeof (*rec));
- struct comparator *cmptr = (struct comparator *) rec;
+ struct comparator *cmptr = &rec->parent;
cmptr->flags = flags;
cmptr->var = var;
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.2.0 on Sat Aug 11 17:19:54 2007 by john@marilyn-->
+<?xml version="1.0"?>
<glade-interface>
+ <!-- interface-requires gtk+ 2.16 -->
+ <!-- interface-naming-policy toplevel-contextual -->
<widget class="GtkWindow" id="output-viewer-window">
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="default_width">600</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkMenuItem" id="menuitem1">
- <property name="visible">False</property>
<property name="sensitive">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">_File</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImageMenuItem" id="file_save">
+ <property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">gtk-save</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkImageMenuItem" id="file_save-as">
+ <property name="label">gtk-save-as</property>
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">gtk-save-as</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="menuitem2">
- <property name="visible">False</property>
<property name="sensitive">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">_Edit</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<child>
<widget class="GtkImageMenuItem" id="imagemenuitem7">
+ <property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="label" translatable="yes">gtk-copy</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
</widget>
</widget>
<packing>
<property name="expand">False</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <widget class="GtkHPaned" id="hpaned1">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="position">112</property>
+ <property name="position_set">True</property>
<child>
- <widget class="GtkTextView" id="output-viewer-textview">
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <widget class="GtkTreeView" id="overview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="editable">False</property>
- <property name="left_margin">5</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <widget class="GtkLayout" id="output">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ </widget>
+ </child>
</widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
</child>
</widget>
<packing>
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2008 Free Software Foundation
+ Copyright (C) 2008, 2009 Free Software Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include "helper.h"
#include <libpspp/message.h>
+#include <output/cairo.h>
+#include <output/manager.h>
+#include <output/output.h>
+#include <output/table.h>
#include <stdlib.h>
#include "about.h"
#define _(msgid) gettext (msgid)
#define N_(msgid) msgid
-
+enum
+ {
+ COL_TITLE, /* Table title. */
+ COL_Y, /* Y position of top of title. */
+ N_COLS
+ };
static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer);
static void psppire_output_window_base_init (PsppireOutputWindowClass *class);
gpointer class_data)
{
}
-
-
\f
+/* Output driver class. */
static PsppireOutputWindow *the_output_viewer = NULL;
+static gboolean
+expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
+{
+ struct som_entity *entity = g_object_get_data (G_OBJECT (widget), "entity");
+ GdkWindow *window = widget->window;
+ cairo_t *cairo = gdk_cairo_create (GDK_DRAWABLE (window));
+ struct outp_driver *driver = xr_create_driver (cairo); /* XXX can fail */
+ struct tab_table *t = entity->ext;
+ void *rendering;
+
+ rendering = entity->class->render_init (entity, driver, tab_l (t),
+ tab_r (t), tab_t (t), tab_b (t));
+
+ entity->class->title (rendering, 0, 0,
+ entity->table_num, entity->subtable_num,
+ entity->command_name);
+ entity->class->render (rendering, tab_l (t), tab_t (t),
+ tab_nc (t) - tab_r (t),
+ tab_nr (t) - tab_b (t));
+
+ entity->class->render_free (rendering);
+ driver->class->close_driver (driver);
+ outp_free_driver (driver);
+ return TRUE;
+}
+static void
+psppire_output_submit (struct outp_driver *this, struct som_entity *entity)
+{
+ if (the_output_viewer == NULL)
+ {
+ the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
+ gtk_widget_show_all (GTK_WIDGET (the_output_viewer));
+ }
+
+ if (entity->type == SOM_TABLE)
+ {
+ GdkWindow *window = GTK_WIDGET (the_output_viewer)->window;
+ cairo_t *cairo = gdk_cairo_create (GDK_DRAWABLE (window));
+ struct outp_driver *driver = xr_create_driver (cairo); /* XXX can fail */
+ struct tab_table *t = entity->ext;
+ GtkTreeStore *store;
+ GtkTreeIter item;
+ GtkTreePath *path;
+ GtkWidget *drawing_area;
+ void *rendering;
+ struct string title;
+ int tw, th;
+
+ tab_ref (t);
+ rendering = entity->class->render_init (entity, driver, tab_l (t),
+ tab_r (t), tab_t (t), tab_b (t));
+ entity->class->area (rendering, &tw, &th);
+
+ drawing_area = gtk_drawing_area_new ();
+ gtk_widget_modify_bg (GTK_WIDGET (drawing_area), GTK_STATE_NORMAL,
+ >k_widget_get_style (drawing_area)->base[GTK_STATE_NORMAL]);
+ g_object_set_data (G_OBJECT (drawing_area),
+ "entity", som_entity_clone (entity));
+ gtk_widget_set_size_request (drawing_area, tw / 1024, th / 1024);
+ gtk_layout_put (the_output_viewer->output, drawing_area,
+ 0, the_output_viewer->y);
+ gtk_widget_show (drawing_area);
+ g_signal_connect (G_OBJECT (drawing_area), "expose_event",
+ G_CALLBACK (expose_event_callback), NULL);
+
+ entity->class->render_free (rendering);
+ driver->class->close_driver (driver);
+ outp_free_driver (driver);
+
+ store = GTK_TREE_STORE (gtk_tree_view_get_model (
+ the_output_viewer->overview));
+
+ ds_init_empty (&title);
+ if (entity->table_num != the_output_viewer->last_table_num)
+ {
+ gtk_tree_store_append (store, &item, NULL);
+
+ ds_put_format (&title, "%d %s",
+ entity->table_num, entity->command_name);
+ gtk_tree_store_set (store, &item,
+ COL_TITLE, ds_cstr (&title),
+ COL_Y, the_output_viewer->y,
+ -1);
+
+ /* XXX shouldn't save a GtkTreeIter */
+ the_output_viewer->last_table_num = entity->table_num;
+ the_output_viewer->last_top_level = item;
+ }
+
+ gtk_tree_store_append (store, &item,
+ &the_output_viewer->last_top_level);
+ ds_clear (&title);
+ ds_put_format (&title, "%d.%d %s",
+ entity->table_num, entity->subtable_num,
+ t->title ? t->title : entity->command_name);
+ gtk_tree_store_set (store, &item,
+ COL_TITLE, ds_cstr (&title),
+ COL_Y, the_output_viewer->y,
+ -1);
+ ds_destroy (&title);
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (store),
+ &the_output_viewer->last_top_level);
+ gtk_tree_view_expand_row (the_output_viewer->overview, path, TRUE);
+ gtk_tree_path_free (path);
+
+ if (tw / 1024 > the_output_viewer->max_width)
+ the_output_viewer->max_width = tw / 1024;
+ the_output_viewer->y += th / 1024;
+
+ gtk_layout_set_size (the_output_viewer->output,
+ the_output_viewer->max_width, the_output_viewer->y);
+ }
+
+ gtk_window_set_urgency_hint (GTK_WINDOW (the_output_viewer), TRUE);
+}
+
+static struct outp_class psppire_output_class =
+ {
+ "PSPPIRE", /* name */
+ true, /* special */
+ NULL, /* open_driver */
+ NULL, /* close_driver */
+ NULL, /* open_page */
+ NULL, /* close_page */
+ NULL, /* flush */
+ NULL, /* output_chart */
+ psppire_output_submit, /* submit */
+ NULL, /* line */
+ NULL, /* text_metrics */
+ NULL, /* text_draw */
+ };
+
+void
+psppire_output_window_setup (void)
+{
+ outp_register_driver (outp_allocate_driver (&psppire_output_class,
+ "PSPPIRE", 0));
+}
+\f
int viewer_length = 16;
int viewer_width = 59;
the_output_viewer = NULL;
- unlink (output_file_name());
-
return FALSE;
}
{
gtk_window_set_urgency_hint (window, FALSE);
}
-/* Sets width and length according to the new size
- of the output window */
+
static void
-on_textview_resize (GtkWidget *widget,
- GtkAllocation *allocation,
- gpointer user_data)
+on_row_activate (GtkTreeView *overview,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ PsppireOutputWindow *window)
{
- PangoContext * context ;
- PangoLayout *layout ;
- PangoRectangle logical;
- GtkStyle *style;
- gint right_margin, left_margin;
- GtkTextView *text_view = GTK_TEXT_VIEW (widget);
-
- context = gtk_widget_create_pango_context (widget);
- layout = pango_layout_new (context);
-
- style = gtk_widget_get_style (widget);
-
- pango_layout_set_font_description (layout, style->font_desc);
-
- /* Find the width of one character. We can use any character, because
- the textview has a monospaced font */
- pango_layout_set_text (layout, "M", 1);
-
- pango_layout_get_extents (layout, NULL, &logical);
-
- left_margin = gtk_text_view_get_left_margin (text_view);
- right_margin = gtk_text_view_get_right_margin (text_view);
-
- viewer_length = allocation->height / PANGO_PIXELS (logical.height);
- viewer_width = (allocation->width - right_margin - left_margin)
- / PANGO_PIXELS (logical.width);
-
- g_object_unref (G_OBJECT (layout));
- g_object_unref (G_OBJECT (context));
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkAdjustment *vadj;
+ GValue value = {0};
+ double y, min, max;
+
+ model = gtk_tree_view_get_model (overview);
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+
+ gtk_tree_model_get_value (model, &iter, COL_Y, &value);
+ y = g_value_get_long (&value);
+ g_value_unset (&value);
+
+ vadj = gtk_layout_get_vadjustment (window->output);
+ min = vadj->lower;
+ max = vadj->upper - vadj->page_size;
+ if (y < min)
+ y = min;
+ else if (y > max)
+ y = max;
+ gtk_adjustment_set_value (vadj, y);
}
-
static void
psppire_output_window_init (PsppireOutputWindow *window)
{
- GtkBuilder *xml = builder_new ("output-viewer.ui");
-
- GtkWidget *box = gtk_vbox_new (FALSE, 0);
-
- GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
-
- GtkWidget *menubar = get_widget_assert (xml, "menubar1");
-
- window->textview = get_widget_assert (xml, "output-viewer-textview");
-
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkBuilder *xml;
- gtk_container_add (GTK_CONTAINER (window), box);
+ xml = builder_new ("output-viewer.ui");
+ gtk_widget_reparent (get_widget_assert (xml, "vbox1"), GTK_WIDGET (window));
- g_object_ref (menubar);
- gtk_widget_unparent (menubar);
+ window->output = GTK_LAYOUT (get_widget_assert (xml, "output"));
+ window->y = 0;
- g_object_ref (sw);
- gtk_widget_unparent (sw);
+ window->overview = GTK_TREE_VIEW (get_widget_assert (xml, "overview"));
+ gtk_tree_view_set_model (window->overview,
+ GTK_TREE_MODEL (gtk_tree_store_new (
+ N_COLS,
+ G_TYPE_STRING, /* COL_TITLE */
+ G_TYPE_LONG))); /* COL_Y */
+ window->last_table_num = -1;
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_append_column (GTK_TREE_VIEW (window->overview), column);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute (column, renderer, "text", COL_TITLE);
- gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
- gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
+ g_signal_connect (GTK_TREE_VIEW (window->overview),
+ "row-activated", G_CALLBACK (on_row_activate), window);
-
- gtk_widget_show_all (box);
+ gtk_widget_modify_bg (GTK_WIDGET (window->output), GTK_STATE_NORMAL,
+ >k_widget_get_style (GTK_WIDGET (window->output))->base[GTK_STATE_NORMAL]);
connect_help (xml);
- window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
-
g_signal_connect (window,
"focus-in-event",
G_CALLBACK (cancel_urgency),
NULL);
- {
- /* Output uses ascii characters for tabular material.
- So we need a monospaced font otherwise it'll look silly */
- PangoFontDescription *font_desc =
- pango_font_description_from_string ("monospace");
-
- gtk_widget_modify_font (window->textview, font_desc);
- pango_font_description_free (font_desc);
- }
-
- g_signal_connect (window->textview, "size-allocate",
- G_CALLBACK (on_textview_resize), NULL);
-
- window->fp = NULL;
-
g_signal_connect (get_action_assert (xml,"help_about"),
"activate",
G_CALLBACK (about_new),
"description", _("Output Viewer"),
NULL));
}
-
-static void reload_viewer (PsppireOutputWindow *ow);
-
-void
-psppire_output_window_reload (void)
-{
- struct stat buf;
-
- /* If there is no output, then don't do anything */
- if (0 != stat (output_file_name(), &buf))
- return ;
-
- if ( NULL == the_output_viewer )
- {
- the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
- gtk_widget_show (GTK_WIDGET (the_output_viewer));
- }
-
- reload_viewer (the_output_viewer);
-
-}
-
-
-static void
-reload_viewer (PsppireOutputWindow *ow)
-{
- GtkTextIter end_iter;
- GtkTextMark *mark ;
-
- char *line = NULL;
-
- gboolean chars_inserted = FALSE;
-
- gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
-
- line = xrealloc (line, sizeof (char) * (viewer_width + 1));
-
- mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
-
-#ifdef __CYGWIN__
- /*
- Apparently Windoze is not capabale of writing to a file whilst
- another (or the same) process is reading from it. Therefore, we
- must close the file after reading it, and clear the entire buffer
- before writing to it.
- This will be slower for large buffers, but should work
- (in so far as anything ever works on windows).
- */
- {
- GtkTextIter start_iter;
- FILE *fp = fopen (output_file_name(), "r");
- if ( !fp)
- {
- g_critical ("Cannot open %s\n", output_file_name());
- return;
- }
-
- /* Delete all the entire buffer */
- gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
- gtk_text_buffer_delete (ow->buffer, &start_iter, &end_iter);
-
-
- gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
- /* Read in the next lot of text */
- while (fgets (line, viewer_width + 1, fp) != NULL)
- {
- chars_inserted = TRUE;
- gtk_text_buffer_insert (ow->buffer, &start_iter, line, -1);
- }
-
- fclose (fp);
- }
-#else
- {
- if ( ow->fp == NULL)
- {
- ow->fp = fopen (output_file_name(), "r");
- if ( ow->fp == NULL)
- {
- g_critical ("Cannot open %s\n", output_file_name());
- return;
- }
- }
-
- /* Read in the next lot of text */
- while (fgets (line, viewer_width + 1, ow->fp) != NULL)
- {
- chars_inserted = TRUE;
- gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
- }
- }
-#endif
-
- /* Scroll to where the start of this lot of text begins */
- gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
- mark,
- 0.1, TRUE, 0.0, 0.0);
-
-
- if ( chars_inserted )
- gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);
-}
-
-
-
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2008 Free Software Foundation
+ Copyright (C) 2008, 2009 Free Software Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
extern int viewer_width ;
-#define OUTPUT_FILE_NAME "psppire.txt"
-
-
-
G_BEGIN_DECLS
#define PSPPIRE_OUTPUT_WINDOW_TYPE (psppire_output_window_get_type ())
PsppireWindow parent;
/* <private> */
- GtkTextBuffer *buffer; /* The buffer which contains the text */
- GtkWidget *textview ;
- FILE *fp; /* The file it's viewing */
+ GtkLayout *output;
+ int max_width;
+ int y;
+
+ GtkTreeView *overview;
+ int last_table_num;
+ GtkTreeIter last_top_level;
};
struct _PsppireOutputWindowClass
GType psppire_output_window_get_type (void);
GtkWidget* psppire_output_window_new (void);
-
-void psppire_output_window_reload (void);
-
+void psppire_output_window_setup (void);
G_END_DECLS
create_icon_factory ();
- {
- const char *filename = output_file_name ();
-
- struct string config_string;
-
- ds_init_empty (&config_string);
-
- ds_put_format (&config_string,
- "gui:ascii:screen:squeeze=on headers=off top-margin=0 "
- "bottom-margin=0 paginate=off length=auto width=auto "
- "emphasis=none "
- "output-file=\"%s\" append=yes", filename);
-
- outp_configure_driver_line (ds_ss (&config_string));
-
- unlink (filename);
-
- ds_destroy (&config_string);
- }
+ psppire_output_window_setup ();
journal_enable ();
textdomain (PACKAGE);
const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};
-
-
-const char *
-output_file_name (void)
-{
- const char *dir = default_output_path ();
- static char *filename = NULL;
-
- if ( NULL == filename )
- filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME);
-
- return filename;
-}
/* PSPPIRE - a graphical user interface for PSPP.
- Copyright (C) 2006 Free Software Foundation
+ Copyright (C) 2006, 2009 Free Software Foundation
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <libpspp/getl.h>
#include <libpspp/compiler.h>
+#include <libpspp/cast.h>
#include <libpspp/str.h>
#include <stdlib.h>
gchar *text;
GtkTextIter next_line;
- struct syntax_editor_source *ses = (struct syntax_editor_source *) i;
+ struct syntax_editor_source *ses
+ = UP_CAST (i, struct syntax_editor_source, parent);
if ( gtk_text_iter_compare (&ses->i, &ses->end) >= 0)
return false;
ses->parent.location = location;
- return (struct getl_interface *) ses;
+ return &ses->parent;
}
struct val_labs_dialog *dialog = data;
union value value;
- const struct val_lab *vl;
+ struct val_lab *vl;
get_selected_tuple (dialog, &value, NULL);
vl = val_labs_lookup (dialog->labs, &value);
src/ui/libuicommon.la \
src/libpspp.la \
src/libpspp-core.la \
+ $(CAIRO_LIBS) \
$(NCURSES_LIBS) \
$(LIBICONV) \
$(LIBINTL) $(LIBREADLINE)
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <data/file-name.h>
#include <data/settings.h>
#include <language/command.h>
+#include <libpspp/cast.h>
#include <libpspp/message.h>
#include <libpspp/str.h>
#include <libpspp/version.h>
read_interactive (struct getl_interface *s,
struct string *line)
{
- struct readln_source *is =
- (struct readln_source *) s ;
+ struct readln_source *is = UP_CAST (s, struct readln_source, parent);
return is->interactive_func (line, prompt_get_style ());
}
rlns->parent.read = read_interactive;
rlns->parent.close = readln_close;
- return (struct getl_interface *) rlns;
+ return &rlns->parent;
}
tests/libpspp/range-set-test \
tests/libpspp/sparse-array-test \
tests/libpspp/str-test \
+ tests/libpspp/string-map-test \
+ tests/libpspp/string-set-test \
tests/libpspp/tower-test
TESTS = $(dist_TESTS) $(nodist_TESTS)
tests/libpspp/str-test.c
tests_libpspp_str_test_LDADD = src/libpspp/libpspp.la gl/libgl.la $(LIBINTL)
+tests_libpspp_string_map_test_SOURCES = \
+ src/libpspp/hash-functions.c \
+ src/libpspp/hmap.c \
+ src/libpspp/string-map.c \
+ src/libpspp/string-set.c \
+ tests/libpspp/string-map-test.c
+tests_libpspp_string_map_test_LDADD = gl/libgl.la $(LIBINTL)
+tests_libpspp_string_map_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
+
+tests_libpspp_string_set_test_SOURCES = \
+ src/libpspp/hash-functions.c \
+ src/libpspp/hmap.c \
+ src/libpspp/string-set.c \
+ tests/libpspp/string-set-test.c
+tests_libpspp_string_set_test_LDADD = gl/libgl.la $(LIBINTL)
+tests_libpspp_string_set_test_CPPFLAGS = $(AM_CPPFLAGS) -DASSERT_LEVEL=10
+
tests_libpspp_tower_test_SOURCES = \
src/libpspp/abt.c \
src/libpspp/abt.h \
size_t i, j;
int *order;
+ check (hmap_is_empty (hmap) == (cnt == 0));
check (hmap_count (hmap) == cnt);
check (cnt <= hmap_capacity (hmap));
for (p = hmap_first (hmap), i = 0; i < cnt; p = hmap_next (hmap, p), i++)
{
struct element *e = hmap_node_to_element (p);
- size_t j;
check (hmap_node_hash (&e->node) == hash (e->data));
for (j = 0; j < left; j++)
/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
size_t i, j;
int *order;
+ check (hmapx_is_empty (hmapx) == (cnt == 0));
check (hmapx_count (hmapx) == cnt);
check (cnt <= hmapx_capacity (hmapx));
caching. */
for (start = 0; start <= 32; start++)
{
- struct range_set *nonconst_rs = (struct range_set *) rs;
+ struct range_set *nonconst_rs = CONST_CAST (struct range_set *, rs);
nonconst_rs->cache_end = 0;
s1 = range_set_scan (rs, start);
s2 = next_1bit (pattern, start);
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* This is a test program for the string_map_* routines defined in
+ string-map.c. This test program aims to be as comprehensive as possible.
+ "gcov -a -b" should report almost complete coverage of lines, blocks and
+ branches in string-map.c, except that one branch caused by hash collision is
+ not exercised because our hash function has so few collisions. "valgrind
+ --leak-check=yes --show-reachable=yes" should give a clean report. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libpspp/string-map.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/hash-functions.h>
+#include <libpspp/compiler.h>
+#include <libpspp/string-set.h>
+\f
+/* Currently running test. */
+static const char *test_name;
+
+/* Exit with a failure code.
+ (Place a breakpoint on this function while debugging.) */
+static void
+check_die (void)
+{
+ exit (EXIT_FAILURE);
+}
+
+/* If OK is not true, prints a message about failure on the
+ current source file and the given LINE and terminates. */
+static void
+check_func (bool ok, int line)
+{
+ if (!ok)
+ {
+ printf ("Check failed in %s test at %s, line %d\n",
+ test_name, __FILE__, line);
+ check_die ();
+ }
+}
+
+/* Verifies that EXPR evaluates to true.
+ If not, prints a message citing the calling line number and
+ terminates. */
+#define check(EXPR) check_func ((EXPR), __LINE__)
+
+/* Prints a message about memory exhaustion and exits with a
+ failure code. */
+static void
+xalloc_die (void)
+{
+ printf ("virtual memory exhausted\n");
+ exit (EXIT_FAILURE);
+}
+
+static void *xmalloc (size_t n) MALLOC_LIKE;
+static void *xnmalloc (size_t n, size_t m) MALLOC_LIKE;
+static void *xmemdup (const void *p, size_t n) MALLOC_LIKE;
+
+/* Allocates and returns N bytes of memory. */
+static void *
+xmalloc (size_t n)
+{
+ if (n != 0)
+ {
+ void *p = malloc (n);
+ if (p == NULL)
+ xalloc_die ();
+
+ return p;
+ }
+ else
+ return NULL;
+}
+
+static void *
+xmemdup (const void *p, size_t n)
+{
+ void *q = xmalloc (n);
+ memcpy (q, p, n);
+ return q;
+}
+
+/* Clone STRING. */
+static char *
+xstrdup (const char *string)
+{
+ return xmemdup (string, strlen (string) + 1);
+}
+
+/* Allocates and returns N * M bytes of memory. */
+static void *
+xnmalloc (size_t n, size_t m)
+{
+ if ((size_t) -1 / m <= n)
+ xalloc_die ();
+ return xmalloc (n * m);
+}
+\f
+/* Support routines. */
+
+enum {
+ IDX_BITS = 10,
+ MAX_IDX = 1 << IDX_BITS,
+ KEY_MASK = (MAX_IDX - 1),
+ KEY_SHIFT = 0,
+ VALUE_MASK = (MAX_IDX - 1) << IDX_BITS,
+ VALUE_SHIFT = IDX_BITS
+};
+
+static char *string_table[MAX_IDX];
+
+static const char *
+get_string (int idx)
+{
+ char **s;
+
+ assert (idx >= 0 && idx < MAX_IDX);
+ s = &string_table[idx];
+ if (*s == NULL)
+ {
+ *s = xmalloc (16);
+ sprintf (*s, "%d", idx);
+ }
+ return *s;
+}
+
+static void
+free_strings (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_IDX; i++)
+ free (string_table[i]);
+}
+
+static const char *
+make_key (int value)
+{
+ return get_string ((value & KEY_MASK) >> KEY_SHIFT);
+}
+
+static const char *
+make_value (int value)
+{
+ return get_string ((value & VALUE_MASK) >> VALUE_SHIFT);
+}
+
+static int
+random_value (unsigned int seed, int basis)
+{
+ return hash_int (seed, basis) & VALUE_MASK;
+}
+
+/* Swaps *A and *B. */
+static void
+swap (int *a, int *b)
+{
+ int t = *a;
+ *a = *b;
+ *b = t;
+}
+
+/* Reverses the order of the CNT integers starting at VALUES. */
+static void
+reverse (int *values, size_t cnt)
+{
+ size_t i = 0;
+ size_t j = cnt;
+
+ while (j > i)
+ swap (&values[i++], &values[--j]);
+}
+
+/* Arranges the CNT elements in VALUES into the lexicographically next greater
+ permutation. Returns true if successful. If VALUES is already the
+ lexicographically greatest permutation of its elements (i.e. ordered from
+ greatest to smallest), arranges them into the lexicographically least
+ permutation (i.e. ordered from smallest to largest) and returns false.
+
+ Comparisons among elements of VALUES consider only the bits in KEY_MASK. */
+static bool
+next_permutation (int *values, size_t cnt)
+{
+ if (cnt > 0)
+ {
+ size_t i = cnt - 1;
+ while (i != 0)
+ {
+ i--;
+ if ((values[i] & KEY_MASK) < (values[i + 1] & KEY_MASK))
+ {
+ size_t j;
+ for (j = cnt - 1;
+ (values[i] & KEY_MASK) >= (values[j] & KEY_MASK);
+ j--)
+ continue;
+ swap (values + i, values + j);
+ reverse (values + (i + 1), cnt - (i + 1));
+ return true;
+ }
+ }
+
+ reverse (values, cnt);
+ }
+
+ return false;
+}
+
+/* Returns N!. */
+static unsigned int
+factorial (unsigned int n)
+{
+ unsigned int value = 1;
+ while (n > 1)
+ value *= n--;
+ return value;
+}
+
+/* Randomly shuffles the CNT elements in ARRAY, each of which is
+ SIZE bytes in size. */
+static void
+random_shuffle (void *array_, size_t cnt, size_t size)
+{
+ char *array = array_;
+ char *tmp = xmalloc (size);
+ size_t i;
+
+ for (i = 0; i < cnt; i++)
+ {
+ size_t j = rand () % (cnt - i) + i;
+ if (i != j)
+ {
+ memcpy (tmp, array + j * size, size);
+ memcpy (array + j * size, array + i * size, size);
+ memcpy (array + i * size, tmp, size);
+ }
+ }
+
+ free (tmp);
+}
+
+/* Checks that MAP contains the CNT strings in DATA, that its structure is
+ correct, and that certain operations on MAP produce the expected results. */
+static void
+check_string_map (struct string_map *map, const int data[], size_t cnt)
+{
+ size_t i;
+
+ check (string_map_is_empty (map) == (cnt == 0));
+ check (string_map_count (map) == cnt);
+
+ for (i = 0; i < cnt; i++)
+ {
+ struct string_map_node *node;
+ const char *key = make_key (data[i]);
+ const char *value = make_value (data[i]);
+ const char *found_value;
+
+ check (string_map_contains (map, key));
+
+ node = string_map_find_node (map, key);
+ check (node != NULL);
+ check (!strcmp (key, string_map_node_get_key (node)));
+ check (!strcmp (value, string_map_node_get_value (node)));
+
+ check (node == string_map_insert (map, key, "abc"));
+ check (!strcmp (value, string_map_node_get_value (node)));
+
+ check (node == string_map_insert_nocopy (map, xstrdup (key),
+ xstrdup ("def")));
+ check (!strcmp (value, string_map_node_get_value (node)));
+
+ found_value = string_map_find (map, key);
+ check (found_value != NULL);
+ check (!strcmp (found_value, value));
+ }
+
+ check (!string_map_contains (map, "xxx"));
+ check (string_map_find (map, "z") == NULL);
+ check (string_map_find_node (map, "") == NULL);
+ check (!string_map_delete (map, "xyz"));
+
+ if (cnt == 0)
+ check (string_map_first (map) == NULL);
+ else
+ {
+ const struct string_map_node *node;
+ int *data_copy;
+ int left;
+
+ data_copy = xmemdup (data, cnt * sizeof *data);
+ left = cnt;
+ for (node = string_map_first (map), i = 0; i < cnt;
+ node = string_map_next (map, node), i++)
+ {
+ const char *key = string_map_node_get_key (node);
+ const char *value = string_map_node_get_value (node);
+ size_t j;
+
+ for (j = 0; j < left; j++)
+ if (!strcmp (key, make_key (data_copy[j]))
+ || !strcmp (value, make_value (data_copy[j])))
+ {
+ data_copy[j] = data_copy[--left];
+ goto next;
+ }
+ check_die ();
+
+ next: ;
+ }
+ check (node == NULL);
+ free (data_copy);
+ }
+}
+
+/* Inserts the CNT strings from 0 to CNT - 1 (inclusive) into a map in the
+ order specified by INSERTIONS, then deletes them in the order specified by
+ DELETIONS, checking the map's contents for correctness after each
+ operation. */
+static void
+test_insert_delete (const int insertions[],
+ const int deletions[],
+ size_t cnt)
+{
+ struct string_map map;
+ size_t i;
+
+ string_map_init (&map);
+ check_string_map (&map, NULL, 0);
+ for (i = 0; i < cnt; i++)
+ {
+ check (string_map_insert (&map, make_key (insertions[i]),
+ make_value (insertions[i])));
+ check_string_map (&map, insertions, i + 1);
+ }
+ for (i = 0; i < cnt; i++)
+ {
+ check (string_map_delete (&map, make_key (deletions[i])));
+ check_string_map (&map, deletions + i + 1, cnt - i - 1);
+ }
+ string_map_destroy (&map);
+}
+\f
+/* Inserts strings into a map in each possible order, then removes them in each
+ possible order, up to a specified maximum size. */
+static void
+test_insert_any_remove_any (void)
+{
+ const int basis = 0;
+ const int max_elems = 5;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *insertions, *deletions;
+ unsigned int ins_perm_cnt;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i | random_value (i, basis);
+
+ for (ins_perm_cnt = 0;
+ ins_perm_cnt == 0 || next_permutation (insertions, cnt);
+ ins_perm_cnt++)
+ {
+ unsigned int del_perm_cnt;
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ deletions[i] = i | random_value (i, basis);
+
+ for (del_perm_cnt = 0;
+ del_perm_cnt == 0 || next_permutation (deletions, cnt);
+ del_perm_cnt++)
+ test_insert_delete (insertions, deletions, cnt);
+
+ check (del_perm_cnt == factorial (cnt));
+ }
+ check (ins_perm_cnt == factorial (cnt));
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts strings into a map in each possible order, then removes them in the
+ same order, up to a specified maximum size. */
+static void
+test_insert_any_remove_same (void)
+{
+ const int max_elems = 7;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *values;
+ unsigned int permutation_cnt;
+ int i;
+
+ values = xnmalloc (cnt, sizeof *values);
+ for (i = 0; i < cnt; i++)
+ values[i] = i | random_value (i, 1);
+
+ for (permutation_cnt = 0;
+ permutation_cnt == 0 || next_permutation (values, cnt);
+ permutation_cnt++)
+ test_insert_delete (values, values, cnt);
+ check (permutation_cnt == factorial (cnt));
+
+ free (values);
+ }
+}
+
+/* Inserts strings into a map in each possible order, then
+ removes them in reverse order, up to a specified maximum
+ size. */
+static void
+test_insert_any_remove_reverse (void)
+{
+ const int max_elems = 7;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *insertions, *deletions;
+ unsigned int permutation_cnt;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i | random_value (i, 2);
+
+ for (permutation_cnt = 0;
+ permutation_cnt == 0 || next_permutation (insertions, cnt);
+ permutation_cnt++)
+ {
+ memcpy (deletions, insertions, sizeof *insertions * cnt);
+ reverse (deletions, cnt);
+
+ test_insert_delete (insertions, deletions, cnt);
+ }
+ check (permutation_cnt == factorial (cnt));
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts and removes strings in a map, in random order. */
+static void
+test_random_sequence (void)
+{
+ const int basis = 3;
+ const int max_elems = 64;
+ const int max_trials = 8;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt += 2)
+ {
+ int *insertions, *deletions;
+ int trial;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i | random_value (i, basis);
+ for (i = 0; i < cnt; i++)
+ deletions[i] = i | random_value (i, basis);
+
+ for (trial = 0; trial < max_trials; trial++)
+ {
+ random_shuffle (insertions, cnt, sizeof *insertions);
+ random_shuffle (deletions, cnt, sizeof *deletions);
+
+ test_insert_delete (insertions, deletions, cnt);
+ }
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts strings into a map in ascending order, then delete in ascending
+ order. */
+static void
+test_insert_ordered (void)
+{
+ const int max_elems = 64;
+ int *values;
+ struct string_map map;
+ int i;
+
+ string_map_init (&map);
+ values = xnmalloc (max_elems, sizeof *values);
+ for (i = 0; i < max_elems; i++)
+ {
+ values[i] = i | random_value (i, 4);
+ string_map_insert_nocopy (&map, xstrdup (make_key (values[i])),
+ xstrdup (make_value (values[i])));
+ check_string_map (&map, values, i + 1);
+ }
+ for (i = 0; i < max_elems; i++)
+ {
+ string_map_delete (&map, make_key (i));
+ check_string_map (&map, values + i + 1, max_elems - i - 1);
+ }
+ string_map_destroy (&map);
+ free (values);
+}
+
+/* Inserts and replaces strings in a map, in random order. */
+static void
+test_replace (void)
+{
+ const int basis = 15;
+ enum { MAX_ELEMS = 16 };
+ const int max_trials = 8;
+ int cnt;
+
+ for (cnt = 0; cnt <= MAX_ELEMS; cnt++)
+ {
+ int insertions[MAX_ELEMS];
+ int trial;
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ insertions[i] = (i / 2) | random_value (i, basis);
+
+ for (trial = 0; trial < max_trials; trial++)
+ {
+ struct string_map map;
+ int data[MAX_ELEMS];
+ int n_data;
+
+ /* Insert with replacement in random order. */
+ n_data = 0;
+ string_map_init (&map);
+ random_shuffle (insertions, cnt, sizeof *insertions);
+ for (i = 0; i < cnt; i++)
+ {
+ const char *key = make_key (insertions[i]);
+ const char *value = make_value (insertions[i]);
+ int j;
+
+ for (j = 0; j < n_data; j++)
+ if ((data[j] & KEY_MASK) == (insertions[i] & KEY_MASK))
+ {
+ data[j] = insertions[i];
+ goto found;
+ }
+ data[n_data++] = insertions[i];
+ found:
+
+ if (i % 2)
+ string_map_replace (&map, key, value);
+ else
+ string_map_replace_nocopy (&map,
+ xstrdup (key), xstrdup (value));
+ check_string_map (&map, data, n_data);
+ }
+
+ /* Delete in original order. */
+ for (i = 0; i < cnt; i++)
+ {
+ const char *expected_value;
+ char *value;
+ int j;
+
+ expected_value = NULL;
+ for (j = 0; j < n_data; j++)
+ if ((data[j] & KEY_MASK) == (insertions[i] & KEY_MASK))
+ {
+ expected_value = make_value (data[j]);
+ data[j] = data[--n_data];
+ break;
+ }
+
+ value = string_map_find_and_delete (&map,
+ make_key (insertions[i]));
+ check ((value != NULL) == (expected_value != NULL));
+ check (value == NULL || !strcmp (value, expected_value));
+ free (value);
+ }
+ assert (string_map_is_empty (&map));
+
+ string_map_destroy (&map);
+ }
+ }
+}
+
+static void
+make_patterned_map (struct string_map *map, unsigned int pattern, int basis,
+ int insertions[], int *np)
+{
+ int n;
+ int i;
+
+ string_map_init (map);
+
+ n = 0;
+ for (i = 0; pattern != 0; i++)
+ if (pattern & (1u << i))
+ {
+ pattern &= pattern - 1;
+ insertions[n] = i | random_value (i, basis);
+ check (string_map_insert (map, make_key (insertions[n]),
+ make_value (insertions[n])));
+ n++;
+ }
+ check_string_map (map, insertions, n);
+
+ *np = n;
+}
+
+static void
+for_each_map (void (*cb)(struct string_map *, int data[], int n),
+ int basis)
+{
+ enum { MAX_ELEMS = 5 };
+ unsigned int pattern;
+
+ for (pattern = 0; pattern < (1u << MAX_ELEMS); pattern++)
+ {
+ int data[MAX_ELEMS];
+ struct string_map map;
+ int n;
+
+ make_patterned_map (&map, pattern, basis, data, &n);
+ (*cb) (&map, data, n);
+ string_map_destroy (&map);
+ }
+}
+
+static void
+for_each_pair_of_maps (
+ void (*cb)(struct string_map *a, int a_data[], int n_a,
+ struct string_map *b, int b_data[], int n_b),
+ int a_basis, int b_basis)
+{
+ enum { MAX_ELEMS = 5 };
+ unsigned int a_pattern, b_pattern;
+
+ for (a_pattern = 0; a_pattern < (1u << MAX_ELEMS); a_pattern++)
+ for (b_pattern = 0; b_pattern < (1u << MAX_ELEMS); b_pattern++)
+ {
+ int a_data[MAX_ELEMS], b_data[MAX_ELEMS];
+ struct string_map a_map, b_map;
+ int n_a, n_b;
+
+ make_patterned_map (&a_map, a_pattern, a_basis, a_data, &n_a);
+ make_patterned_map (&b_map, b_pattern, b_basis, b_data, &n_b);
+ (*cb) (&a_map, a_data, n_a, &b_map, b_data, n_b);
+ string_map_destroy (&a_map);
+ string_map_destroy (&b_map);
+ }
+}
+
+static void
+clear_cb (struct string_map *map, int data[] UNUSED, int n UNUSED)
+{
+ string_map_clear (map);
+ check_string_map (map, NULL, 0);
+}
+
+static void
+test_clear (void)
+{
+ for_each_map (clear_cb, 5);
+}
+
+static void
+clone_cb (struct string_map *map, int data[], int n)
+{
+ struct string_map clone;
+
+ string_map_clone (&clone, map);
+ check_string_map (&clone, data, n);
+ string_map_destroy (&clone);
+}
+
+static void
+test_clone (void)
+{
+ for_each_map (clone_cb, 6);
+}
+
+static void
+node_swap_value_cb (struct string_map *map, int data[], int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ const char *value = make_value (data[i]);
+ struct string_map_node *node;
+ char *old_value;
+
+ node = string_map_find_node (map, make_key (data[i]));
+ check (node != NULL);
+ check (!strcmp (string_map_node_get_value (node), value));
+ data[i] = (data[i] & KEY_MASK) | random_value (i, 15);
+ old_value = string_map_node_swap_value (node, make_value (data[i]));
+ check (old_value != NULL);
+ check (!strcmp (value, old_value));
+ free (old_value);
+ }
+}
+
+static void
+test_node_swap_value (void)
+{
+ for_each_map (node_swap_value_cb, 14);
+}
+
+static void
+swap_cb (struct string_map *a, int a_data[], int n_a,
+ struct string_map *b, int b_data[], int n_b)
+{
+ string_map_swap (a, b);
+ check_string_map (a, b_data, n_b);
+ check_string_map (b, a_data, n_a);
+}
+
+static void
+test_swap (void)
+{
+ for_each_pair_of_maps (swap_cb, 7, 8);
+}
+
+static void
+insert_map_cb (struct string_map *a, int a_data[], int n_a,
+ struct string_map *b, int b_data[], int n_b)
+{
+ int i, j;
+
+ string_map_insert_map (a, b);
+
+ for (i = 0; i < n_b; i++)
+ {
+ for (j = 0; j < n_a; j++)
+ if ((b_data[i] & KEY_MASK) == (a_data[j] & KEY_MASK))
+ goto found;
+ a_data[n_a++] = b_data[i];
+ found:;
+ }
+ check_string_map (a, a_data, n_a);
+ check_string_map (b, b_data, n_b);
+}
+
+static void
+test_insert_map (void)
+{
+ for_each_pair_of_maps (insert_map_cb, 91, 10);
+}
+
+static void
+replace_map_cb (struct string_map *a, int a_data[], int n_a,
+ struct string_map *b, int b_data[], int n_b)
+{
+ int i, j;
+
+ string_map_replace_map (a, b);
+
+ for (i = 0; i < n_b; i++)
+ {
+ for (j = 0; j < n_a; j++)
+ if ((b_data[i] & KEY_MASK) == (a_data[j] & KEY_MASK))
+ {
+ a_data[j] = (a_data[j] & KEY_MASK) | (b_data[i] & VALUE_MASK);
+ goto found;
+ }
+ a_data[n_a++] = b_data[i];
+ found:;
+ }
+ check_string_map (a, a_data, n_a);
+ check_string_map (b, b_data, n_b);
+}
+
+static void
+test_replace_map (void)
+{
+ for_each_pair_of_maps (replace_map_cb, 11, 12);
+}
+
+static void
+check_set (struct string_set *set, const int *data, int n_data,
+ int mask, int shift)
+{
+ int *unique;
+ int n_unique;
+ int i;
+
+ n_unique = 0;
+ unique = xmalloc (n_data * sizeof *unique);
+ for (i = 0; i < n_data; i++)
+ {
+ int idx = (data[i] & mask) >> shift;
+ int j;
+
+ for (j = 0; j < n_unique; j++)
+ if (unique[j] == idx)
+ goto found;
+ unique[n_unique++] = idx;
+ found:;
+ }
+
+ check (string_set_count (set) == n_unique);
+ for (i = 0; i < n_unique; i++)
+ check (string_set_contains (set, get_string (unique[i])));
+ string_set_destroy (set);
+ free (unique);
+}
+
+static void
+get_keys_and_values_cb (struct string_map *map, int data[], int n)
+{
+ struct string_set keys, values;
+
+ string_set_init (&keys);
+ string_set_init (&values);
+ string_map_get_keys (map, &keys);
+ string_map_get_values (map, &values);
+ check_set (&keys, data, n, KEY_MASK, KEY_SHIFT);
+ check_set (&values, data, n, VALUE_MASK, VALUE_SHIFT);
+}
+
+static void
+test_get_keys_and_values (void)
+{
+ for_each_map (get_keys_and_values_cb, 13);
+}
+
+static void
+test_destroy_null (void)
+{
+ string_map_destroy (NULL);
+}
+\f
+/* Main program. */
+
+/* Runs TEST_FUNCTION and prints a message about NAME. */
+static void
+run_test (void (*test_function) (void), const char *name)
+{
+ test_name = name;
+ putchar ('.');
+ fflush (stdout);
+ test_function ();
+}
+
+int
+main (void)
+{
+ run_test (test_insert_any_remove_any, "insert any order, delete any order");
+ run_test (test_insert_any_remove_same,
+ "insert any order, delete same order");
+ run_test (test_insert_any_remove_reverse,
+ "insert any order, delete reverse order");
+ run_test (test_random_sequence, "insert and delete in random sequence");
+ run_test (test_replace, "insert and replace in random sequence");
+ run_test (test_insert_ordered, "insert in ascending order");
+ run_test (test_clear, "clear");
+ run_test (test_clone, "clone");
+ run_test (test_swap, "swap");
+ run_test (test_node_swap_value, "node_swap_value");
+ run_test (test_insert_map, "insert_map");
+ run_test (test_replace_map, "replace_map");
+ run_test (test_get_keys_and_values, "get keys and values");
+ run_test (test_destroy_null, "destroying null table");
+
+ putchar ('\n');
+
+ free_strings ();
+
+ return 0;
+}
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* This is a test program for the string_set_* routines defined in
+ string-set.c. This test program aims to be as comprehensive as possible.
+ "gcov -a -b" should report almost complete coverage of lines, blocks and
+ branches in string-set.c, except that one branch caused by hash collision is
+ not exercised because our hash function has so few collisions. "valgrind
+ --leak-check=yes --show-reachable=yes" should give a clean report. */
+
+#include <config.h>
+
+#include <libpspp/string-set.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libpspp/compiler.h>
+\f
+/* Currently running test. */
+static const char *test_name;
+
+/* Exit with a failure code.
+ (Place a breakpoint on this function while debugging.) */
+static void
+check_die (void)
+{
+ exit (EXIT_FAILURE);
+}
+
+/* If OK is not true, prints a message about failure on the
+ current source file and the given LINE and terminates. */
+static void
+check_func (bool ok, int line)
+{
+ if (!ok)
+ {
+ printf ("Check failed in %s test at %s, line %d\n",
+ test_name, __FILE__, line);
+ check_die ();
+ }
+}
+
+/* Verifies that EXPR evaluates to true.
+ If not, prints a message citing the calling line number and
+ terminates. */
+#define check(EXPR) check_func ((EXPR), __LINE__)
+
+/* Prints a message about memory exhaustion and exits with a
+ failure code. */
+static void
+xalloc_die (void)
+{
+ printf ("virtual memory exhausted\n");
+ exit (EXIT_FAILURE);
+}
+
+static void *xmalloc (size_t n) MALLOC_LIKE;
+static void *xnmalloc (size_t n, size_t m) MALLOC_LIKE;
+static void *xmemdup (const void *p, size_t n) MALLOC_LIKE;
+
+/* Allocates and returns N bytes of memory. */
+static void *
+xmalloc (size_t n)
+{
+ if (n != 0)
+ {
+ void *p = malloc (n);
+ if (p == NULL)
+ xalloc_die ();
+
+ return p;
+ }
+ else
+ return NULL;
+}
+
+static void *
+xmemdup (const void *p, size_t n)
+{
+ void *q = xmalloc (n);
+ memcpy (q, p, n);
+ return q;
+}
+
+/* Clone STRING. */
+static char *
+xstrdup (const char *string)
+{
+ return xmemdup (string, strlen (string) + 1);
+}
+
+/* Allocates and returns N * M bytes of memory. */
+static void *
+xnmalloc (size_t n, size_t m)
+{
+ if ((size_t) -1 / m <= n)
+ xalloc_die ();
+ return xmalloc (n * m);
+}
+\f
+/* Support routines. */
+
+enum { MAX_VALUE = 1024 };
+
+static char *string_table[MAX_VALUE];
+
+static const char *
+make_string (int value)
+{
+ char **s;
+
+ assert (value >= 0 && value < MAX_VALUE);
+ s = &string_table[value];
+ if (*s == NULL)
+ {
+ *s = xmalloc (16);
+ sprintf (*s, "%d", value);
+ }
+ return *s;
+}
+
+static void
+free_strings (void)
+{
+ int i;
+
+ for (i = 0; i < MAX_VALUE; i++)
+ free (string_table[i]);
+}
+
+/* Swaps *A and *B. */
+static void
+swap (int *a, int *b)
+{
+ int t = *a;
+ *a = *b;
+ *b = t;
+}
+
+/* Reverses the order of the CNT integers starting at VALUES. */
+static void
+reverse (int *values, size_t cnt)
+{
+ size_t i = 0;
+ size_t j = cnt;
+
+ while (j > i)
+ swap (&values[i++], &values[--j]);
+}
+
+/* Arranges the CNT elements in VALUES into the lexicographically
+ next greater permutation. Returns true if successful.
+ If VALUES is already the lexicographically greatest
+ permutation of its elements (i.e. ordered from greatest to
+ smallest), arranges them into the lexicographically least
+ permutation (i.e. ordered from smallest to largest) and
+ returns false. */
+static bool
+next_permutation (int *values, size_t cnt)
+{
+ if (cnt > 0)
+ {
+ size_t i = cnt - 1;
+ while (i != 0)
+ {
+ i--;
+ if (values[i] < values[i + 1])
+ {
+ size_t j;
+ for (j = cnt - 1; values[i] >= values[j]; j--)
+ continue;
+ swap (values + i, values + j);
+ reverse (values + (i + 1), cnt - (i + 1));
+ return true;
+ }
+ }
+
+ reverse (values, cnt);
+ }
+
+ return false;
+}
+
+/* Returns N!. */
+static unsigned int
+factorial (unsigned int n)
+{
+ unsigned int value = 1;
+ while (n > 1)
+ value *= n--;
+ return value;
+}
+
+/* Randomly shuffles the CNT elements in ARRAY, each of which is
+ SIZE bytes in size. */
+static void
+random_shuffle (void *array_, size_t cnt, size_t size)
+{
+ char *array = array_;
+ char *tmp = xmalloc (size);
+ size_t i;
+
+ for (i = 0; i < cnt; i++)
+ {
+ size_t j = rand () % (cnt - i) + i;
+ if (i != j)
+ {
+ memcpy (tmp, array + j * size, size);
+ memcpy (array + j * size, array + i * size, size);
+ memcpy (array + i * size, tmp, size);
+ }
+ }
+
+ free (tmp);
+}
+
+/* Checks that SET contains the CNT strings in DATA, that its structure is
+ correct, and that certain operations on SET produce the expected results. */
+static void
+check_string_set (struct string_set *set, const int data[], size_t cnt)
+{
+ size_t i;
+
+ check (string_set_is_empty (set) == (cnt == 0));
+ check (string_set_count (set) == cnt);
+
+ for (i = 0; i < cnt; i++)
+ {
+ struct string_set_node *node;
+ const char *s = make_string (data[i]);
+
+ check (string_set_contains (set, s));
+ check (!string_set_insert (set, s));
+ check (!string_set_insert_nocopy (set, xstrdup (s)));
+
+ node = string_set_find_node (set, s);
+ check (node != NULL);
+ check (!strcmp (s, string_set_node_get_string (node)));
+ }
+
+ check (!string_set_contains (set, "xxx"));
+ check (string_set_find_node (set, "") == NULL);
+
+ if (cnt == 0)
+ check (string_set_first (set) == NULL);
+ else
+ {
+ const struct string_set_node *node;
+ int *data_copy;
+ int left;
+
+ data_copy = xmemdup (data, cnt * sizeof *data);
+ left = cnt;
+ for (node = string_set_first (set), i = 0; i < cnt;
+ node = string_set_next (set, node), i++)
+ {
+ const char *s = string_set_node_get_string (node);
+ size_t j;
+
+ for (j = 0; j < left; j++)
+ if (!strcmp (s, make_string (data_copy[j])))
+ {
+ data_copy[j] = data_copy[--left];
+ goto next;
+ }
+ check_die ();
+
+ next: ;
+ }
+ check (node == NULL);
+ free (data_copy);
+ }
+}
+
+/* Inserts the CNT strings from 0 to CNT - 1 (inclusive) into a set in the
+ order specified by INSERTIONS, then deletes them in the order specified by
+ DELETIONS, checking the set's contents for correctness after each
+ operation. */
+static void
+test_insert_delete (const int insertions[],
+ const int deletions[],
+ size_t cnt)
+{
+ struct string_set set;
+ size_t i;
+
+ string_set_init (&set);
+ check_string_set (&set, NULL, 0);
+ for (i = 0; i < cnt; i++)
+ {
+ check (string_set_insert (&set, make_string (insertions[i])));
+ check_string_set (&set, insertions, i + 1);
+ }
+ for (i = 0; i < cnt; i++)
+ {
+ check (string_set_delete (&set, make_string (deletions[i])));
+ check_string_set (&set, deletions + i + 1, cnt - i - 1);
+ }
+ string_set_destroy (&set);
+}
+\f
+/* Inserts strings into a set in each possible order, then removes them in each
+ possible order, up to a specified maximum size. */
+static void
+test_insert_any_remove_any (void)
+{
+ const int max_elems = 5;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *insertions, *deletions;
+ unsigned int ins_perm_cnt;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i;
+
+ for (ins_perm_cnt = 0;
+ ins_perm_cnt == 0 || next_permutation (insertions, cnt);
+ ins_perm_cnt++)
+ {
+ unsigned int del_perm_cnt;
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ deletions[i] = i;
+
+ for (del_perm_cnt = 0;
+ del_perm_cnt == 0 || next_permutation (deletions, cnt);
+ del_perm_cnt++)
+ test_insert_delete (insertions, deletions, cnt);
+
+ check (del_perm_cnt == factorial (cnt));
+ }
+ check (ins_perm_cnt == factorial (cnt));
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts strings into a set in each possible order, then removes them in the
+ same order, up to a specified maximum size. */
+static void
+test_insert_any_remove_same (void)
+{
+ const int max_elems = 7;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *values;
+ unsigned int permutation_cnt;
+ int i;
+
+ values = xnmalloc (cnt, sizeof *values);
+ for (i = 0; i < cnt; i++)
+ values[i] = i;
+
+ for (permutation_cnt = 0;
+ permutation_cnt == 0 || next_permutation (values, cnt);
+ permutation_cnt++)
+ test_insert_delete (values, values, cnt);
+ check (permutation_cnt == factorial (cnt));
+
+ free (values);
+ }
+}
+
+/* Inserts strings into a set in each possible order, then
+ removes them in reverse order, up to a specified maximum
+ size. */
+static void
+test_insert_any_remove_reverse (void)
+{
+ const int max_elems = 7;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt++)
+ {
+ int *insertions, *deletions;
+ unsigned int permutation_cnt;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i;
+
+ for (permutation_cnt = 0;
+ permutation_cnt == 0 || next_permutation (insertions, cnt);
+ permutation_cnt++)
+ {
+ memcpy (deletions, insertions, sizeof *insertions * cnt);
+ reverse (deletions, cnt);
+
+ test_insert_delete (insertions, deletions, cnt);
+ }
+ check (permutation_cnt == factorial (cnt));
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts and removes strings in a set, in random order. */
+static void
+test_random_sequence (void)
+{
+ const int max_elems = 64;
+ const int max_trials = 8;
+ int cnt;
+
+ for (cnt = 0; cnt <= max_elems; cnt += 2)
+ {
+ int *insertions, *deletions;
+ int trial;
+ int i;
+
+ insertions = xnmalloc (cnt, sizeof *insertions);
+ deletions = xnmalloc (cnt, sizeof *deletions);
+ for (i = 0; i < cnt; i++)
+ insertions[i] = i;
+ for (i = 0; i < cnt; i++)
+ deletions[i] = i;
+
+ for (trial = 0; trial < max_trials; trial++)
+ {
+ random_shuffle (insertions, cnt, sizeof *insertions);
+ random_shuffle (deletions, cnt, sizeof *deletions);
+
+ test_insert_delete (insertions, deletions, cnt);
+ }
+
+ free (insertions);
+ free (deletions);
+ }
+}
+
+/* Inserts strings into a set in ascending order, then delete in ascending
+ order. */
+static void
+test_insert_ordered (void)
+{
+ const int max_elems = 64;
+ int *values;
+ struct string_set set;
+ int i;
+
+ string_set_init (&set);
+ values = xnmalloc (max_elems, sizeof *values);
+ for (i = 0; i < max_elems; i++)
+ {
+ values[i] = i;
+ string_set_insert_nocopy (&set, xstrdup (make_string (i)));
+ check_string_set (&set, values, i + 1);
+ }
+ for (i = 0; i < max_elems; i++)
+ {
+ string_set_delete (&set, make_string (i));
+ check_string_set (&set, values + i + 1, max_elems - i - 1);
+ }
+ string_set_destroy (&set);
+ free (values);
+}
+
+static void
+test_boolean_ops (void (*function)(struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat))
+{
+ enum { MAX_STRINGS = 7 };
+ unsigned int a_pat, b_pat;
+
+ for (a_pat = 0; a_pat < (1u << MAX_STRINGS); a_pat++)
+ for (b_pat = 0; b_pat < (1u << MAX_STRINGS); b_pat++)
+ {
+ unsigned int new_a_pat = a_pat;
+ unsigned int new_b_pat = b_pat;
+ struct string_set a, b;
+ int a_strings[MAX_STRINGS], b_strings[MAX_STRINGS];
+ size_t i, n_a, n_b;
+
+ string_set_init (&a);
+ string_set_init (&b);
+ for (i = 0; i < MAX_STRINGS; i++)
+ {
+ if (a_pat & (1u << i))
+ string_set_insert (&a, make_string (i));
+ if (b_pat & (1u << i))
+ string_set_insert (&b, make_string (i));
+ }
+
+ function (&a, &b, &new_a_pat, &new_b_pat);
+
+ n_a = n_b = 0;
+ for (i = 0; i < MAX_STRINGS; i++)
+ {
+ if (new_a_pat & (1u << i))
+ a_strings[n_a++] = i;
+ if (new_b_pat & (1u << i))
+ b_strings[n_b++] = i;
+ }
+ check_string_set (&a, a_strings, n_a);
+ check_string_set (&b, b_strings, n_b);
+ string_set_destroy (&a);
+ string_set_destroy (&b);
+ }
+}
+
+static void
+union_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ string_set_union (a, b);
+ *a_pat |= *b_pat;
+}
+
+static void
+test_union (void)
+{
+ test_boolean_ops (union_cb);
+}
+
+static void
+union_and_intersection_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ unsigned int orig_a_pat = *a_pat;
+ unsigned int orig_b_pat = *b_pat;
+
+ string_set_union_and_intersection (a, b);
+ *a_pat = orig_a_pat | orig_b_pat;
+ *b_pat = orig_a_pat & orig_b_pat;
+}
+
+static void
+test_union_and_intersection (void)
+{
+ test_boolean_ops (union_and_intersection_cb);
+}
+
+static void
+intersect_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ string_set_intersect (a, b);
+ *a_pat &= *b_pat;
+}
+
+static void
+test_intersect (void)
+{
+ test_boolean_ops (intersect_cb);
+}
+
+static void
+subtract_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ string_set_subtract (a, b);
+ *a_pat &= ~*b_pat;
+}
+
+static void
+test_subtract (void)
+{
+ test_boolean_ops (subtract_cb);
+}
+
+static void
+swap_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ unsigned int tmp;
+ string_set_swap (a, b);
+ tmp = *a_pat;
+ *a_pat = *b_pat;
+ *b_pat = tmp;
+}
+
+static void
+test_swap (void)
+{
+ test_boolean_ops (swap_cb);
+}
+
+static void
+clear_cb (struct string_set *a, struct string_set *b UNUSED,
+ unsigned int *a_pat, unsigned int *b_pat UNUSED)
+{
+ string_set_clear (a);
+ *a_pat = 0;
+}
+
+static void
+test_clear (void)
+{
+ test_boolean_ops (clear_cb);
+}
+
+static void
+clone_cb (struct string_set *a, struct string_set *b,
+ unsigned int *a_pat, unsigned int *b_pat)
+{
+ string_set_destroy (a);
+ string_set_clone (a, b);
+ *a_pat = *b_pat;
+}
+
+static void
+test_clone (void)
+{
+ test_boolean_ops (clone_cb);
+}
+
+static void
+test_destroy_null (void)
+{
+ string_set_destroy (NULL);
+}
+\f
+/* Main program. */
+
+/* Runs TEST_FUNCTION and prints a message about NAME. */
+static void
+run_test (void (*test_function) (void), const char *name)
+{
+ test_name = name;
+ putchar ('.');
+ fflush (stdout);
+ test_function ();
+}
+
+int
+main (void)
+{
+ run_test (test_insert_any_remove_any, "insert any order, delete any order");
+ run_test (test_insert_any_remove_same,
+ "insert any order, delete same order");
+ run_test (test_insert_any_remove_reverse,
+ "insert any order, delete reverse order");
+ run_test (test_random_sequence, "insert and delete in random sequence");
+ run_test (test_insert_ordered, "insert in ascending order");
+ run_test (test_union, "union");
+ run_test (test_union_and_intersection, "union and intersection");
+ run_test (test_intersect, "intersect");
+ run_test (test_subtract, "subtract");
+ run_test (test_swap, "swap");
+ run_test (test_clear, "clear");
+ run_test (test_clone, "clone");
+ run_test (test_destroy_null, "destroying null table");
+
+ putchar ('\n');
+
+ free_strings ();
+
+ return 0;
+}