changeset 3274:5a691cbef111

[project @ 1999-10-12 05:21:34 by jwe]
author jwe
date Tue, 12 Oct 1999 05:24:13 +0000
parents eb27ea9b7ff8
children b9a024ee0312
files libcruft/lapack/dggbak.f libcruft/lapack/dtgevc.f libcruft/lapack/zggbal.f libcruft/ranlib/HOWTOGET libcruft/slatec-err/Makefile.in libcruft/slatec-err/fdump.f libcruft/slatec-err/j4save.f libcruft/slatec-err/xerclr.f libcruft/slatec-err/xercnt.f libcruft/slatec-err/xerhlt.f libcruft/slatec-err/xermsg.f libcruft/slatec-err/xerprn.f libcruft/slatec-err/xersve.f libcruft/slatec-err/xgetf.f libcruft/slatec-err/xgetua.f libcruft/slatec-err/xsetf.f libcruft/slatec-err/xsetua.f liboctave/strftime.c
diffstat 18 files changed, 3948 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/libcruft/lapack/dggbak.f
@@ -0,0 +1,216 @@
+      SUBROUTINE DGGBAK( JOB, SIDE, N, ILO, IHI, LSCALE, RSCALE, M, V,
+     $                   LDV, INFO )
+*
+*  -- LAPACK routine (version 2.0) --
+*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+*     Courant Institute, Argonne National Lab, and Rice University
+*     September 30, 1994
+*
+*     .. Scalar Arguments ..
+      CHARACTER          JOB, SIDE
+      INTEGER            IHI, ILO, INFO, LDV, M, N
+*     ..
+*     .. Array Arguments ..
+      DOUBLE PRECISION   LSCALE( * ), RSCALE( * ), V( LDV, * )
+*     ..
+*
+*  Purpose
+*  =======
+*
+*  DGGBAK forms the right or left eigenvectors of a real generalized
+*  eigenvalue problem A*x = lambda*B*x, by backward transformation on
+*  the computed eigenvectors of the balanced pair of matrices output by
+*  DGGBAL.
+*
+*  Arguments
+*  =========
+*
+*  JOB     (input) CHARACTER*1
+*          Specifies the type of backward transformation required:
+*          = 'N':  do nothing, return immediately;
+*          = 'P':  do backward transformation for permutation only;
+*          = 'S':  do backward transformation for scaling only;
+*          = 'B':  do backward transformations for both permutation and
+*                  scaling.
+*          JOB must be the same as the argument JOB supplied to DGGBAL.
+*
+*  SIDE    (input) CHARACTER*1
+*          = 'R':  V contains right eigenvectors;
+*          = 'L':  V contains left eigenvectors.
+*
+*  N       (input) INTEGER
+*          The number of rows of the matrix V.  N >= 0.
+*
+*  ILO     (input) INTEGER
+*  IHI     (input) INTEGER
+*          The integers ILO and IHI determined by DGGBAL.
+*          1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0.
+*
+*  LSCALE  (input) DOUBLE PRECISION array, dimension (N)
+*          Details of the permutations and/or scaling factors applied
+*          to the left side of A and B, as returned by DGGBAL.
+*
+*  RSCALE  (input) DOUBLE PRECISION array, dimension (N)
+*          Details of the permutations and/or scaling factors applied
+*          to the right side of A and B, as returned by DGGBAL.
+*
+*  M       (input) INTEGER
+*          The number of columns of the matrix V.  M >= 0.
+*
+*  V       (input/output) DOUBLE PRECISION array, dimension (LDV,M)
+*          On entry, the matrix of right or left eigenvectors to be
+*          transformed, as returned by DTGEVC.
+*          On exit, V is overwritten by the transformed eigenvectors.
+*
+*  LDV     (input) INTEGER
+*          The leading dimension of the matrix V. LDV >= max(1,N).
+*
+*  INFO    (output) INTEGER
+*          = 0:  successful exit.
+*          < 0:  if INFO = -i, the i-th argument had an illegal value.
+*
+*  Further Details
+*  ===============
+*
+*  See R.C. Ward, Balancing the generalized eigenvalue problem,
+*                 SIAM J. Sci. Stat. Comp. 2 (1981), 141-152.
+*
+*  =====================================================================
+*
+*     .. Local Scalars ..
+      LOGICAL            LEFTV, RIGHTV
+      INTEGER            I, K
+*     ..
+*     .. External Functions ..
+      LOGICAL            LSAME
+      EXTERNAL           LSAME
+*     ..
+*     .. External Subroutines ..
+      EXTERNAL           DSCAL, DSWAP, XERBLA
+*     ..
+*     .. Intrinsic Functions ..
+      INTRINSIC          MAX
+*     ..
+*     .. Executable Statements ..
+*
+*     Test the input parameters
+*
+      RIGHTV = LSAME( SIDE, 'R' )
+      LEFTV = LSAME( SIDE, 'L' )
+*
+      INFO = 0
+      IF( .NOT.LSAME( JOB, 'N' ) .AND. .NOT.LSAME( JOB, 'P' ) .AND.
+     $    .NOT.LSAME( JOB, 'S' ) .AND. .NOT.LSAME( JOB, 'B' ) ) THEN
+         INFO = -1
+      ELSE IF( .NOT.RIGHTV .AND. .NOT.LEFTV ) THEN
+         INFO = -2
+      ELSE IF( N.LT.0 ) THEN
+         INFO = -3
+      ELSE IF( ILO.LT.1 ) THEN
+         INFO = -4
+      ELSE IF( IHI.LT.ILO .OR. IHI.GT.MAX( 1, N ) ) THEN
+         INFO = -5
+      ELSE IF( M.LT.0 ) THEN
+         INFO = -6
+      ELSE IF( LDV.LT.MAX( 1, N ) ) THEN
+         INFO = -10
+      END IF
+      IF( INFO.NE.0 ) THEN
+         CALL XERBLA( 'DGGBAK', -INFO )
+         RETURN
+      END IF
+*
+*     Quick return if possible
+*
+      IF( N.EQ.0 )
+     $   RETURN
+      IF( M.EQ.0 )
+     $   RETURN
+      IF( LSAME( JOB, 'N' ) )
+     $   RETURN
+*
+      IF( ILO.EQ.IHI )
+     $   GO TO 30
+*
+*     Backward balance
+*
+      IF( LSAME( JOB, 'S' ) .OR. LSAME( JOB, 'B' ) ) THEN
+*
+*        Backward transformation on right eigenvectors
+*
+         IF( RIGHTV ) THEN
+            DO 10 I = ILO, IHI
+               CALL DSCAL( M, RSCALE( I ), V( I, 1 ), LDV )
+   10       CONTINUE
+         END IF
+*
+*        Backward transformation on left eigenvectors
+*
+         IF( LEFTV ) THEN
+            DO 20 I = ILO, IHI
+               CALL DSCAL( M, LSCALE( I ), V( I, 1 ), LDV )
+   20       CONTINUE
+         END IF
+      END IF
+*
+*     Backward permutation
+*
+   30 CONTINUE
+      IF( LSAME( JOB, 'P' ) .OR. LSAME( JOB, 'B' ) ) THEN
+*
+*        Backward permutation on right eigenvectors
+*
+         IF( RIGHTV ) THEN
+            IF( ILO.EQ.1 )
+     $         GO TO 50
+*
+            DO 40 I = ILO - 1, 1, -1
+               K = RSCALE( I )
+               IF( K.EQ.I )
+     $            GO TO 40
+               CALL DSWAP( M, V( I, 1 ), LDV, V( K, 1 ), LDV )
+   40       CONTINUE
+*
+   50       CONTINUE
+            IF( IHI.EQ.N )
+     $         GO TO 70
+            DO 60 I = IHI + 1, N
+               K = RSCALE( I )
+               IF( K.EQ.I )
+     $            GO TO 60
+               CALL DSWAP( M, V( I, 1 ), LDV, V( K, 1 ), LDV )
+   60       CONTINUE
+         END IF
+*
+*        Backward permutation on left eigenvectors
+*
+   70    CONTINUE
+         IF( LEFTV ) THEN
+            IF( ILO.EQ.1 )
+     $         GO TO 90
+            DO 80 I = ILO - 1, 1, -1
+               K = LSCALE( I )
+               IF( K.EQ.I )
+     $            GO TO 80
+               CALL DSWAP( M, V( I, 1 ), LDV, V( K, 1 ), LDV )
+   80       CONTINUE
+*
+   90       CONTINUE
+            IF( IHI.EQ.N )
+     $         GO TO 110
+            DO 100 I = IHI + 1, N
+               K = LSCALE( I )
+               IF( K.EQ.I )
+     $            GO TO 100
+               CALL DSWAP( M, V( I, 1 ), LDV, V( K, 1 ), LDV )
+  100       CONTINUE
+         END IF
+      END IF
+*
+  110 CONTINUE
+*
+      RETURN
+*
+*     End of DGGBAK
+*
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/lapack/dtgevc.f
@@ -0,0 +1,1140 @@
+      SUBROUTINE DTGEVC( SIDE, HOWMNY, SELECT, N, A, LDA, B, LDB, VL,
+     $                   LDVL, VR, LDVR, MM, M, WORK, INFO )
+*
+*  -- LAPACK routine (version 2.0) --
+*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+*     Courant Institute, Argonne National Lab, and Rice University
+*     September 30, 1994
+*
+*     .. Scalar Arguments ..
+      CHARACTER          HOWMNY, SIDE
+      INTEGER            INFO, LDA, LDB, LDVL, LDVR, M, MM, N
+*     ..
+*     .. Array Arguments ..
+      LOGICAL            SELECT( * )
+      DOUBLE PRECISION   A( LDA, * ), B( LDB, * ), VL( LDVL, * ),
+     $                   VR( LDVR, * ), WORK( * )
+*     ..
+*
+*
+*  Purpose
+*  =======
+*
+*  DTGEVC computes some or all of the right and/or left generalized
+*  eigenvectors of a pair of real upper triangular matrices (A,B).
+*
+*  The right generalized eigenvector x and the left generalized
+*  eigenvector y of (A,B) corresponding to a generalized eigenvalue
+*  w are defined by:
+*
+*          (A - wB) * x = 0  and  y**H * (A - wB) = 0
+*
+*  where y**H denotes the conjugate tranpose of y.
+*
+*  If an eigenvalue w is determined by zero diagonal elements of both A
+*  and B, a unit vector is returned as the corresponding eigenvector.
+*
+*  If all eigenvectors are requested, the routine may either return
+*  the matrices X and/or Y of right or left eigenvectors of (A,B), or
+*  the products Z*X and/or Q*Y, where Z and Q are input orthogonal
+*  matrices.  If (A,B) was obtained from the generalized real-Schur
+*  factorization of an original pair of matrices
+*     (A0,B0) = (Q*A*Z**H,Q*B*Z**H),
+*  then Z*X and Q*Y are the matrices of right or left eigenvectors of
+*  A.
+*
+*  A must be block upper triangular, with 1-by-1 and 2-by-2 diagonal
+*  blocks.  Corresponding to each 2-by-2 diagonal block is a complex
+*  conjugate pair of eigenvalues and eigenvectors; only one
+*  eigenvector of the pair is computed, namely the one corresponding
+*  to the eigenvalue with positive imaginary part.
+*
+*  Arguments
+*  =========
+*
+*  SIDE    (input) CHARACTER*1
+*          = 'R': compute right eigenvectors only;
+*          = 'L': compute left eigenvectors only;
+*          = 'B': compute both right and left eigenvectors.
+*
+*  HOWMNY  (input) CHARACTER*1
+*          = 'A': compute all right and/or left eigenvectors;
+*          = 'B': compute all right and/or left eigenvectors, and
+*                 backtransform them using the input matrices supplied
+*                 in VR and/or VL;
+*          = 'S': compute selected right and/or left eigenvectors,
+*                 specified by the logical array SELECT.
+*
+*  SELECT  (input) LOGICAL array, dimension (N)
+*          If HOWMNY='S', SELECT specifies the eigenvectors to be
+*          computed.
+*          If HOWMNY='A' or 'B', SELECT is not referenced.
+*          To select the real eigenvector corresponding to the real
+*          eigenvalue w(j), SELECT(j) must be set to .TRUE.  To select
+*          the complex eigenvector corresponding to a complex conjugate
+*          pair w(j) and w(j+1), either SELECT(j) or SELECT(j+1) must
+*          be set to .TRUE..
+*
+*  N       (input) INTEGER
+*          The order of the matrices A and B.  N >= 0.
+*
+*  A       (input) DOUBLE PRECISION array, dimension (LDA,N)
+*          The upper quasi-triangular matrix A.
+*
+*  LDA     (input) INTEGER
+*          The leading dimension of array A.  LDA >= max(1, N).
+*
+*  B       (input) DOUBLE PRECISION array, dimension (LDB,N)
+*          The upper triangular matrix B.  If A has a 2-by-2 diagonal
+*          block, then the corresponding 2-by-2 block of B must be
+*          diagonal with positive elements.
+*
+*  LDB     (input) INTEGER
+*          The leading dimension of array B.  LDB >= max(1,N).
+*
+*  VL      (input/output) DOUBLE PRECISION array, dimension (LDVL,MM)
+*          On entry, if SIDE = 'L' or 'B' and HOWMNY = 'B', VL must
+*          contain an N-by-N matrix Q (usually the orthogonal matrix Q
+*          of left Schur vectors returned by DHGEQZ).
+*          On exit, if SIDE = 'L' or 'B', VL contains:
+*          if HOWMNY = 'A', the matrix Y of left eigenvectors of (A,B);
+*          if HOWMNY = 'B', the matrix Q*Y;
+*          if HOWMNY = 'S', the left eigenvectors of (A,B) specified by
+*                      SELECT, stored consecutively in the columns of
+*                      VL, in the same order as their eigenvalues.
+*          If SIDE = 'R', VL is not referenced.
+*
+*          A complex eigenvector corresponding to a complex eigenvalue
+*          is stored in two consecutive columns, the first holding the
+*          real part, and the second the imaginary part.
+*
+*  LDVL    (input) INTEGER
+*          The leading dimension of array VL.
+*          LDVL >= max(1,N) if SIDE = 'L' or 'B'; LDVL >= 1 otherwise.
+*
+*  VR      (input/output) COMPLEX*16 array, dimension (LDVR,MM)
+*          On entry, if SIDE = 'R' or 'B' and HOWMNY = 'B', VR must
+*          contain an N-by-N matrix Q (usually the orthogonal matrix Z
+*          of right Schur vectors returned by DHGEQZ).
+*          On exit, if SIDE = 'R' or 'B', VR contains:
+*          if HOWMNY = 'A', the matrix X of right eigenvectors of (A,B);
+*          if HOWMNY = 'B', the matrix Z*X;
+*          if HOWMNY = 'S', the right eigenvectors of (A,B) specified by
+*                      SELECT, stored consecutively in the columns of
+*                      VR, in the same order as their eigenvalues.
+*          If SIDE = 'L', VR is not referenced.
+*
+*          A complex eigenvector corresponding to a complex eigenvalue
+*          is stored in two consecutive columns, the first holding the
+*          real part and the second the imaginary part.
+*
+*  LDVR    (input) INTEGER
+*          The leading dimension of the array VR.
+*          LDVR >= max(1,N) if SIDE = 'R' or 'B'; LDVR >= 1 otherwise.
+*
+*  MM      (input) INTEGER
+*          The number of columns in the arrays VL and/or VR. MM >= M.
+*
+*  M       (output) INTEGER
+*          The number of columns in the arrays VL and/or VR actually
+*          used to store the eigenvectors.  If HOWMNY = 'A' or 'B', M
+*          is set to N.  Each selected real eigenvector occupies one
+*          column and each selected complex eigenvector occupies two
+*          columns.
+*
+*  WORK    (workspace) DOUBLE PRECISION array, dimension (6*N)
+*
+*  INFO    (output) INTEGER
+*          = 0:  successful exit.
+*          < 0:  if INFO = -i, the i-th argument had an illegal value.
+*          > 0:  the 2-by-2 block (INFO:INFO+1) does not have a complex
+*                eigenvalue.
+*
+*  Further Details
+*  ===============
+*
+*  Allocation of workspace:
+*  ---------- -- ---------
+*
+*     WORK( j ) = 1-norm of j-th column of A, above the diagonal
+*     WORK( N+j ) = 1-norm of j-th column of B, above the diagonal
+*     WORK( 2*N+1:3*N ) = real part of eigenvector
+*     WORK( 3*N+1:4*N ) = imaginary part of eigenvector
+*     WORK( 4*N+1:5*N ) = real part of back-transformed eigenvector
+*     WORK( 5*N+1:6*N ) = imaginary part of back-transformed eigenvector
+*
+*  Rowwise vs. columnwise solution methods:
+*  ------- --  ---------- -------- -------
+*
+*  Finding a generalized eigenvector consists basically of solving the
+*  singular triangular system
+*
+*   (A - w B) x = 0     (for right) or:   (A - w B)**H y = 0  (for left)
+*
+*  Consider finding the i-th right eigenvector (assume all eigenvalues
+*  are real). The equation to be solved is:
+*       n                   i
+*  0 = sum  C(j,k) v(k)  = sum  C(j,k) v(k)     for j = i,. . .,1
+*      k=j                 k=j
+*
+*  where  C = (A - w B)  (The components v(i+1:n) are 0.)
+*
+*  The "rowwise" method is:
+*
+*  (1)  v(i) := 1
+*  for j = i-1,. . .,1:
+*                          i
+*      (2) compute  s = - sum C(j,k) v(k)   and
+*                        k=j+1
+*
+*      (3) v(j) := s / C(j,j)
+*
+*  Step 2 is sometimes called the "dot product" step, since it is an
+*  inner product between the j-th row and the portion of the eigenvector
+*  that has been computed so far.
+*
+*  The "columnwise" method consists basically in doing the sums
+*  for all the rows in parallel.  As each v(j) is computed, the
+*  contribution of v(j) times the j-th column of C is added to the
+*  partial sums.  Since FORTRAN arrays are stored columnwise, this has
+*  the advantage that at each step, the elements of C that are accessed
+*  are adjacent to one another, whereas with the rowwise method, the
+*  elements accessed at a step are spaced LDA (and LDB) words apart.
+*
+*  When finding left eigenvectors, the matrix in question is the
+*  transpose of the one in storage, so the rowwise method then
+*  actually accesses columns of A and B at each step, and so is the
+*  preferred method.
+*
+*  =====================================================================
+*
+*     .. Parameters ..
+      DOUBLE PRECISION   ZERO, ONE, SAFETY
+      PARAMETER          ( ZERO = 0.0D+0, ONE = 1.0D+0,
+     $                   SAFETY = 1.0D+2 )
+*     ..
+*     .. Local Scalars ..
+      LOGICAL            COMPL, COMPR, IL2BY2, ILABAD, ILALL, ILBACK,
+     $                   ILBBAD, ILCOMP, ILCPLX, LSA, LSB
+      INTEGER            I, IBEG, IEIG, IEND, IHWMNY, IINFO, IM, ISIDE,
+     $                   J, JA, JC, JE, JR, JW, NA, NW
+      DOUBLE PRECISION   ACOEF, ACOEFA, ANORM, ASCALE, BCOEFA, BCOEFI,
+     $                   BCOEFR, BIG, BIGNUM, BNORM, BSCALE, CIM2A,
+     $                   CIM2B, CIMAGA, CIMAGB, CRE2A, CRE2B, CREALA,
+     $                   CREALB, DMIN, SAFMIN, SALFAR, SBETA, SCALE,
+     $                   SMALL, TEMP, TEMP2, TEMP2I, TEMP2R, ULP, XMAX,
+     $                   XSCALE
+*     ..
+*     .. Local Arrays ..
+      DOUBLE PRECISION   BDIAG( 2 ), SUM( 2, 2 ), SUMA( 2, 2 ),
+     $                   SUMB( 2, 2 )
+*     ..
+*     .. External Functions ..
+      LOGICAL            LSAME
+      DOUBLE PRECISION   DLAMCH
+      EXTERNAL           LSAME, DLAMCH
+*     ..
+*     .. External Subroutines ..
+      EXTERNAL           DGEMV, DLABAD, DLACPY, DLAG2, DLALN2, XERBLA
+*     ..
+*     .. Intrinsic Functions ..
+      INTRINSIC          ABS, MAX, MIN
+*     ..
+*     .. Executable Statements ..
+*
+*     Decode and Test the input parameters
+*
+      IF( LSAME( HOWMNY, 'A' ) ) THEN
+         IHWMNY = 1
+         ILALL = .TRUE.
+         ILBACK = .FALSE.
+      ELSE IF( LSAME( HOWMNY, 'S' ) ) THEN
+         IHWMNY = 2
+         ILALL = .FALSE.
+         ILBACK = .FALSE.
+      ELSE IF( LSAME( HOWMNY, 'B' ) .OR. LSAME( HOWMNY, 'T' ) ) THEN
+         IHWMNY = 3
+         ILALL = .TRUE.
+         ILBACK = .TRUE.
+      ELSE
+         IHWMNY = -1
+         ILALL = .TRUE.
+      END IF
+*
+      IF( LSAME( SIDE, 'R' ) ) THEN
+         ISIDE = 1
+         COMPL = .FALSE.
+         COMPR = .TRUE.
+      ELSE IF( LSAME( SIDE, 'L' ) ) THEN
+         ISIDE = 2
+         COMPL = .TRUE.
+         COMPR = .FALSE.
+      ELSE IF( LSAME( SIDE, 'B' ) ) THEN
+         ISIDE = 3
+         COMPL = .TRUE.
+         COMPR = .TRUE.
+      ELSE
+         ISIDE = -1
+      END IF
+*
+*     Count the number of eigenvectors to be computed
+*
+      IF( .NOT.ILALL ) THEN
+         IM = 0
+         ILCPLX = .FALSE.
+         DO 10 J = 1, N
+            IF( ILCPLX ) THEN
+               ILCPLX = .FALSE.
+               GO TO 10
+            END IF
+            IF( J.LT.N ) THEN
+               IF( A( J+1, J ).NE.ZERO )
+     $            ILCPLX = .TRUE.
+            END IF
+            IF( ILCPLX ) THEN
+               IF( SELECT( J ) .OR. SELECT( J+1 ) )
+     $            IM = IM + 2
+            ELSE
+               IF( SELECT( J ) )
+     $            IM = IM + 1
+            END IF
+   10    CONTINUE
+      ELSE
+         IM = N
+      END IF
+*
+*     Check 2-by-2 diagonal blocks of A, B
+*
+      ILABAD = .FALSE.
+      ILBBAD = .FALSE.
+      DO 20 J = 1, N - 1
+         IF( A( J+1, J ).NE.ZERO ) THEN
+            IF( B( J, J ).EQ.ZERO .OR. B( J+1, J+1 ).EQ.ZERO .OR.
+     $          B( J, J+1 ).NE.ZERO )ILBBAD = .TRUE.
+            IF( J.LT.N-1 ) THEN
+               IF( A( J+2, J+1 ).NE.ZERO )
+     $            ILABAD = .TRUE.
+            END IF
+         END IF
+   20 CONTINUE
+*
+      INFO = 0
+      IF( ISIDE.LT.0 ) THEN
+         INFO = -1
+      ELSE IF( IHWMNY.LT.0 ) THEN
+         INFO = -2
+      ELSE IF( N.LT.0 ) THEN
+         INFO = -4
+      ELSE IF( ILABAD ) THEN
+         INFO = -5
+      ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
+         INFO = -6
+      ELSE IF( ILBBAD ) THEN
+         INFO = -7
+      ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
+         INFO = -8
+      ELSE IF( COMPL .AND. LDVL.LT.N .OR. LDVL.LT.1 ) THEN
+         INFO = -10
+      ELSE IF( COMPR .AND. LDVR.LT.N .OR. LDVR.LT.1 ) THEN
+         INFO = -12
+      ELSE IF( MM.LT.IM ) THEN
+         INFO = -13
+      END IF
+      IF( INFO.NE.0 ) THEN
+         CALL XERBLA( 'DTGEVC', -INFO )
+         RETURN
+      END IF
+*
+*     Quick return if possible
+*
+      M = IM
+      IF( N.EQ.0 )
+     $   RETURN
+*
+*     Machine Constants
+*
+      SAFMIN = DLAMCH( 'Safe minimum' )
+      BIG = ONE / SAFMIN
+      CALL DLABAD( SAFMIN, BIG )
+      ULP = DLAMCH( 'Epsilon' )*DLAMCH( 'Base' )
+      SMALL = SAFMIN*N / ULP
+      BIG = ONE / SMALL
+      BIGNUM = ONE / ( SAFMIN*N )
+*
+*     Compute the 1-norm of each column of the strictly upper triangular
+*     part (i.e., excluding all elements belonging to the diagonal
+*     blocks) of A and B to check for possible overflow in the
+*     triangular solver.
+*
+      ANORM = ABS( A( 1, 1 ) )
+      IF( N.GT.1 )
+     $   ANORM = ANORM + ABS( A( 2, 1 ) )
+      BNORM = ABS( B( 1, 1 ) )
+      WORK( 1 ) = ZERO
+      WORK( N+1 ) = ZERO
+*
+      DO 50 J = 2, N
+         TEMP = ZERO
+         TEMP2 = ZERO
+         IF( A( J, J-1 ).EQ.ZERO ) THEN
+            IEND = J - 1
+         ELSE
+            IEND = J - 2
+         END IF
+         DO 30 I = 1, IEND
+            TEMP = TEMP + ABS( A( I, J ) )
+            TEMP2 = TEMP2 + ABS( B( I, J ) )
+   30    CONTINUE
+         WORK( J ) = TEMP
+         WORK( N+J ) = TEMP2
+         DO 40 I = IEND + 1, MIN( J+1, N )
+            TEMP = TEMP + ABS( A( I, J ) )
+            TEMP2 = TEMP2 + ABS( B( I, J ) )
+   40    CONTINUE
+         ANORM = MAX( ANORM, TEMP )
+         BNORM = MAX( BNORM, TEMP2 )
+   50 CONTINUE
+*
+      ASCALE = ONE / MAX( ANORM, SAFMIN )
+      BSCALE = ONE / MAX( BNORM, SAFMIN )
+*
+*     Left eigenvectors
+*
+      IF( COMPL ) THEN
+         IEIG = 0
+*
+*        Main loop over eigenvalues
+*
+         ILCPLX = .FALSE.
+         DO 220 JE = 1, N
+*
+*           Skip this iteration if (a) HOWMNY='S' and SELECT=.FALSE., or
+*           (b) this would be the second of a complex pair.
+*           Check for complex eigenvalue, so as to be sure of which
+*           entry(-ies) of SELECT to look at.
+*
+            IF( ILCPLX ) THEN
+               ILCPLX = .FALSE.
+               GO TO 220
+            END IF
+            NW = 1
+            IF( JE.LT.N ) THEN
+               IF( A( JE+1, JE ).NE.ZERO ) THEN
+                  ILCPLX = .TRUE.
+                  NW = 2
+               END IF
+            END IF
+            IF( ILALL ) THEN
+               ILCOMP = .TRUE.
+            ELSE IF( ILCPLX ) THEN
+               ILCOMP = SELECT( JE ) .OR. SELECT( JE+1 )
+            ELSE
+               ILCOMP = SELECT( JE )
+            END IF
+            IF( .NOT.ILCOMP )
+     $         GO TO 220
+*
+*           Decide if (a) singular pencil, (b) real eigenvalue, or
+*           (c) complex eigenvalue.
+*
+            IF( .NOT.ILCPLX ) THEN
+               IF( ABS( A( JE, JE ) ).LE.SAFMIN .AND.
+     $             ABS( B( JE, JE ) ).LE.SAFMIN ) THEN
+*
+*                 Singular matrix pencil -- return unit eigenvector
+*
+                  IEIG = IEIG + 1
+                  DO 60 JR = 1, N
+                     VL( JR, IEIG ) = ZERO
+   60             CONTINUE
+                  VL( IEIG, IEIG ) = ONE
+                  GO TO 220
+               END IF
+            END IF
+*
+*           Clear vector
+*
+            DO 70 JR = 1, NW*N
+               WORK( 2*N+JR ) = ZERO
+   70       CONTINUE
+*                                                 T
+*           Compute coefficients in  ( a A - b B )  y = 0
+*              a  is  ACOEF
+*              b  is  BCOEFR + i*BCOEFI
+*
+            IF( .NOT.ILCPLX ) THEN
+*
+*              Real eigenvalue
+*
+               TEMP = ONE / MAX( ABS( A( JE, JE ) )*ASCALE,
+     $                ABS( B( JE, JE ) )*BSCALE, SAFMIN )
+               SALFAR = ( TEMP*A( JE, JE ) )*ASCALE
+               SBETA = ( TEMP*B( JE, JE ) )*BSCALE
+               ACOEF = SBETA*ASCALE
+               BCOEFR = SALFAR*BSCALE
+               BCOEFI = ZERO
+*
+*              Scale to avoid underflow
+*
+               SCALE = ONE
+               LSA = ABS( SBETA ).GE.SAFMIN .AND. ABS( ACOEF ).LT.SMALL
+               LSB = ABS( SALFAR ).GE.SAFMIN .AND. ABS( BCOEFR ).LT.
+     $               SMALL
+               IF( LSA )
+     $            SCALE = ( SMALL / ABS( SBETA ) )*MIN( ANORM, BIG )
+               IF( LSB )
+     $            SCALE = MAX( SCALE, ( SMALL / ABS( SALFAR ) )*
+     $                    MIN( BNORM, BIG ) )
+               IF( LSA .OR. LSB ) THEN
+                  SCALE = MIN( SCALE, ONE /
+     $                    ( SAFMIN*MAX( ONE, ABS( ACOEF ),
+     $                    ABS( BCOEFR ) ) ) )
+                  IF( LSA ) THEN
+                     ACOEF = ASCALE*( SCALE*SBETA )
+                  ELSE
+                     ACOEF = SCALE*ACOEF
+                  END IF
+                  IF( LSB ) THEN
+                     BCOEFR = BSCALE*( SCALE*SALFAR )
+                  ELSE
+                     BCOEFR = SCALE*BCOEFR
+                  END IF
+               END IF
+               ACOEFA = ABS( ACOEF )
+               BCOEFA = ABS( BCOEFR )
+*
+*              First component is 1
+*
+               WORK( 2*N+JE ) = ONE
+               XMAX = ONE
+            ELSE
+*
+*              Complex eigenvalue
+*
+               CALL DLAG2( A( JE, JE ), LDA, B( JE, JE ), LDB,
+     $                     SAFMIN*SAFETY, ACOEF, TEMP, BCOEFR, TEMP2,
+     $                     BCOEFI )
+               BCOEFI = -BCOEFI
+               IF( BCOEFI.EQ.ZERO ) THEN
+                  INFO = JE
+                  RETURN
+               END IF
+*
+*              Scale to avoid over/underflow
+*
+               ACOEFA = ABS( ACOEF )
+               BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
+               SCALE = ONE
+               IF( ACOEFA*ULP.LT.SAFMIN .AND. ACOEFA.GE.SAFMIN )
+     $            SCALE = ( SAFMIN / ULP ) / ACOEFA
+               IF( BCOEFA*ULP.LT.SAFMIN .AND. BCOEFA.GE.SAFMIN )
+     $            SCALE = MAX( SCALE, ( SAFMIN / ULP ) / BCOEFA )
+               IF( SAFMIN*ACOEFA.GT.ASCALE )
+     $            SCALE = ASCALE / ( SAFMIN*ACOEFA )
+               IF( SAFMIN*BCOEFA.GT.BSCALE )
+     $            SCALE = MIN( SCALE, BSCALE / ( SAFMIN*BCOEFA ) )
+               IF( SCALE.NE.ONE ) THEN
+                  ACOEF = SCALE*ACOEF
+                  ACOEFA = ABS( ACOEF )
+                  BCOEFR = SCALE*BCOEFR
+                  BCOEFI = SCALE*BCOEFI
+                  BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
+               END IF
+*
+*              Compute first two components of eigenvector
+*
+               TEMP = ACOEF*A( JE+1, JE )
+               TEMP2R = ACOEF*A( JE, JE ) - BCOEFR*B( JE, JE )
+               TEMP2I = -BCOEFI*B( JE, JE )
+               IF( ABS( TEMP ).GT.ABS( TEMP2R )+ABS( TEMP2I ) ) THEN
+                  WORK( 2*N+JE ) = ONE
+                  WORK( 3*N+JE ) = ZERO
+                  WORK( 2*N+JE+1 ) = -TEMP2R / TEMP
+                  WORK( 3*N+JE+1 ) = -TEMP2I / TEMP
+               ELSE
+                  WORK( 2*N+JE+1 ) = ONE
+                  WORK( 3*N+JE+1 ) = ZERO
+                  TEMP = ACOEF*A( JE, JE+1 )
+                  WORK( 2*N+JE ) = ( BCOEFR*B( JE+1, JE+1 )-ACOEF*
+     $                             A( JE+1, JE+1 ) ) / TEMP
+                  WORK( 3*N+JE ) = BCOEFI*B( JE+1, JE+1 ) / TEMP
+               END IF
+               XMAX = MAX( ABS( WORK( 2*N+JE ) )+ABS( WORK( 3*N+JE ) ),
+     $                ABS( WORK( 2*N+JE+1 ) )+ABS( WORK( 3*N+JE+1 ) ) )
+            END IF
+*
+            DMIN = MAX( ULP*ACOEFA*ANORM, ULP*BCOEFA*BNORM, SAFMIN )
+*
+*                                           T
+*           Triangular solve of  (a A - b B)  y = 0
+*
+*                                   T
+*           (rowwise in  (a A - b B) , or columnwise in (a A - b B) )
+*
+            IL2BY2 = .FALSE.
+*
+            DO 160 J = JE + NW, N
+               IF( IL2BY2 ) THEN
+                  IL2BY2 = .FALSE.
+                  GO TO 160
+               END IF
+*
+               NA = 1
+               BDIAG( 1 ) = B( J, J )
+               IF( J.LT.N ) THEN
+                  IF( A( J+1, J ).NE.ZERO ) THEN
+                     IL2BY2 = .TRUE.
+                     BDIAG( 2 ) = B( J+1, J+1 )
+                     NA = 2
+                  END IF
+               END IF
+*
+*              Check whether scaling is necessary for dot products
+*
+               XSCALE = ONE / MAX( ONE, XMAX )
+               TEMP = MAX( WORK( J ), WORK( N+J ),
+     $                ACOEFA*WORK( J )+BCOEFA*WORK( N+J ) )
+               IF( IL2BY2 )
+     $            TEMP = MAX( TEMP, WORK( J+1 ), WORK( N+J+1 ),
+     $                   ACOEFA*WORK( J+1 )+BCOEFA*WORK( N+J+1 ) )
+               IF( TEMP.GT.BIGNUM*XSCALE ) THEN
+                  DO 90 JW = 0, NW - 1
+                     DO 80 JR = JE, J - 1
+                        WORK( ( JW+2 )*N+JR ) = XSCALE*
+     $                     WORK( ( JW+2 )*N+JR )
+   80                CONTINUE
+   90             CONTINUE
+                  XMAX = XMAX*XSCALE
+               END IF
+*
+*              Compute dot products
+*
+*                    j-1
+*              SUM = sum  conjg( a*A(k,j) - b*B(k,j) )*x(k)
+*                    k=je
+*
+*              To reduce the op count, this is done as
+*
+*              _        j-1                  _        j-1
+*              a*conjg( sum  A(k,j)*x(k) ) - b*conjg( sum  B(k,j)*x(k) )
+*                       k=je                          k=je
+*
+*              which may cause underflow problems if A or B are close
+*              to underflow.  (E.g., less than SMALL.)
+*
+*
+*              A series of compiler directives to defeat vectorization
+*              for the next loop
+*
+*$PL$ CMCHAR=' '
+CDIR$          NEXTSCALAR
+C$DIR          SCALAR
+CDIR$          NEXT SCALAR
+CVD$L          NOVECTOR
+CDEC$          NOVECTOR
+CVD$           NOVECTOR
+*VDIR          NOVECTOR
+*VOCL          LOOP,SCALAR
+CIBM           PREFER SCALAR
+*$PL$ CMCHAR='*'
+*
+               DO 120 JW = 1, NW
+*
+*$PL$ CMCHAR=' '
+CDIR$             NEXTSCALAR
+C$DIR             SCALAR
+CDIR$             NEXT SCALAR
+CVD$L             NOVECTOR
+CDEC$             NOVECTOR
+CVD$              NOVECTOR
+*VDIR             NOVECTOR
+*VOCL             LOOP,SCALAR
+CIBM              PREFER SCALAR
+*$PL$ CMCHAR='*'
+*
+                  DO 110 JA = 1, NA
+                     SUMA( JA, JW ) = ZERO
+                     SUMB( JA, JW ) = ZERO
+*
+                     DO 100 JR = JE, J - 1
+                        SUMA( JA, JW ) = SUMA( JA, JW ) +
+     $                                   A( JR, J+JA-1 )*
+     $                                   WORK( ( JW+1 )*N+JR )
+                        SUMB( JA, JW ) = SUMB( JA, JW ) +
+     $                                   B( JR, J+JA-1 )*
+     $                                   WORK( ( JW+1 )*N+JR )
+  100                CONTINUE
+  110             CONTINUE
+  120          CONTINUE
+*
+*$PL$ CMCHAR=' '
+CDIR$          NEXTSCALAR
+C$DIR          SCALAR
+CDIR$          NEXT SCALAR
+CVD$L          NOVECTOR
+CDEC$          NOVECTOR
+CVD$           NOVECTOR
+*VDIR          NOVECTOR
+*VOCL          LOOP,SCALAR
+CIBM           PREFER SCALAR
+*$PL$ CMCHAR='*'
+*
+               DO 130 JA = 1, NA
+                  IF( ILCPLX ) THEN
+                     SUM( JA, 1 ) = -ACOEF*SUMA( JA, 1 ) +
+     $                              BCOEFR*SUMB( JA, 1 ) -
+     $                              BCOEFI*SUMB( JA, 2 )
+                     SUM( JA, 2 ) = -ACOEF*SUMA( JA, 2 ) +
+     $                              BCOEFR*SUMB( JA, 2 ) +
+     $                              BCOEFI*SUMB( JA, 1 )
+                  ELSE
+                     SUM( JA, 1 ) = -ACOEF*SUMA( JA, 1 ) +
+     $                              BCOEFR*SUMB( JA, 1 )
+                  END IF
+  130          CONTINUE
+*
+*                                  T
+*              Solve  ( a A - b B )  y = SUM(,)
+*              with scaling and perturbation of the denominator
+*
+               CALL DLALN2( .TRUE., NA, NW, DMIN, ACOEF, A( J, J ), LDA,
+     $                      BDIAG( 1 ), BDIAG( 2 ), SUM, 2, BCOEFR,
+     $                      BCOEFI, WORK( 2*N+J ), N, SCALE, TEMP,
+     $                      IINFO )
+               IF( SCALE.LT.ONE ) THEN
+                  DO 150 JW = 0, NW - 1
+                     DO 140 JR = JE, J - 1
+                        WORK( ( JW+2 )*N+JR ) = SCALE*
+     $                     WORK( ( JW+2 )*N+JR )
+  140                CONTINUE
+  150             CONTINUE
+                  XMAX = SCALE*XMAX
+               END IF
+               XMAX = MAX( XMAX, TEMP )
+  160       CONTINUE
+*
+*           Copy eigenvector to VL, back transforming if
+*           HOWMNY='B'.
+*
+            IEIG = IEIG + 1
+            IF( ILBACK ) THEN
+               DO 170 JW = 0, NW - 1
+                  CALL DGEMV( 'N', N, N+1-JE, ONE, VL( 1, JE ), LDVL,
+     $                        WORK( ( JW+2 )*N+JE ), 1, ZERO,
+     $                        WORK( ( JW+4 )*N+1 ), 1 )
+  170          CONTINUE
+               CALL DLACPY( ' ', N, NW, WORK( 4*N+1 ), N, VL( 1, JE ),
+     $                      LDVL )
+               IBEG = 1
+            ELSE
+               CALL DLACPY( ' ', N, NW, WORK( 2*N+1 ), N, VL( 1, IEIG ),
+     $                      LDVL )
+               IBEG = JE
+            END IF
+*
+*           Scale eigenvector
+*
+            XMAX = ZERO
+            IF( ILCPLX ) THEN
+               DO 180 J = IBEG, N
+                  XMAX = MAX( XMAX, ABS( VL( J, IEIG ) )+
+     $                   ABS( VL( J, IEIG+1 ) ) )
+  180          CONTINUE
+            ELSE
+               DO 190 J = IBEG, N
+                  XMAX = MAX( XMAX, ABS( VL( J, IEIG ) ) )
+  190          CONTINUE
+            END IF
+*
+            IF( XMAX.GT.SAFMIN ) THEN
+               XSCALE = ONE / XMAX
+*
+               DO 210 JW = 0, NW - 1
+                  DO 200 JR = IBEG, N
+                     VL( JR, IEIG+JW ) = XSCALE*VL( JR, IEIG+JW )
+  200             CONTINUE
+  210          CONTINUE
+            END IF
+            IEIG = IEIG + NW - 1
+*
+  220    CONTINUE
+      END IF
+*
+*     Right eigenvectors
+*
+      IF( COMPR ) THEN
+         IEIG = IM + 1
+*
+*        Main loop over eigenvalues
+*
+         ILCPLX = .FALSE.
+         DO 500 JE = N, 1, -1
+*
+*           Skip this iteration if (a) HOWMNY='S' and SELECT=.FALSE., or
+*           (b) this would be the second of a complex pair.
+*           Check for complex eigenvalue, so as to be sure of which
+*           entry(-ies) of SELECT to look at -- if complex, SELECT(JE)
+*           or SELECT(JE-1).
+*           If this is a complex pair, the 2-by-2 diagonal block
+*           corresponding to the eigenvalue is in rows/columns JE-1:JE
+*
+            IF( ILCPLX ) THEN
+               ILCPLX = .FALSE.
+               GO TO 500
+            END IF
+            NW = 1
+            IF( JE.GT.1 ) THEN
+               IF( A( JE, JE-1 ).NE.ZERO ) THEN
+                  ILCPLX = .TRUE.
+                  NW = 2
+               END IF
+            END IF
+            IF( ILALL ) THEN
+               ILCOMP = .TRUE.
+            ELSE IF( ILCPLX ) THEN
+               ILCOMP = SELECT( JE ) .OR. SELECT( JE-1 )
+            ELSE
+               ILCOMP = SELECT( JE )
+            END IF
+            IF( .NOT.ILCOMP )
+     $         GO TO 500
+*
+*           Decide if (a) singular pencil, (b) real eigenvalue, or
+*           (c) complex eigenvalue.
+*
+            IF( .NOT.ILCPLX ) THEN
+               IF( ABS( A( JE, JE ) ).LE.SAFMIN .AND.
+     $             ABS( B( JE, JE ) ).LE.SAFMIN ) THEN
+*
+*                 Singular matrix pencil -- unit eigenvector
+*
+                  IEIG = IEIG - 1
+                  DO 230 JR = 1, N
+                     VR( JR, IEIG ) = ZERO
+  230             CONTINUE
+                  VR( IEIG, IEIG ) = ONE
+                  GO TO 500
+               END IF
+            END IF
+*
+*           Clear vector
+*
+            DO 250 JW = 0, NW - 1
+               DO 240 JR = 1, N
+                  WORK( ( JW+2 )*N+JR ) = ZERO
+  240          CONTINUE
+  250       CONTINUE
+*
+*           Compute coefficients in  ( a A - b B ) x = 0
+*              a  is  ACOEF
+*              b  is  BCOEFR + i*BCOEFI
+*
+            IF( .NOT.ILCPLX ) THEN
+*
+*              Real eigenvalue
+*
+               TEMP = ONE / MAX( ABS( A( JE, JE ) )*ASCALE,
+     $                ABS( B( JE, JE ) )*BSCALE, SAFMIN )
+               SALFAR = ( TEMP*A( JE, JE ) )*ASCALE
+               SBETA = ( TEMP*B( JE, JE ) )*BSCALE
+               ACOEF = SBETA*ASCALE
+               BCOEFR = SALFAR*BSCALE
+               BCOEFI = ZERO
+*
+*              Scale to avoid underflow
+*
+               SCALE = ONE
+               LSA = ABS( SBETA ).GE.SAFMIN .AND. ABS( ACOEF ).LT.SMALL
+               LSB = ABS( SALFAR ).GE.SAFMIN .AND. ABS( BCOEFR ).LT.
+     $               SMALL
+               IF( LSA )
+     $            SCALE = ( SMALL / ABS( SBETA ) )*MIN( ANORM, BIG )
+               IF( LSB )
+     $            SCALE = MAX( SCALE, ( SMALL / ABS( SALFAR ) )*
+     $                    MIN( BNORM, BIG ) )
+               IF( LSA .OR. LSB ) THEN
+                  SCALE = MIN( SCALE, ONE /
+     $                    ( SAFMIN*MAX( ONE, ABS( ACOEF ),
+     $                    ABS( BCOEFR ) ) ) )
+                  IF( LSA ) THEN
+                     ACOEF = ASCALE*( SCALE*SBETA )
+                  ELSE
+                     ACOEF = SCALE*ACOEF
+                  END IF
+                  IF( LSB ) THEN
+                     BCOEFR = BSCALE*( SCALE*SALFAR )
+                  ELSE
+                     BCOEFR = SCALE*BCOEFR
+                  END IF
+               END IF
+               ACOEFA = ABS( ACOEF )
+               BCOEFA = ABS( BCOEFR )
+*
+*              First component is 1
+*
+               WORK( 2*N+JE ) = ONE
+               XMAX = ONE
+*
+*              Compute contribution from column JE of A and B to sum
+*              (See "Further Details", above.)
+*
+               DO 260 JR = 1, JE - 1
+                  WORK( 2*N+JR ) = BCOEFR*B( JR, JE ) -
+     $                             ACOEF*A( JR, JE )
+  260          CONTINUE
+            ELSE
+*
+*              Complex eigenvalue
+*
+               CALL DLAG2( A( JE-1, JE-1 ), LDA, B( JE-1, JE-1 ), LDB,
+     $                     SAFMIN*SAFETY, ACOEF, TEMP, BCOEFR, TEMP2,
+     $                     BCOEFI )
+               IF( BCOEFI.EQ.ZERO ) THEN
+                  INFO = JE - 1
+                  RETURN
+               END IF
+*
+*              Scale to avoid over/underflow
+*
+               ACOEFA = ABS( ACOEF )
+               BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
+               SCALE = ONE
+               IF( ACOEFA*ULP.LT.SAFMIN .AND. ACOEFA.GE.SAFMIN )
+     $            SCALE = ( SAFMIN / ULP ) / ACOEFA
+               IF( BCOEFA*ULP.LT.SAFMIN .AND. BCOEFA.GE.SAFMIN )
+     $            SCALE = MAX( SCALE, ( SAFMIN / ULP ) / BCOEFA )
+               IF( SAFMIN*ACOEFA.GT.ASCALE )
+     $            SCALE = ASCALE / ( SAFMIN*ACOEFA )
+               IF( SAFMIN*BCOEFA.GT.BSCALE )
+     $            SCALE = MIN( SCALE, BSCALE / ( SAFMIN*BCOEFA ) )
+               IF( SCALE.NE.ONE ) THEN
+                  ACOEF = SCALE*ACOEF
+                  ACOEFA = ABS( ACOEF )
+                  BCOEFR = SCALE*BCOEFR
+                  BCOEFI = SCALE*BCOEFI
+                  BCOEFA = ABS( BCOEFR ) + ABS( BCOEFI )
+               END IF
+*
+*              Compute first two components of eigenvector
+*              and contribution to sums
+*
+               TEMP = ACOEF*A( JE, JE-1 )
+               TEMP2R = ACOEF*A( JE, JE ) - BCOEFR*B( JE, JE )
+               TEMP2I = -BCOEFI*B( JE, JE )
+               IF( ABS( TEMP ).GE.ABS( TEMP2R )+ABS( TEMP2I ) ) THEN
+                  WORK( 2*N+JE ) = ONE
+                  WORK( 3*N+JE ) = ZERO
+                  WORK( 2*N+JE-1 ) = -TEMP2R / TEMP
+                  WORK( 3*N+JE-1 ) = -TEMP2I / TEMP
+               ELSE
+                  WORK( 2*N+JE-1 ) = ONE
+                  WORK( 3*N+JE-1 ) = ZERO
+                  TEMP = ACOEF*A( JE-1, JE )
+                  WORK( 2*N+JE ) = ( BCOEFR*B( JE-1, JE-1 )-ACOEF*
+     $                             A( JE-1, JE-1 ) ) / TEMP
+                  WORK( 3*N+JE ) = BCOEFI*B( JE-1, JE-1 ) / TEMP
+               END IF
+*
+               XMAX = MAX( ABS( WORK( 2*N+JE ) )+ABS( WORK( 3*N+JE ) ),
+     $                ABS( WORK( 2*N+JE-1 ) )+ABS( WORK( 3*N+JE-1 ) ) )
+*
+*              Compute contribution from columns JE and JE-1
+*              of A and B to the sums.
+*
+               CREALA = ACOEF*WORK( 2*N+JE-1 )
+               CIMAGA = ACOEF*WORK( 3*N+JE-1 )
+               CREALB = BCOEFR*WORK( 2*N+JE-1 ) -
+     $                  BCOEFI*WORK( 3*N+JE-1 )
+               CIMAGB = BCOEFI*WORK( 2*N+JE-1 ) +
+     $                  BCOEFR*WORK( 3*N+JE-1 )
+               CRE2A = ACOEF*WORK( 2*N+JE )
+               CIM2A = ACOEF*WORK( 3*N+JE )
+               CRE2B = BCOEFR*WORK( 2*N+JE ) - BCOEFI*WORK( 3*N+JE )
+               CIM2B = BCOEFI*WORK( 2*N+JE ) + BCOEFR*WORK( 3*N+JE )
+               DO 270 JR = 1, JE - 2
+                  WORK( 2*N+JR ) = -CREALA*A( JR, JE-1 ) +
+     $                             CREALB*B( JR, JE-1 ) -
+     $                             CRE2A*A( JR, JE ) + CRE2B*B( JR, JE )
+                  WORK( 3*N+JR ) = -CIMAGA*A( JR, JE-1 ) +
+     $                             CIMAGB*B( JR, JE-1 ) -
+     $                             CIM2A*A( JR, JE ) + CIM2B*B( JR, JE )
+  270          CONTINUE
+            END IF
+*
+            DMIN = MAX( ULP*ACOEFA*ANORM, ULP*BCOEFA*BNORM, SAFMIN )
+*
+*           Columnwise triangular solve of  (a A - b B)  x = 0
+*
+            IL2BY2 = .FALSE.
+            DO 370 J = JE - NW, 1, -1
+*
+*              If a 2-by-2 block, is in position j-1:j, wait until
+*              next iteration to process it (when it will be j:j+1)
+*
+               IF( .NOT.IL2BY2 .AND. J.GT.1 ) THEN
+                  IF( A( J, J-1 ).NE.ZERO ) THEN
+                     IL2BY2 = .TRUE.
+                     GO TO 370
+                  END IF
+               END IF
+               BDIAG( 1 ) = B( J, J )
+               IF( IL2BY2 ) THEN
+                  NA = 2
+                  BDIAG( 2 ) = B( J+1, J+1 )
+               ELSE
+                  NA = 1
+               END IF
+*
+*              Compute x(j) (and x(j+1), if 2-by-2 block)
+*
+               CALL DLALN2( .FALSE., NA, NW, DMIN, ACOEF, A( J, J ),
+     $                      LDA, BDIAG( 1 ), BDIAG( 2 ), WORK( 2*N+J ),
+     $                      N, BCOEFR, BCOEFI, SUM, 2, SCALE, TEMP,
+     $                      IINFO )
+               IF( SCALE.LT.ONE ) THEN
+*
+                  DO 290 JW = 0, NW - 1
+                     DO 280 JR = 1, JE
+                        WORK( ( JW+2 )*N+JR ) = SCALE*
+     $                     WORK( ( JW+2 )*N+JR )
+  280                CONTINUE
+  290             CONTINUE
+               END IF
+               XMAX = MAX( SCALE*XMAX, TEMP )
+*
+               DO 310 JW = 1, NW
+                  DO 300 JA = 1, NA
+                     WORK( ( JW+1 )*N+J+JA-1 ) = SUM( JA, JW )
+  300             CONTINUE
+  310          CONTINUE
+*
+*              w = w + x(j)*(a A(*,j) - b B(*,j) ) with scaling
+*
+               IF( J.GT.1 ) THEN
+*
+*                 Check whether scaling is necessary for sum.
+*
+                  XSCALE = ONE / MAX( ONE, XMAX )
+                  TEMP = ACOEFA*WORK( J ) + BCOEFA*WORK( N+J )
+                  IF( IL2BY2 )
+     $               TEMP = MAX( TEMP, ACOEFA*WORK( J+1 )+BCOEFA*
+     $                      WORK( N+J+1 ) )
+                  TEMP = MAX( TEMP, ACOEFA, BCOEFA )
+                  IF( TEMP.GT.BIGNUM*XSCALE ) THEN
+*
+                     DO 330 JW = 0, NW - 1
+                        DO 320 JR = 1, JE
+                           WORK( ( JW+2 )*N+JR ) = XSCALE*
+     $                        WORK( ( JW+2 )*N+JR )
+  320                   CONTINUE
+  330                CONTINUE
+                     XMAX = XMAX*XSCALE
+                  END IF
+*
+*                 Compute the contributions of the off-diagonals of
+*                 column j (and j+1, if 2-by-2 block) of A and B to the
+*                 sums.
+*
+*
+                  DO 360 JA = 1, NA
+                     IF( ILCPLX ) THEN
+                        CREALA = ACOEF*WORK( 2*N+J+JA-1 )
+                        CIMAGA = ACOEF*WORK( 3*N+J+JA-1 )
+                        CREALB = BCOEFR*WORK( 2*N+J+JA-1 ) -
+     $                           BCOEFI*WORK( 3*N+J+JA-1 )
+                        CIMAGB = BCOEFI*WORK( 2*N+J+JA-1 ) +
+     $                           BCOEFR*WORK( 3*N+J+JA-1 )
+                        DO 340 JR = 1, J - 1
+                           WORK( 2*N+JR ) = WORK( 2*N+JR ) -
+     $                                      CREALA*A( JR, J+JA-1 ) +
+     $                                      CREALB*B( JR, J+JA-1 )
+                           WORK( 3*N+JR ) = WORK( 3*N+JR ) -
+     $                                      CIMAGA*A( JR, J+JA-1 ) +
+     $                                      CIMAGB*B( JR, J+JA-1 )
+  340                   CONTINUE
+                     ELSE
+                        CREALA = ACOEF*WORK( 2*N+J+JA-1 )
+                        CREALB = BCOEFR*WORK( 2*N+J+JA-1 )
+                        DO 350 JR = 1, J - 1
+                           WORK( 2*N+JR ) = WORK( 2*N+JR ) -
+     $                                      CREALA*A( JR, J+JA-1 ) +
+     $                                      CREALB*B( JR, J+JA-1 )
+  350                   CONTINUE
+                     END IF
+  360             CONTINUE
+               END IF
+*
+               IL2BY2 = .FALSE.
+  370       CONTINUE
+*
+*           Copy eigenvector to VR, back transforming if
+*           HOWMNY='B'.
+*
+            IEIG = IEIG - NW
+            IF( ILBACK ) THEN
+*
+               DO 410 JW = 0, NW - 1
+                  DO 380 JR = 1, N
+                     WORK( ( JW+4 )*N+JR ) = WORK( ( JW+2 )*N+1 )*
+     $                                       VR( JR, 1 )
+  380             CONTINUE
+*
+*                 A series of compiler directives to defeat
+*                 vectorization for the next loop
+*
+*
+                  DO 400 JC = 2, JE
+                     DO 390 JR = 1, N
+                        WORK( ( JW+4 )*N+JR ) = WORK( ( JW+4 )*N+JR ) +
+     $                     WORK( ( JW+2 )*N+JC )*VR( JR, JC )
+  390                CONTINUE
+  400             CONTINUE
+  410          CONTINUE
+*
+               DO 430 JW = 0, NW - 1
+                  DO 420 JR = 1, N
+                     VR( JR, IEIG+JW ) = WORK( ( JW+4 )*N+JR )
+  420             CONTINUE
+  430          CONTINUE
+*
+               IEND = N
+            ELSE
+               DO 450 JW = 0, NW - 1
+                  DO 440 JR = 1, N
+                     VR( JR, IEIG+JW ) = WORK( ( JW+2 )*N+JR )
+  440             CONTINUE
+  450          CONTINUE
+*
+               IEND = JE
+            END IF
+*
+*           Scale eigenvector
+*
+            XMAX = ZERO
+            IF( ILCPLX ) THEN
+               DO 460 J = 1, IEND
+                  XMAX = MAX( XMAX, ABS( VR( J, IEIG ) )+
+     $                   ABS( VR( J, IEIG+1 ) ) )
+  460          CONTINUE
+            ELSE
+               DO 470 J = 1, IEND
+                  XMAX = MAX( XMAX, ABS( VR( J, IEIG ) ) )
+  470          CONTINUE
+            END IF
+*
+            IF( XMAX.GT.SAFMIN ) THEN
+               XSCALE = ONE / XMAX
+               DO 490 JW = 0, NW - 1
+                  DO 480 JR = 1, IEND
+                     VR( JR, IEIG+JW ) = XSCALE*VR( JR, IEIG+JW )
+  480             CONTINUE
+  490          CONTINUE
+            END IF
+  500    CONTINUE
+      END IF
+*
+      RETURN
+*
+*     End of DTGEVC
+*
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/lapack/zggbal.f
@@ -0,0 +1,474 @@
+      SUBROUTINE ZGGBAL( JOB, N, A, LDA, B, LDB, ILO, IHI, LSCALE,
+     $                   RSCALE, WORK, INFO )
+*
+*  -- LAPACK routine (version 2.0) --
+*     Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
+*     Courant Institute, Argonne National Lab, and Rice University
+*     September 30, 1994
+*
+*     .. Scalar Arguments ..
+      CHARACTER          JOB
+      INTEGER            IHI, ILO, INFO, LDA, LDB, N
+*     ..
+*     .. Array Arguments ..
+      DOUBLE PRECISION   LSCALE( * ), RSCALE( * ), WORK( * )
+      COMPLEX*16         A( LDA, * ), B( LDB, * )
+*     ..
+*
+*  Purpose
+*  =======
+*
+*  ZGGBAL balances a pair of general complex matrices (A,B).  This
+*  involves, first, permuting A and B by similarity transformations to
+*  isolate eigenvalues in the first 1 to ILO$-$1 and last IHI+1 to N
+*  elements on the diagonal; and second, applying a diagonal similarity
+*  transformation to rows and columns ILO to IHI to make the rows
+*  and columns as close in norm as possible. Both steps are optional.
+*
+*  Balancing may reduce the 1-norm of the matrices, and improve the
+*  accuracy of the computed eigenvalues and/or eigenvectors in the
+*  generalized eigenvalue problem A*x = lambda*B*x.
+*
+*  Arguments
+*  =========
+*
+*  JOB     (input) CHARACTER*1
+*          Specifies the operations to be performed on A and B:
+*          = 'N':  none:  simply set ILO = 1, IHI = N, LSCALE(I) = 1.0
+*                  and RSCALE(I) = 1.0 for i=1,...,N;
+*          = 'P':  permute only;
+*          = 'S':  scale only;
+*          = 'B':  both permute and scale.
+*
+*  N       (input) INTEGER
+*          The order of the matrices A and B.  N >= 0.
+*
+*  A       (input/output) COMPLEX*16 array, dimension (LDA,N)
+*          On entry, the input matrix A.
+*          On exit, A is overwritten by the balanced matrix.
+*          If JOB = 'N', A is not referenced.
+*
+*  LDA     (input) INTEGER
+*          The leading dimension of the array A. LDA >= max(1,N).
+*
+*  B       (input/output) COMPLEX*16 array, dimension (LDB,N)
+*          On entry, the input matrix B.
+*          On exit, B is overwritten by the balanced matrix.
+*          If JOB = 'N', B is not referenced.
+*
+*  LDB     (input) INTEGER
+*          The leading dimension of the array B. LDB >= max(1,N).
+*
+*  ILO     (output) INTEGER
+*  IHI     (output) INTEGER
+*          ILO and IHI are set to integers such that on exit
+*          A(i,j) = 0 and B(i,j) = 0 if i > j and
+*          j = 1,...,ILO-1 or i = IHI+1,...,N.
+*          If JOB = 'N' or 'S', ILO = 1 and IHI = N.
+*
+*  LSCALE  (output) DOUBLE PRECISION array, dimension (N)
+*          Details of the permutations and scaling factors applied
+*          to the left side of A and B.  If P(j) is the index of the
+*          row interchanged with row j, and D(j) is the scaling factor
+*          applied to row j, then
+*            LSCALE(j) = P(j)    for J = 1,...,ILO-1
+*                      = D(j)    for J = ILO,...,IHI
+*                      = P(j)    for J = IHI+1,...,N.
+*          The order in which the interchanges are made is N to IHI+1,
+*          then 1 to ILO-1.
+*
+*  RSCALE  (output) DOUBLE PRECISION array, dimension (N)
+*          Details of the permutations and scaling factors applied
+*          to the right side of A and B.  If P(j) is the index of the
+*          column interchanged with column j, and D(j) is the scaling
+*          factor applied to column j, then
+*            RSCALE(j) = P(j)    for J = 1,...,ILO-1
+*                      = D(j)    for J = ILO,...,IHI
+*                      = P(j)    for J = IHI+1,...,N.
+*          The order in which the interchanges are made is N to IHI+1,
+*          then 1 to ILO-1.
+*
+*  WORK    (workspace) DOUBLE PRECISION array, dimension (6*N)
+*
+*  INFO    (output) INTEGER
+*          = 0:  successful exit
+*          < 0:  if INFO = -i, the i-th argument had an illegal value.
+*
+*  Further Details
+*  ===============
+*
+*  See R.C. WARD, Balancing the generalized eigenvalue problem,
+*                 SIAM J. Sci. Stat. Comp. 2 (1981), 141-152.
+*
+*  =====================================================================
+*
+*     .. Parameters ..
+      DOUBLE PRECISION   ZERO, HALF, ONE
+      PARAMETER          ( ZERO = 0.0D+0, HALF = 0.5D+0, ONE = 1.0D+0 )
+      DOUBLE PRECISION   THREE, SCLFAC
+      PARAMETER          ( THREE = 3.0D+0, SCLFAC = 1.0D+1 )
+      COMPLEX*16         CZERO
+      PARAMETER          ( CZERO = ( 0.0D+0, 0.0D+0 ) )
+*     ..
+*     .. Local Scalars ..
+      INTEGER            I, ICAB, IFLOW, IP1, IR, IRAB, IT, J, JC, JP1,
+     $                   K, KOUNT, L, LCAB, LM1, LRAB, LSFMAX, LSFMIN,
+     $                   M, NR, NRP2
+      DOUBLE PRECISION   ALPHA, BASL, BETA, CAB, CMAX, COEF, COEF2,
+     $                   COEF5, COR, EW, EWC, GAMMA, PGAMMA, RAB, SFMAX,
+     $                   SFMIN, SUM, T, TA, TB, TC
+      COMPLEX*16         CDUM
+*     ..
+*     .. External Functions ..
+      LOGICAL            LSAME
+      INTEGER            IZAMAX
+      DOUBLE PRECISION   DDOT, DLAMCH
+      EXTERNAL           LSAME, IZAMAX, DDOT, DLAMCH
+*     ..
+*     .. External Subroutines ..
+      EXTERNAL           DAXPY, DSCAL, XERBLA, ZDSCAL, ZSWAP
+*     ..
+*     .. Intrinsic Functions ..
+      INTRINSIC          ABS, DBLE, DIMAG, INT, LOG10, MAX, MIN, SIGN
+*     ..
+*     .. Statement Functions ..
+      DOUBLE PRECISION   CABS1
+*     ..
+*     .. Statement Function definitions ..
+      CABS1( CDUM ) = ABS( DBLE( CDUM ) ) + ABS( DIMAG( CDUM ) )
+*     ..
+*     .. Executable Statements ..
+*
+*     Test the input parameters
+*
+      INFO = 0
+      IF( .NOT.LSAME( JOB, 'N' ) .AND. .NOT.LSAME( JOB, 'P' ) .AND.
+     $    .NOT.LSAME( JOB, 'S' ) .AND. .NOT.LSAME( JOB, 'B' ) ) THEN
+         INFO = -1
+      ELSE IF( N.LT.0 ) THEN
+         INFO = -2
+      ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
+         INFO = -4
+      ELSE IF( LDB.LT.MAX( 1, N ) ) THEN
+         INFO = -5
+      END IF
+      IF( INFO.NE.0 ) THEN
+         CALL XERBLA( 'ZGGBAL', -INFO )
+         RETURN
+      END IF
+*
+      K = 1
+      L = N
+*
+*     Quick return if possible
+*
+      IF( N.EQ.0 )
+     $   RETURN
+*
+      IF( LSAME( JOB, 'N' ) ) THEN
+         ILO = 1
+         IHI = N
+         DO 10 I = 1, N
+            LSCALE( I ) = ONE
+            RSCALE( I ) = ONE
+   10    CONTINUE
+         RETURN
+      END IF
+*
+      IF( K.EQ.L ) THEN
+         ILO = 1
+         IHI = 1
+         LSCALE( 1 ) = ONE
+         RSCALE( 1 ) = ONE
+         RETURN
+      END IF
+*
+      IF( LSAME( JOB, 'S' ) )
+     $   GO TO 190
+*
+      GO TO 30
+*
+*     Permute the matrices A and B to isolate the eigenvalues.
+*
+*     Find row with one nonzero in columns 1 through L
+*
+   20 CONTINUE
+      L = LM1
+      IF( L.NE.1 )
+     $   GO TO 30
+*
+      RSCALE( 1 ) = 1
+      LSCALE( 1 ) = 1
+      GO TO 190
+*
+   30 CONTINUE
+      LM1 = L - 1
+      DO 80 I = L, 1, -1
+         DO 40 J = 1, LM1
+            JP1 = J + 1
+            IF( A( I, J ).NE.CZERO .OR. B( I, J ).NE.CZERO )
+     $         GO TO 50
+   40    CONTINUE
+         J = L
+         GO TO 70
+*
+   50    CONTINUE
+         DO 60 J = JP1, L
+            IF( A( I, J ).NE.CZERO .OR. B( I, J ).NE.CZERO )
+     $         GO TO 80
+   60    CONTINUE
+         J = JP1 - 1
+*
+   70    CONTINUE
+         M = L
+         IFLOW = 1
+         GO TO 160
+   80 CONTINUE
+      GO TO 100
+*
+*     Find column with one nonzero in rows K through N
+*
+   90 CONTINUE
+      K = K + 1
+*
+  100 CONTINUE
+      DO 150 J = K, L
+         DO 110 I = K, LM1
+            IP1 = I + 1
+            IF( A( I, J ).NE.CZERO .OR. B( I, J ).NE.CZERO )
+     $         GO TO 120
+  110    CONTINUE
+         I = L
+         GO TO 140
+  120    CONTINUE
+         DO 130 I = IP1, L
+            IF( A( I, J ).NE.CZERO .OR. B( I, J ).NE.CZERO )
+     $         GO TO 150
+  130    CONTINUE
+         I = IP1 - 1
+  140    CONTINUE
+         M = K
+         IFLOW = 2
+         GO TO 160
+  150 CONTINUE
+      GO TO 190
+*
+*     Permute rows M and I
+*
+  160 CONTINUE
+      LSCALE( M ) = I
+      IF( I.EQ.M )
+     $   GO TO 170
+      CALL ZSWAP( N-K+1, A( I, K ), LDA, A( M, K ), LDA )
+      CALL ZSWAP( N-K+1, B( I, K ), LDB, B( M, K ), LDB )
+*
+*     Permute columns M and J
+*
+  170 CONTINUE
+      RSCALE( M ) = J
+      IF( J.EQ.M )
+     $   GO TO 180
+      CALL ZSWAP( L, A( 1, J ), 1, A( 1, M ), 1 )
+      CALL ZSWAP( L, B( 1, J ), 1, B( 1, M ), 1 )
+*
+  180 CONTINUE
+      GO TO ( 20, 90 )IFLOW
+*
+  190 CONTINUE
+      ILO = K
+      IHI = L
+*
+      IF( ILO.EQ.IHI )
+     $   RETURN
+*
+      IF( LSAME( JOB, 'P' ) )
+     $   RETURN
+*
+*     Balance the submatrix in rows ILO to IHI.
+*
+      NR = IHI - ILO + 1
+      DO 200 I = ILO, IHI
+         RSCALE( I ) = ZERO
+         LSCALE( I ) = ZERO
+*
+         WORK( I ) = ZERO
+         WORK( I+N ) = ZERO
+         WORK( I+2*N ) = ZERO
+         WORK( I+3*N ) = ZERO
+         WORK( I+4*N ) = ZERO
+         WORK( I+5*N ) = ZERO
+  200 CONTINUE
+*
+*     Compute right side vector in resulting linear equations
+*
+      BASL = LOG10( SCLFAC )
+      DO 240 I = ILO, IHI
+         DO 230 J = ILO, IHI
+            IF( A( I, J ).EQ.CZERO ) THEN
+               TA = ZERO
+               GO TO 210
+            END IF
+            TA = LOG10( CABS1( A( I, J ) ) ) / BASL
+*
+  210       CONTINUE
+            IF( B( I, J ).EQ.CZERO ) THEN
+               TB = ZERO
+               GO TO 220
+            END IF
+            TB = LOG10( CABS1( B( I, J ) ) ) / BASL
+*
+  220       CONTINUE
+            WORK( I+4*N ) = WORK( I+4*N ) - TA - TB
+            WORK( J+5*N ) = WORK( J+5*N ) - TA - TB
+  230    CONTINUE
+  240 CONTINUE
+*
+      COEF = ONE / DBLE( 2*NR )
+      COEF2 = COEF*COEF
+      COEF5 = HALF*COEF2
+      NRP2 = NR + 2
+      BETA = ZERO
+      IT = 1
+*
+*     Start generalized conjugate gradient iteration
+*
+  250 CONTINUE
+*
+      GAMMA = DDOT( NR, WORK( ILO+4*N ), 1, WORK( ILO+4*N ), 1 ) +
+     $        DDOT( NR, WORK( ILO+5*N ), 1, WORK( ILO+5*N ), 1 )
+*
+      EW = ZERO
+      EWC = ZERO
+      DO 260 I = ILO, IHI
+         EW = EW + WORK( I+4*N )
+         EWC = EWC + WORK( I+5*N )
+  260 CONTINUE
+*
+      GAMMA = COEF*GAMMA - COEF2*( EW**2+EWC**2 ) - COEF5*( EW-EWC )**2
+      IF( GAMMA.EQ.ZERO )
+     $   GO TO 350
+      IF( IT.NE.1 )
+     $   BETA = GAMMA / PGAMMA
+      T = COEF5*( EWC-THREE*EW )
+      TC = COEF5*( EW-THREE*EWC )
+*
+      CALL DSCAL( NR, BETA, WORK( ILO ), 1 )
+      CALL DSCAL( NR, BETA, WORK( ILO+N ), 1 )
+*
+      CALL DAXPY( NR, COEF, WORK( ILO+4*N ), 1, WORK( ILO+N ), 1 )
+      CALL DAXPY( NR, COEF, WORK( ILO+5*N ), 1, WORK( ILO ), 1 )
+*
+      DO 270 I = ILO, IHI
+         WORK( I ) = WORK( I ) + TC
+         WORK( I+N ) = WORK( I+N ) + T
+  270 CONTINUE
+*
+*     Apply matrix to vector
+*
+      DO 300 I = ILO, IHI
+         KOUNT = 0
+         SUM = ZERO
+         DO 290 J = ILO, IHI
+            IF( A( I, J ).EQ.CZERO )
+     $         GO TO 280
+            KOUNT = KOUNT + 1
+            SUM = SUM + WORK( J )
+  280       CONTINUE
+            IF( B( I, J ).EQ.CZERO )
+     $         GO TO 290
+            KOUNT = KOUNT + 1
+            SUM = SUM + WORK( J )
+  290    CONTINUE
+         WORK( I+2*N ) = DBLE( KOUNT )*WORK( I+N ) + SUM
+  300 CONTINUE
+*
+      DO 330 J = ILO, IHI
+         KOUNT = 0
+         SUM = ZERO
+         DO 320 I = ILO, IHI
+            IF( A( I, J ).EQ.CZERO )
+     $         GO TO 310
+            KOUNT = KOUNT + 1
+            SUM = SUM + WORK( I+N )
+  310       CONTINUE
+            IF( B( I, J ).EQ.CZERO )
+     $         GO TO 320
+            KOUNT = KOUNT + 1
+            SUM = SUM + WORK( I+N )
+  320    CONTINUE
+         WORK( J+3*N ) = DBLE( KOUNT )*WORK( J ) + SUM
+  330 CONTINUE
+*
+      SUM = DDOT( NR, WORK( ILO+N ), 1, WORK( ILO+2*N ), 1 ) +
+     $      DDOT( NR, WORK( ILO ), 1, WORK( ILO+3*N ), 1 )
+      ALPHA = GAMMA / SUM
+*
+*     Determine correction to current iteration
+*
+      CMAX = ZERO
+      DO 340 I = ILO, IHI
+         COR = ALPHA*WORK( I+N )
+         IF( ABS( COR ).GT.CMAX )
+     $      CMAX = ABS( COR )
+         LSCALE( I ) = LSCALE( I ) + COR
+         COR = ALPHA*WORK( I )
+         IF( ABS( COR ).GT.CMAX )
+     $      CMAX = ABS( COR )
+         RSCALE( I ) = RSCALE( I ) + COR
+  340 CONTINUE
+      IF( CMAX.LT.HALF )
+     $   GO TO 350
+*
+      CALL DAXPY( NR, -ALPHA, WORK( ILO+2*N ), 1, WORK( ILO+4*N ), 1 )
+      CALL DAXPY( NR, -ALPHA, WORK( ILO+3*N ), 1, WORK( ILO+5*N ), 1 )
+*
+      PGAMMA = GAMMA
+      IT = IT + 1
+      IF( IT.LE.NRP2 )
+     $   GO TO 250
+*
+*     End generalized conjugate gradient iteration
+*
+  350 CONTINUE
+      SFMIN = DLAMCH( 'S' )
+      SFMAX = ONE / SFMIN
+      LSFMIN = INT( LOG10( SFMIN ) / BASL+ONE )
+      LSFMAX = INT( LOG10( SFMAX ) / BASL )
+      DO 360 I = ILO, IHI
+         IRAB = IZAMAX( N-ILO+1, A( I, ILO ), LDA )
+         RAB = ABS( A( I, IRAB+ILO-1 ) )
+         IRAB = IZAMAX( N-ILO+1, B( I, ILO ), LDA )
+         RAB = MAX( RAB, ABS( B( I, IRAB+ILO-1 ) ) )
+         LRAB = INT( LOG10( RAB+SFMIN ) / BASL+ONE )
+         IR = LSCALE( I ) + SIGN( HALF, LSCALE( I ) )
+         IR = MIN( MAX( IR, LSFMIN ), LSFMAX, LSFMAX-LRAB )
+         LSCALE( I ) = SCLFAC**IR
+         ICAB = IZAMAX( IHI, A( 1, I ), 1 )
+         CAB = ABS( A( ICAB, I ) )
+         ICAB = IZAMAX( IHI, B( 1, I ), 1 )
+         CAB = MAX( CAB, ABS( B( ICAB, I ) ) )
+         LCAB = INT( LOG10( CAB+SFMIN ) / BASL+ONE )
+         JC = RSCALE( I ) + SIGN( HALF, RSCALE( I ) )
+         JC = MIN( MAX( JC, LSFMIN ), LSFMAX, LSFMAX-LCAB )
+         RSCALE( I ) = SCLFAC**JC
+  360 CONTINUE
+*
+*     Row scaling of matrices A and B
+*
+      DO 370 I = ILO, IHI
+         CALL ZDSCAL( N-ILO+1, LSCALE( I ), A( I, ILO ), LDA )
+         CALL ZDSCAL( N-ILO+1, LSCALE( I ), B( I, ILO ), LDB )
+  370 CONTINUE
+*
+*     Column scaling of matrices A and B
+*
+      DO 380 J = ILO, IHI
+         CALL ZDSCAL( IHI, RSCALE( J ), A( 1, J ), 1 )
+         CALL ZDSCAL( IHI, RSCALE( J ), B( 1, J ), 1 )
+  380 CONTINUE
+*
+      RETURN
+*
+*     End of ZGGBAL
+*
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/ranlib/HOWTOGET
@@ -0,0 +1,31 @@
+
+                                WHERE TO GET IT
+
+     Software written  by members  of the section   is freely available  to
+     anyone.  Reposting  on other   archives is  encouraged.  The  code  is
+     furnished in source form and as DOS and Macintosh executables. Readers
+     with Internet access  and a browser  might note the following web site
+     addresses:
+
+          University of Texas M. D. Anderson Cancer Center Home Page:
+                           http://utmdacc.mdacc.tmc.edu/
+
+                    Department of Biomathematics Home Page:
+                           http://odin.mdacc.tmc.edu/
+
+
+                              Available Software:
+                       http://odin.mdacc.tmc.edu/anonftp/
+
+
+     Our code can also be obtained  by anonymous ftp to odin.mdacc.tmc.edu.
+     The index is on file ./pub/index.
+
+     Our statistical  code is  also  posted  to statlib  after some  delay.
+     Statlib can be accessed at:
+                             http://lib.stat.cmu.edu/
+     See in particular:
+                    http://lib.stat.cmu.edu/general/Utexas/
+
+     The code is also archived at many other sites (at their option).  Use
+     your favorite search engine to find one close to you.
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/Makefile.in
@@ -0,0 +1,19 @@
+#
+# Makefile for octave's libcruft/slatec-err directory
+#
+# John W. Eaton
+# jwe@bevo.che.wisc.edu
+# University of Wisconsin-Madison
+# Department of Chemical Engineering
+
+TOPDIR = ../..
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+
+EXTERNAL_DISTFILES = $(DISTFILES)
+
+include $(TOPDIR)/Makeconf
+
+include ../Makerules
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/fdump.f
@@ -0,0 +1,31 @@
+*DECK FDUMP
+      SUBROUTINE FDUMP
+C***BEGIN PROLOGUE  FDUMP
+C***PURPOSE  Symbolic dump (should be locally written).
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3
+C***TYPE      ALL (FDUMP-A)
+C***KEYWORDS  ERROR, XERMSG
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C        ***Note*** Machine Dependent Routine
+C        FDUMP is intended to be replaced by a locally written
+C        version which produces a symbolic dump.  Failing this,
+C        it should be replaced by a version which prints the
+C        subprogram nesting list.  Note that this dump must be
+C        printed on each of up to five files, as indicated by the
+C        XGETUA routine.  See XSETUA and XGETUA for details.
+C
+C     Written by Ron Jones, with SLATEC Common Math Library Subcommittee
+C
+C***REFERENCES  (NONE)
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C***END PROLOGUE  FDUMP
+C***FIRST EXECUTABLE STATEMENT  FDUMP
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/j4save.f
@@ -0,0 +1,65 @@
+*DECK J4SAVE
+      FUNCTION J4SAVE (IWHICH, IVALUE, ISET)
+C***BEGIN PROLOGUE  J4SAVE
+C***SUBSIDIARY
+C***PURPOSE  Save or recall global variables needed by error
+C            handling routines.
+C***LIBRARY   SLATEC (XERROR)
+C***TYPE      INTEGER (J4SAVE-I)
+C***KEYWORDS  ERROR MESSAGES, ERROR NUMBER, RECALL, SAVE, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        J4SAVE saves and recalls several global variables needed
+C        by the library error handling routines.
+C
+C     Description of Parameters
+C      --Input--
+C        IWHICH - Index of item desired.
+C                = 1 Refers to current error number.
+C                = 2 Refers to current error control flag.
+C                = 3 Refers to current unit number to which error
+C                    messages are to be sent.  (0 means use standard.)
+C                = 4 Refers to the maximum number of times any
+C                     message is to be printed (as set by XERMAX).
+C                = 5 Refers to the total number of units to which
+C                     each error message is to be written.
+C                = 6 Refers to the 2nd unit for error messages
+C                = 7 Refers to the 3rd unit for error messages
+C                = 8 Refers to the 4th unit for error messages
+C                = 9 Refers to the 5th unit for error messages
+C        IVALUE - The value to be set for the IWHICH-th parameter,
+C                 if ISET is .TRUE. .
+C        ISET   - If ISET=.TRUE., the IWHICH-th parameter will BE
+C                 given the value, IVALUE.  If ISET=.FALSE., the
+C                 IWHICH-th parameter will be unchanged, and IVALUE
+C                 is a dummy parameter.
+C      --Output--
+C        The (old) value of the IWHICH-th parameter will be returned
+C        in the function value, J4SAVE.
+C
+C***SEE ALSO  XERMSG
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900205  Minor modifications to prologue.  (WRB)
+C   900402  Added TYPE section.  (WRB)
+C   910411  Added KEYWORDS section.  (WRB)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  J4SAVE
+      LOGICAL ISET
+      INTEGER IPARAM(9)
+      SAVE IPARAM
+      DATA IPARAM(1),IPARAM(2),IPARAM(3),IPARAM(4)/0,2,0,10/
+      DATA IPARAM(5)/1/
+      DATA IPARAM(6),IPARAM(7),IPARAM(8),IPARAM(9)/0,0,0,0/
+C***FIRST EXECUTABLE STATEMENT  J4SAVE
+      J4SAVE = IPARAM(IWHICH)
+      IF (ISET) IPARAM(IWHICH) = IVALUE
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xerclr.f
@@ -0,0 +1,31 @@
+*DECK XERCLR
+      SUBROUTINE XERCLR
+C***BEGIN PROLOGUE  XERCLR
+C***PURPOSE  Reset current error number to zero.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XERCLR-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        This routine simply resets the current error number to zero.
+C        This may be necessary in order to determine that a certain
+C        error has occurred again since the last time NUMXER was
+C        referenced.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  J4SAVE
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERCLR
+C***FIRST EXECUTABLE STATEMENT  XERCLR
+      JUNK = J4SAVE(1,0,.TRUE.)
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xercnt.f
@@ -0,0 +1,60 @@
+*DECK XERCNT
+      SUBROUTINE XERCNT (LIBRAR, SUBROU, MESSG, NERR, LEVEL, KONTRL)
+C***BEGIN PROLOGUE  XERCNT
+C***SUBSIDIARY
+C***PURPOSE  Allow user control over handling of errors.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XERCNT-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        Allows user control over handling of individual errors.
+C        Just after each message is recorded, but before it is
+C        processed any further (i.e., before it is printed or
+C        a decision to abort is made), a call is made to XERCNT.
+C        If the user has provided his own version of XERCNT, he
+C        can then override the value of KONTROL used in processing
+C        this message by redefining its value.
+C        KONTRL may be set to any value from -2 to 2.
+C        The meanings for KONTRL are the same as in XSETF, except
+C        that the value of KONTRL changes only for this message.
+C        If KONTRL is set to a value outside the range from -2 to 2,
+C        it will be moved back into that range.
+C
+C     Description of Parameters
+C
+C      --Input--
+C        LIBRAR - the library that the routine is in.
+C        SUBROU - the subroutine that XERMSG is being called from
+C        MESSG  - the first 20 characters of the error message.
+C        NERR   - same as in the call to XERMSG.
+C        LEVEL  - same as in the call to XERMSG.
+C        KONTRL - the current value of the control flag as set
+C                 by a call to XSETF.
+C
+C      --Output--
+C        KONTRL - the new value of KONTRL.  If KONTRL is not
+C                 defined, it will remain at its original value.
+C                 This changed value of control affects only
+C                 the current occurrence of the current message.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900206  Routine changed from user-callable to subsidiary.  (WRB)
+C   900510  Changed calling sequence to include LIBRARY and SUBROUTINE
+C           names, changed routine name from XERCTL to XERCNT.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERCNT
+      CHARACTER*(*) LIBRAR, SUBROU, MESSG
+C***FIRST EXECUTABLE STATEMENT  XERCNT
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xerhlt.f
@@ -0,0 +1,39 @@
+*DECK XERHLT
+      SUBROUTINE XERHLT (MESSG)
+C***BEGIN PROLOGUE  XERHLT
+C***SUBSIDIARY
+C***PURPOSE  Abort program execution and print error message.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XERHLT-A)
+C***KEYWORDS  ABORT PROGRAM EXECUTION, ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        ***Note*** machine dependent routine
+C        XERHLT aborts the execution of the program.
+C        The error message causing the abort is given in the calling
+C        sequence, in case one needs it for printing on a dayfile,
+C        for example.
+C
+C     Description of Parameters
+C        MESSG is as in XERMSG.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  (NONE)
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900206  Routine changed from user-callable to subsidiary.  (WRB)
+C   900510  Changed calling sequence to delete length of character
+C           and changed routine name from XERABT to XERHLT.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERHLT
+      CHARACTER*(*) MESSG
+C***FIRST EXECUTABLE STATEMENT  XERHLT
+      CALL XSTOPX (MESSG)
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xermsg.f
@@ -0,0 +1,364 @@
+*DECK XERMSG
+      SUBROUTINE XERMSG (LIBRAR, SUBROU, MESSG, NERR, LEVEL)
+C***BEGIN PROLOGUE  XERMSG
+C***PURPOSE  Process error messages for SLATEC and other libraries.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XERMSG-A)
+C***KEYWORDS  ERROR MESSAGE, XERROR
+C***AUTHOR  Fong, Kirby, (NMFECC at LLNL)
+C***DESCRIPTION
+C
+C   XERMSG processes a diagnostic message in a manner determined by the
+C   value of LEVEL and the current value of the library error control
+C   flag, KONTRL.  See subroutine XSETF for details.
+C
+C    LIBRAR   A character constant (or character variable) with the name
+C             of the library.  This will be 'SLATEC' for the SLATEC
+C             Common Math Library.  The error handling package is
+C             general enough to be used by many libraries
+C             simultaneously, so it is desirable for the routine that
+C             detects and reports an error to identify the library name
+C             as well as the routine name.
+C
+C    SUBROU   A character constant (or character variable) with the name
+C             of the routine that detected the error.  Usually it is the
+C             name of the routine that is calling XERMSG.  There are
+C             some instances where a user callable library routine calls
+C             lower level subsidiary routines where the error is
+C             detected.  In such cases it may be more informative to
+C             supply the name of the routine the user called rather than
+C             the name of the subsidiary routine that detected the
+C             error.
+C
+C    MESSG    A character constant (or character variable) with the text
+C             of the error or warning message.  In the example below,
+C             the message is a character constant that contains a
+C             generic message.
+C
+C                   CALL XERMSG ('SLATEC', 'MMPY',
+C                  *'THE ORDER OF THE MATRIX EXCEEDS THE ROW DIMENSION',
+C                  *3, 1)
+C
+C             It is possible (and is sometimes desirable) to generate a
+C             specific message--e.g., one that contains actual numeric
+C             values.  Specific numeric values can be converted into
+C             character strings using formatted WRITE statements into
+C             character variables.  This is called standard Fortran
+C             internal file I/O and is exemplified in the first three
+C             lines of the following example.  You can also catenate
+C             substrings of characters to construct the error message.
+C             Here is an example showing the use of both writing to
+C             an internal file and catenating character strings.
+C
+C                   CHARACTER*5 CHARN, CHARL
+C                   WRITE (CHARN,10) N
+C                   WRITE (CHARL,10) LDA
+C                10 FORMAT(I5)
+C                   CALL XERMSG ('SLATEC', 'MMPY', 'THE ORDER'//CHARN//
+C                  *   ' OF THE MATRIX EXCEEDS ITS ROW DIMENSION OF'//
+C                  *   CHARL, 3, 1)
+C
+C             There are two subtleties worth mentioning.  One is that
+C             the // for character catenation is used to construct the
+C             error message so that no single character constant is
+C             continued to the next line.  This avoids confusion as to
+C             whether there are trailing blanks at the end of the line.
+C             The second is that by catenating the parts of the message
+C             as an actual argument rather than encoding the entire
+C             message into one large character variable, we avoid
+C             having to know how long the message will be in order to
+C             declare an adequate length for that large character
+C             variable.  XERMSG calls XERPRN to print the message using
+C             multiple lines if necessary.  If the message is very long,
+C             XERPRN will break it into pieces of 72 characters (as
+C             requested by XERMSG) for printing on multiple lines.
+C             Also, XERMSG asks XERPRN to prefix each line with ' *  '
+C             so that the total line length could be 76 characters.
+C             Note also that XERPRN scans the error message backwards
+C             to ignore trailing blanks.  Another feature is that
+C             the substring '$$' is treated as a new line sentinel
+C             by XERPRN.  If you want to construct a multiline
+C             message without having to count out multiples of 72
+C             characters, just use '$$' as a separator.  '$$'
+C             obviously must occur within 72 characters of the
+C             start of each line to have its intended effect since
+C             XERPRN is asked to wrap around at 72 characters in
+C             addition to looking for '$$'.
+C
+C    NERR     An integer value that is chosen by the library routine's
+C             author.  It must be in the range -99 to 999 (three
+C             printable digits).  Each distinct error should have its
+C             own error number.  These error numbers should be described
+C             in the machine readable documentation for the routine.
+C             The error numbers need be unique only within each routine,
+C             so it is reasonable for each routine to start enumerating
+C             errors from 1 and proceeding to the next integer.
+C
+C    LEVEL    An integer value in the range 0 to 2 that indicates the
+C             level (severity) of the error.  Their meanings are
+C
+C            -1  A warning message.  This is used if it is not clear
+C                that there really is an error, but the user's attention
+C                may be needed.  An attempt is made to only print this
+C                message once.
+C
+C             0  A warning message.  This is used if it is not clear
+C                that there really is an error, but the user's attention
+C                may be needed.
+C
+C             1  A recoverable error.  This is used even if the error is
+C                so serious that the routine cannot return any useful
+C                answer.  If the user has told the error package to
+C                return after recoverable errors, then XERMSG will
+C                return to the Library routine which can then return to
+C                the user's routine.  The user may also permit the error
+C                package to terminate the program upon encountering a
+C                recoverable error.
+C
+C             2  A fatal error.  XERMSG will not return to its caller
+C                after it receives a fatal error.  This level should
+C                hardly ever be used; it is much better to allow the
+C                user a chance to recover.  An example of one of the few
+C                cases in which it is permissible to declare a level 2
+C                error is a reverse communication Library routine that
+C                is likely to be called repeatedly until it integrates
+C                across some interval.  If there is a serious error in
+C                the input such that another step cannot be taken and
+C                the Library routine is called again without the input
+C                error having been corrected by the caller, the Library
+C                routine will probably be called forever with improper
+C                input.  In this case, it is reasonable to declare the
+C                error to be fatal.
+C
+C    Each of the arguments to XERMSG is input; none will be modified by
+C    XERMSG.  A routine may make multiple calls to XERMSG with warning
+C    level messages; however, after a call to XERMSG with a recoverable
+C    error, the routine should return to the user.  Do not try to call
+C    XERMSG with a second recoverable error after the first recoverable
+C    error because the error package saves the error number.  The user
+C    can retrieve this error number by calling another entry point in
+C    the error handling package and then clear the error number when
+C    recovering from the error.  Calling XERMSG in succession causes the
+C    old error number to be overwritten by the latest error number.
+C    This is considered harmless for error numbers associated with
+C    warning messages but must not be done for error numbers of serious
+C    errors.  After a call to XERMSG with a recoverable error, the user
+C    must be given a chance to call NUMXER or XERCLR to retrieve or
+C    clear the error number.
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  FDUMP, J4SAVE, XERCNT, XERHLT, XERPRN, XERSVE
+C***REVISION HISTORY  (YYMMDD)
+C   880101  DATE WRITTEN
+C   880621  REVISED AS DIRECTED AT SLATEC CML MEETING OF FEBRUARY 1988.
+C           THERE ARE TWO BASIC CHANGES.
+C           1.  A NEW ROUTINE, XERPRN, IS USED INSTEAD OF XERPRT TO
+C               PRINT MESSAGES.  THIS ROUTINE WILL BREAK LONG MESSAGES
+C               INTO PIECES FOR PRINTING ON MULTIPLE LINES.  '$$' IS
+C               ACCEPTED AS A NEW LINE SENTINEL.  A PREFIX CAN BE
+C               ADDED TO EACH LINE TO BE PRINTED.  XERMSG USES EITHER
+C               ' ***' OR ' *  ' AND LONG MESSAGES ARE BROKEN EVERY
+C               72 CHARACTERS (AT MOST) SO THAT THE MAXIMUM LINE
+C               LENGTH OUTPUT CAN NOW BE AS GREAT AS 76.
+C           2.  THE TEXT OF ALL MESSAGES IS NOW IN UPPER CASE SINCE THE
+C               FORTRAN STANDARD DOCUMENT DOES NOT ADMIT THE EXISTENCE
+C               OF LOWER CASE.
+C   880708  REVISED AFTER THE SLATEC CML MEETING OF JUNE 29 AND 30.
+C           THE PRINCIPAL CHANGES ARE
+C           1.  CLARIFY COMMENTS IN THE PROLOGUES
+C           2.  RENAME XRPRNT TO XERPRN
+C           3.  REWORK HANDLING OF '$$' IN XERPRN TO HANDLE BLANK LINES
+C               SIMILAR TO THE WAY FORMAT STATEMENTS HANDLE THE /
+C               CHARACTER FOR NEW RECORDS.
+C   890706  REVISED WITH THE HELP OF FRED FRITSCH AND REG CLEMENS TO
+C           CLEAN UP THE CODING.
+C   890721  REVISED TO USE NEW FEATURE IN XERPRN TO COUNT CHARACTERS IN
+C           PREFIX.
+C   891013  REVISED TO CORRECT COMMENTS.
+C   891214  Prologue converted to Version 4.0 format.  (WRB)
+C   900510  Changed test on NERR to be -9999999 < NERR < 99999999, but
+C           NERR .ne. 0, and on LEVEL to be -2 < LEVEL < 3.  Added
+C           LEVEL=-1 logic, changed calls to XERSAV to XERSVE, and
+C           XERCTL to XERCNT.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERMSG
+      CHARACTER*(*) LIBRAR, SUBROU, MESSG
+      CHARACTER*8 XLIBR, XSUBR
+      CHARACTER*72  TEMP
+      CHARACTER*20  LFIRST
+C***FIRST EXECUTABLE STATEMENT  XERMSG
+      LKNTRL = J4SAVE (2, 0, .FALSE.)
+      MAXMES = J4SAVE (4, 0, .FALSE.)
+C
+C       LKNTRL IS A LOCAL COPY OF THE CONTROL FLAG KONTRL.
+C       MAXMES IS THE MAXIMUM NUMBER OF TIMES ANY PARTICULAR MESSAGE
+C          SHOULD BE PRINTED.
+C
+C       WE PRINT A FATAL ERROR MESSAGE AND TERMINATE FOR AN ERROR IN
+C          CALLING XERMSG.  THE ERROR NUMBER SHOULD BE POSITIVE,
+C          AND THE LEVEL SHOULD BE BETWEEN 0 AND 2.
+C
+      IF (NERR.LT.-9999999 .OR. NERR.GT.99999999 .OR. NERR.EQ.0 .OR.
+     *   LEVEL.LT.-1 .OR. LEVEL.GT.2) THEN
+         CALL XERPRN (' ***', -1, 'FATAL ERROR IN...$$ ' //
+     *      'XERMSG -- INVALID ERROR NUMBER OR LEVEL$$ '//
+     *      'JOB ABORT DUE TO FATAL ERROR.', 72)
+         CALL XERSVE (' ', ' ', ' ', 0, 0, 0, KDUMMY)
+         CALL XERHLT (' ***XERMSG -- INVALID INPUT')
+         RETURN
+      ENDIF
+C
+C       RECORD THE MESSAGE.
+C
+      I = J4SAVE (1, NERR, .TRUE.)
+      CALL XERSVE (LIBRAR, SUBROU, MESSG, 1, NERR, LEVEL, KOUNT)
+C
+C       HANDLE PRINT-ONCE WARNING MESSAGES.
+C
+      IF (LEVEL.EQ.-1 .AND. KOUNT.GT.1) RETURN
+C
+C       ALLOW TEMPORARY USER OVERRIDE OF THE CONTROL FLAG.
+C
+      XLIBR  = LIBRAR
+      XSUBR  = SUBROU
+      LFIRST = MESSG
+      LERR   = NERR
+      LLEVEL = LEVEL
+      CALL XERCNT (XLIBR, XSUBR, LFIRST, LERR, LLEVEL, LKNTRL)
+C
+      LKNTRL = MAX(-2, MIN(2,LKNTRL))
+      MKNTRL = ABS(LKNTRL)
+C
+C       SKIP PRINTING IF THE CONTROL FLAG VALUE AS RESET IN XERCNT IS
+C       ZERO AND THE ERROR IS NOT FATAL.
+C
+      IF (LEVEL.LT.2 .AND. LKNTRL.EQ.0) GO TO 30
+      IF (LEVEL.EQ.0 .AND. KOUNT.GT.MAXMES) GO TO 30
+      IF (LEVEL.EQ.1 .AND. KOUNT.GT.MAXMES .AND. MKNTRL.EQ.1) GO TO 30
+      IF (LEVEL.EQ.2 .AND. KOUNT.GT.MAX(1,MAXMES)) GO TO 30
+C
+C       ANNOUNCE THE NAMES OF THE LIBRARY AND SUBROUTINE BY BUILDING A
+C       MESSAGE IN CHARACTER VARIABLE TEMP (NOT EXCEEDING 66 CHARACTERS)
+C       AND SENDING IT OUT VIA XERPRN.  PRINT ONLY IF CONTROL FLAG
+C       IS NOT ZERO.
+C
+      IF (LKNTRL .NE. 0) THEN
+         TEMP(1:21) = 'MESSAGE FROM ROUTINE '
+         I = MIN(LEN(SUBROU), 16)
+         TEMP(22:21+I) = SUBROU(1:I)
+         TEMP(22+I:33+I) = ' IN LIBRARY '
+         LTEMP = 33 + I
+         I = MIN(LEN(LIBRAR), 16)
+         TEMP(LTEMP+1:LTEMP+I) = LIBRAR (1:I)
+         TEMP(LTEMP+I+1:LTEMP+I+1) = '.'
+         LTEMP = LTEMP + I + 1
+         CALL XERPRN (' ***', -1, TEMP(1:LTEMP), 72)
+      ENDIF
+C
+C       IF LKNTRL IS POSITIVE, PRINT AN INTRODUCTORY LINE BEFORE
+C       PRINTING THE MESSAGE.  THE INTRODUCTORY LINE TELLS THE CHOICE
+C       FROM EACH OF THE FOLLOWING THREE OPTIONS.
+C       1.  LEVEL OF THE MESSAGE
+C              'INFORMATIVE MESSAGE'
+C              'POTENTIALLY RECOVERABLE ERROR'
+C              'FATAL ERROR'
+C       2.  WHETHER CONTROL FLAG WILL ALLOW PROGRAM TO CONTINUE
+C              'PROG CONTINUES'
+C              'PROG ABORTED'
+C       3.  WHETHER OR NOT A TRACEBACK WAS REQUESTED.  (THE TRACEBACK
+C           MAY NOT BE IMPLEMENTED AT SOME SITES, SO THIS ONLY TELLS
+C           WHAT WAS REQUESTED, NOT WHAT WAS DELIVERED.)
+C              'TRACEBACK REQUESTED'
+C              'TRACEBACK NOT REQUESTED'
+C       NOTICE THAT THE LINE INCLUDING FOUR PREFIX CHARACTERS WILL NOT
+C       EXCEED 74 CHARACTERS.
+C       WE SKIP THE NEXT BLOCK IF THE INTRODUCTORY LINE IS NOT NEEDED.
+C
+      IF (LKNTRL .GT. 0) THEN
+C
+C       THE FIRST PART OF THE MESSAGE TELLS ABOUT THE LEVEL.
+C
+         IF (LEVEL .LE. 0) THEN
+            TEMP(1:20) = 'INFORMATIVE MESSAGE,'
+            LTEMP = 20
+         ELSEIF (LEVEL .EQ. 1) THEN
+            TEMP(1:30) = 'POTENTIALLY RECOVERABLE ERROR,'
+            LTEMP = 30
+         ELSE
+            TEMP(1:12) = 'FATAL ERROR,'
+            LTEMP = 12
+         ENDIF
+C
+C       THEN WHETHER THE PROGRAM WILL CONTINUE.
+C
+         IF ((MKNTRL.EQ.2 .AND. LEVEL.GE.1) .OR.
+     *       (MKNTRL.EQ.1 .AND. LEVEL.EQ.2)) THEN
+            TEMP(LTEMP+1:LTEMP+14) = ' PROG ABORTED,'
+            LTEMP = LTEMP + 14
+         ELSE
+            TEMP(LTEMP+1:LTEMP+16) = ' PROG CONTINUES,'
+            LTEMP = LTEMP + 16
+         ENDIF
+C
+C       FINALLY TELL WHETHER THERE SHOULD BE A TRACEBACK.
+C
+         IF (LKNTRL .GT. 0) THEN
+            TEMP(LTEMP+1:LTEMP+20) = ' TRACEBACK REQUESTED'
+            LTEMP = LTEMP + 20
+         ELSE
+            TEMP(LTEMP+1:LTEMP+24) = ' TRACEBACK NOT REQUESTED'
+            LTEMP = LTEMP + 24
+         ENDIF
+         CALL XERPRN (' ***', -1, TEMP(1:LTEMP), 72)
+      ENDIF
+C
+C       NOW SEND OUT THE MESSAGE.
+C
+      CALL XERPRN (' *  ', -1, MESSG, 72)
+C
+C       IF LKNTRL IS POSITIVE, WRITE THE ERROR NUMBER AND REQUEST A
+C          TRACEBACK.
+C
+      IF (LKNTRL .GT. 0) THEN
+         WRITE (TEMP, '(''ERROR NUMBER = '', I8)') NERR
+         DO 10 I=16,22
+            IF (TEMP(I:I) .NE. ' ') GO TO 20
+   10    CONTINUE
+C
+   20    CALL XERPRN (' *  ', -1, TEMP(1:15) // TEMP(I:23), 72)
+         CALL FDUMP
+      ENDIF
+C
+C       IF LKNTRL IS NOT ZERO, PRINT A BLANK LINE AND AN END OF MESSAGE.
+C
+      IF (LKNTRL .NE. 0) THEN
+         CALL XERPRN (' *  ', -1, ' ', 72)
+         CALL XERPRN (' ***', -1, 'END OF MESSAGE', 72)
+         CALL XERPRN ('    ',  0, ' ', 72)
+      ENDIF
+C
+C       IF THE ERROR IS NOT FATAL OR THE ERROR IS RECOVERABLE AND THE
+C       CONTROL FLAG IS SET FOR RECOVERY, THEN RETURN.
+C
+   30 IF (LEVEL.LE.0 .OR. (LEVEL.EQ.1 .AND. MKNTRL.LE.1)) RETURN
+C
+C       THE PROGRAM WILL BE STOPPED DUE TO AN UNRECOVERED ERROR OR A
+C       FATAL ERROR.  PRINT THE REASON FOR THE ABORT AND THE ERROR
+C       SUMMARY IF THE CONTROL FLAG AND THE MAXIMUM ERROR COUNT PERMIT.
+C
+      IF (LKNTRL.GT.0 .AND. KOUNT.LT.MAX(1,MAXMES)) THEN
+         IF (LEVEL .EQ. 1) THEN
+            CALL XERPRN
+     *         (' ***', -1, 'JOB ABORT DUE TO UNRECOVERED ERROR.', 72)
+         ELSE
+            CALL XERPRN(' ***', -1, 'JOB ABORT DUE TO FATAL ERROR.', 72)
+         ENDIF
+         CALL XERSVE (' ', ' ', ' ', -1, 0, 0, KDUMMY)
+         CALL XERHLT (' ')
+      ELSE
+         CALL XERHLT (MESSG)
+      ENDIF
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xerprn.f
@@ -0,0 +1,228 @@
+*DECK XERPRN
+      SUBROUTINE XERPRN (PREFIX, NPREF, MESSG, NWRAP)
+C***BEGIN PROLOGUE  XERPRN
+C***SUBSIDIARY
+C***PURPOSE  Print error messages processed by XERMSG.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XERPRN-A)
+C***KEYWORDS  ERROR MESSAGES, PRINTING, XERROR
+C***AUTHOR  Fong, Kirby, (NMFECC at LLNL)
+C***DESCRIPTION
+C
+C This routine sends one or more lines to each of the (up to five)
+C logical units to which error messages are to be sent.  This routine
+C is called several times by XERMSG, sometimes with a single line to
+C print and sometimes with a (potentially very long) message that may
+C wrap around into multiple lines.
+C
+C PREFIX  Input argument of type CHARACTER.  This argument contains
+C         characters to be put at the beginning of each line before
+C         the body of the message.  No more than 16 characters of
+C         PREFIX will be used.
+C
+C NPREF   Input argument of type INTEGER.  This argument is the number
+C         of characters to use from PREFIX.  If it is negative, the
+C         intrinsic function LEN is used to determine its length.  If
+C         it is zero, PREFIX is not used.  If it exceeds 16 or if
+C         LEN(PREFIX) exceeds 16, only the first 16 characters will be
+C         used.  If NPREF is positive and the length of PREFIX is less
+C         than NPREF, a copy of PREFIX extended with blanks to length
+C         NPREF will be used.
+C
+C MESSG   Input argument of type CHARACTER.  This is the text of a
+C         message to be printed.  If it is a long message, it will be
+C         broken into pieces for printing on multiple lines.  Each line
+C         will start with the appropriate prefix and be followed by a
+C         piece of the message.  NWRAP is the number of characters per
+C         piece; that is, after each NWRAP characters, we break and
+C         start a new line.  In addition the characters '$$' embedded
+C         in MESSG are a sentinel for a new line.  The counting of
+C         characters up to NWRAP starts over for each new line.  The
+C         value of NWRAP typically used by XERMSG is 72 since many
+C         older error messages in the SLATEC Library are laid out to
+C         rely on wrap-around every 72 characters.
+C
+C NWRAP   Input argument of type INTEGER.  This gives the maximum size
+C         piece into which to break MESSG for printing on multiple
+C         lines.  An embedded '$$' ends a line, and the count restarts
+C         at the following character.  If a line break does not occur
+C         on a blank (it would split a word) that word is moved to the
+C         next line.  Values of NWRAP less than 16 will be treated as
+C         16.  Values of NWRAP greater than 132 will be treated as 132.
+C         The actual line length will be NPREF + NWRAP after NPREF has
+C         been adjusted to fall between 0 and 16 and NWRAP has been
+C         adjusted to fall between 16 and 132.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  I1MACH, XGETUA
+C***REVISION HISTORY  (YYMMDD)
+C   880621  DATE WRITTEN
+C   880708  REVISED AFTER THE SLATEC CML SUBCOMMITTEE MEETING OF
+C           JUNE 29 AND 30 TO CHANGE THE NAME TO XERPRN AND TO REWORK
+C           THE HANDLING OF THE NEW LINE SENTINEL TO BEHAVE LIKE THE
+C           SLASH CHARACTER IN FORMAT STATEMENTS.
+C   890706  REVISED WITH THE HELP OF FRED FRITSCH AND REG CLEMENS TO
+C           STREAMLINE THE CODING AND FIX A BUG THAT CAUSED EXTRA BLANK
+C           LINES TO BE PRINTED.
+C   890721  REVISED TO ADD A NEW FEATURE.  A NEGATIVE VALUE OF NPREF
+C           CAUSES LEN(PREFIX) TO BE USED AS THE LENGTH.
+C   891013  REVISED TO CORRECT ERROR IN CALCULATING PREFIX LENGTH.
+C   891214  Prologue converted to Version 4.0 format.  (WRB)
+C   900510  Added code to break messages between words.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERPRN
+      CHARACTER*(*) PREFIX, MESSG
+      INTEGER NPREF, NWRAP
+      CHARACTER*148 CBUFF
+      INTEGER IU(5), NUNIT
+      CHARACTER*2 NEWLIN
+      PARAMETER (NEWLIN = '$$')
+C***FIRST EXECUTABLE STATEMENT  XERPRN
+      CALL XGETUA(IU,NUNIT)
+C
+C       A ZERO VALUE FOR A LOGICAL UNIT NUMBER MEANS TO USE THE STANDARD
+C       ERROR MESSAGE UNIT INSTEAD.  I1MACH(4) RETRIEVES THE STANDARD
+C       ERROR MESSAGE UNIT.
+C
+      N = I1MACH(4)
+      DO 10 I=1,NUNIT
+         IF (IU(I) .EQ. 0) IU(I) = N
+   10 CONTINUE
+C
+C       LPREF IS THE LENGTH OF THE PREFIX.  THE PREFIX IS PLACED AT THE
+C       BEGINNING OF CBUFF, THE CHARACTER BUFFER, AND KEPT THERE DURING
+C       THE REST OF THIS ROUTINE.
+C
+      IF ( NPREF .LT. 0 ) THEN
+         LPREF = LEN(PREFIX)
+      ELSE
+         LPREF = NPREF
+      ENDIF
+      LPREF = MIN(16, LPREF)
+      IF (LPREF .NE. 0) CBUFF(1:LPREF) = PREFIX
+C
+C       LWRAP IS THE MAXIMUM NUMBER OF CHARACTERS WE WANT TO TAKE AT ONE
+C       TIME FROM MESSG TO PRINT ON ONE LINE.
+C
+      LWRAP = MAX(16, MIN(132, NWRAP))
+C
+C       SET LENMSG TO THE LENGTH OF MESSG, IGNORE ANY TRAILING BLANKS.
+C
+      LENMSG = LEN(MESSG)
+      N = LENMSG
+      DO 20 I=1,N
+         IF (MESSG(LENMSG:LENMSG) .NE. ' ') GO TO 30
+         LENMSG = LENMSG - 1
+   20 CONTINUE
+   30 CONTINUE
+C
+C       IF THE MESSAGE IS ALL BLANKS, THEN PRINT ONE BLANK LINE.
+C
+      IF (LENMSG .EQ. 0) THEN
+         CBUFF(LPREF+1:LPREF+1) = ' '
+         DO 40 I=1,NUNIT
+            WRITE(IU(I), '(A)') CBUFF(1:LPREF+1)
+   40    CONTINUE
+         RETURN
+      ENDIF
+C
+C       SET NEXTC TO THE POSITION IN MESSG WHERE THE NEXT SUBSTRING
+C       STARTS.  FROM THIS POSITION WE SCAN FOR THE NEW LINE SENTINEL.
+C       WHEN NEXTC EXCEEDS LENMSG, THERE IS NO MORE TO PRINT.
+C       WE LOOP BACK TO LABEL 50 UNTIL ALL PIECES HAVE BEEN PRINTED.
+C
+C       WE LOOK FOR THE NEXT OCCURRENCE OF THE NEW LINE SENTINEL.  THE
+C       INDEX INTRINSIC FUNCTION RETURNS ZERO IF THERE IS NO OCCURRENCE
+C       OR IF THE LENGTH OF THE FIRST ARGUMENT IS LESS THAN THE LENGTH
+C       OF THE SECOND ARGUMENT.
+C
+C       THERE ARE SEVERAL CASES WHICH SHOULD BE CHECKED FOR IN THE
+C       FOLLOWING ORDER.  WE ARE ATTEMPTING TO SET LPIECE TO THE NUMBER
+C       OF CHARACTERS THAT SHOULD BE TAKEN FROM MESSG STARTING AT
+C       POSITION NEXTC.
+C
+C       LPIECE .EQ. 0   THE NEW LINE SENTINEL DOES NOT OCCUR IN THE
+C                       REMAINDER OF THE CHARACTER STRING.  LPIECE
+C                       SHOULD BE SET TO LWRAP OR LENMSG+1-NEXTC,
+C                       WHICHEVER IS LESS.
+C
+C       LPIECE .EQ. 1   THE NEW LINE SENTINEL STARTS AT MESSG(NEXTC:
+C                       NEXTC).  LPIECE IS EFFECTIVELY ZERO, AND WE
+C                       PRINT NOTHING TO AVOID PRODUCING UNNECESSARY
+C                       BLANK LINES.  THIS TAKES CARE OF THE SITUATION
+C                       WHERE THE LIBRARY ROUTINE HAS A MESSAGE OF
+C                       EXACTLY 72 CHARACTERS FOLLOWED BY A NEW LINE
+C                       SENTINEL FOLLOWED BY MORE CHARACTERS.  NEXTC
+C                       SHOULD BE INCREMENTED BY 2.
+C
+C       LPIECE .GT. LWRAP+1  REDUCE LPIECE TO LWRAP.
+C
+C       ELSE            THIS LAST CASE MEANS 2 .LE. LPIECE .LE. LWRAP+1
+C                       RESET LPIECE = LPIECE-1.  NOTE THAT THIS
+C                       PROPERLY HANDLES THE END CASE WHERE LPIECE .EQ.
+C                       LWRAP+1.  THAT IS, THE SENTINEL FALLS EXACTLY
+C                       AT THE END OF A LINE.
+C
+      NEXTC = 1
+   50 LPIECE = INDEX(MESSG(NEXTC:LENMSG), NEWLIN)
+      IF (LPIECE .EQ. 0) THEN
+C
+C       THERE WAS NO NEW LINE SENTINEL FOUND.
+C
+         IDELTA = 0
+         LPIECE = MIN(LWRAP, LENMSG+1-NEXTC)
+         IF (LPIECE .LT. LENMSG+1-NEXTC) THEN
+            DO 52 I=LPIECE+1,2,-1
+               IF (MESSG(NEXTC+I-1:NEXTC+I-1) .EQ. ' ') THEN
+                  LPIECE = I-1
+                  IDELTA = 1
+                  GOTO 54
+               ENDIF
+   52       CONTINUE
+         ENDIF
+   54    CBUFF(LPREF+1:LPREF+LPIECE) = MESSG(NEXTC:NEXTC+LPIECE-1)
+         NEXTC = NEXTC + LPIECE + IDELTA
+      ELSEIF (LPIECE .EQ. 1) THEN
+C
+C       WE HAVE A NEW LINE SENTINEL AT MESSG(NEXTC:NEXTC+1).
+C       DON'T PRINT A BLANK LINE.
+C
+         NEXTC = NEXTC + 2
+         GO TO 50
+      ELSEIF (LPIECE .GT. LWRAP+1) THEN
+C
+C       LPIECE SHOULD BE SET DOWN TO LWRAP.
+C
+         IDELTA = 0
+         LPIECE = LWRAP
+         DO 56 I=LPIECE+1,2,-1
+            IF (MESSG(NEXTC+I-1:NEXTC+I-1) .EQ. ' ') THEN
+               LPIECE = I-1
+               IDELTA = 1
+               GOTO 58
+            ENDIF
+   56    CONTINUE
+   58    CBUFF(LPREF+1:LPREF+LPIECE) = MESSG(NEXTC:NEXTC+LPIECE-1)
+         NEXTC = NEXTC + LPIECE + IDELTA
+      ELSE
+C
+C       IF WE ARRIVE HERE, IT MEANS 2 .LE. LPIECE .LE. LWRAP+1.
+C       WE SHOULD DECREMENT LPIECE BY ONE.
+C
+         LPIECE = LPIECE - 1
+         CBUFF(LPREF+1:LPREF+LPIECE) = MESSG(NEXTC:NEXTC+LPIECE-1)
+         NEXTC  = NEXTC + LPIECE + 2
+      ENDIF
+C
+C       PRINT
+C
+      DO 60 I=1,NUNIT
+         WRITE(IU(I), '(A)') CBUFF(1:LPREF+LPIECE)
+   60 CONTINUE
+C
+      IF (NEXTC .LE. LENMSG) GO TO 50
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xersve.f
@@ -0,0 +1,155 @@
+*DECK XERSVE
+      SUBROUTINE XERSVE (LIBRAR, SUBROU, MESSG, KFLAG, NERR, LEVEL,
+     +   ICOUNT)
+C***BEGIN PROLOGUE  XERSVE
+C***SUBSIDIARY
+C***PURPOSE  Record that an error has occurred.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3
+C***TYPE      ALL (XERSVE-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C *Usage:
+C
+C        INTEGER  KFLAG, NERR, LEVEL, ICOUNT
+C        CHARACTER * (len) LIBRAR, SUBROU, MESSG
+C
+C        CALL XERSVE (LIBRAR, SUBROU, MESSG, KFLAG, NERR, LEVEL, ICOUNT)
+C
+C *Arguments:
+C
+C        LIBRAR :IN    is the library that the message is from.
+C        SUBROU :IN    is the subroutine that the message is from.
+C        MESSG  :IN    is the message to be saved.
+C        KFLAG  :IN    indicates the action to be performed.
+C                      when KFLAG > 0, the message in MESSG is saved.
+C                      when KFLAG=0 the tables will be dumped and
+C                      cleared.
+C                      when KFLAG < 0, the tables will be dumped and
+C                      not cleared.
+C        NERR   :IN    is the error number.
+C        LEVEL  :IN    is the error severity.
+C        ICOUNT :OUT   the number of times this message has been seen,
+C                      or zero if the table has overflowed and does not
+C                      contain this message specifically.  When KFLAG=0,
+C                      ICOUNT will not be altered.
+C
+C *Description:
+C
+C   Record that this error occurred and possibly dump and clear the
+C   tables.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  I1MACH, XGETUA
+C***REVISION HISTORY  (YYMMDD)
+C   800319  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900413  Routine modified to remove reference to KFLAG.  (WRB)
+C   900510  Changed to add LIBRARY NAME and SUBROUTINE to calling
+C           sequence, use IF-THEN-ELSE, make number of saved entries
+C           easily changeable, changed routine name from XERSAV to
+C           XERSVE.  (RWC)
+C   910626  Added LIBTAB and SUBTAB to SAVE statement.  (BKS)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XERSVE
+      PARAMETER (LENTAB=10)
+      INTEGER LUN(5)
+      CHARACTER*(*) LIBRAR, SUBROU, MESSG
+      CHARACTER*8  LIBTAB(LENTAB), SUBTAB(LENTAB), LIB, SUB
+      CHARACTER*20 MESTAB(LENTAB), MES
+      DIMENSION NERTAB(LENTAB), LEVTAB(LENTAB), KOUNT(LENTAB)
+      SAVE LIBTAB, SUBTAB, MESTAB, NERTAB, LEVTAB, KOUNT, KOUNTX, NMSG
+      DATA KOUNTX/0/, NMSG/0/
+C***FIRST EXECUTABLE STATEMENT  XERSVE
+C
+      IF (KFLAG.LE.0) THEN
+C
+C        Dump the table.
+C
+         IF (NMSG.EQ.0) RETURN
+C
+C        Print to each unit.
+C
+         CALL XGETUA (LUN, NUNIT)
+         DO 20 KUNIT = 1,NUNIT
+            IUNIT = LUN(KUNIT)
+            IF (IUNIT.EQ.0) IUNIT = I1MACH(4)
+C
+C           Print the table header.
+C
+            WRITE (IUNIT,9000)
+C
+C           Print body of table.
+C
+            DO 10 I = 1,NMSG
+               WRITE (IUNIT,9010) LIBTAB(I), SUBTAB(I), MESTAB(I),
+     *            NERTAB(I),LEVTAB(I),KOUNT(I)
+   10       CONTINUE
+C
+C           Print number of other errors.
+C
+            IF (KOUNTX.NE.0) WRITE (IUNIT,9020) KOUNTX
+            WRITE (IUNIT,9030)
+   20    CONTINUE
+C
+C        Clear the error tables.
+C
+         IF (KFLAG.EQ.0) THEN
+            NMSG = 0
+            KOUNTX = 0
+         ENDIF
+      ELSE
+C
+C        PROCESS A MESSAGE...
+C        SEARCH FOR THIS MESSG, OR ELSE AN EMPTY SLOT FOR THIS MESSG,
+C        OR ELSE DETERMINE THAT THE ERROR TABLE IS FULL.
+C
+         LIB = LIBRAR
+         SUB = SUBROU
+         MES = MESSG
+         DO 30 I = 1,NMSG
+            IF (LIB.EQ.LIBTAB(I) .AND. SUB.EQ.SUBTAB(I) .AND.
+     *         MES.EQ.MESTAB(I) .AND. NERR.EQ.NERTAB(I) .AND.
+     *         LEVEL.EQ.LEVTAB(I)) THEN
+                  KOUNT(I) = KOUNT(I) + 1
+                  ICOUNT = KOUNT(I)
+                  RETURN
+            ENDIF
+   30    CONTINUE
+C
+         IF (NMSG.LT.LENTAB) THEN
+C
+C           Empty slot found for new message.
+C
+            NMSG = NMSG + 1
+            LIBTAB(I) = LIB
+            SUBTAB(I) = SUB
+            MESTAB(I) = MES
+            NERTAB(I) = NERR
+            LEVTAB(I) = LEVEL
+            KOUNT (I) = 1
+            ICOUNT    = 1
+         ELSE
+C
+C           Table is full.
+C
+            KOUNTX = KOUNTX+1
+            ICOUNT = 0
+         ENDIF
+      ENDIF
+      RETURN
+C
+C     Formats.
+C
+ 9000 FORMAT ('0          ERROR MESSAGE SUMMARY' /
+     +   ' LIBRARY    SUBROUTINE MESSAGE START             NERR',
+     +   '     LEVEL     COUNT')
+ 9010 FORMAT (1X,A,3X,A,3X,A,3I10)
+ 9020 FORMAT ('0OTHER ERRORS NOT INDIVIDUALLY TABULATED = ', I10)
+ 9030 FORMAT (1X)
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xgetf.f
@@ -0,0 +1,30 @@
+*DECK XGETF
+      SUBROUTINE XGETF (KONTRL)
+C***BEGIN PROLOGUE  XGETF
+C***PURPOSE  Return the current value of the error control flag.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XGETF-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C   Abstract
+C        XGETF returns the current value of the error control flag
+C        in KONTRL.  See subroutine XSETF for flag value meanings.
+C        (KONTRL is an output parameter only.)
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  J4SAVE
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XGETF
+C***FIRST EXECUTABLE STATEMENT  XGETF
+      KONTRL = J4SAVE(2,0,.FALSE.)
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xgetua.f
@@ -0,0 +1,51 @@
+*DECK XGETUA
+      SUBROUTINE XGETUA (IUNITA, N)
+C***BEGIN PROLOGUE  XGETUA
+C***PURPOSE  Return unit number(s) to which error messages are being
+C            sent.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3C
+C***TYPE      ALL (XGETUA-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        XGETUA may be called to determine the unit number or numbers
+C        to which error messages are being sent.
+C        These unit numbers may have been set by a call to XSETUN,
+C        or a call to XSETUA, or may be a default value.
+C
+C     Description of Parameters
+C      --Output--
+C        IUNIT - an array of one to five unit numbers, depending
+C                on the value of N.  A value of zero refers to the
+C                default unit, as defined by the I1MACH machine
+C                constant routine.  Only IUNIT(1),...,IUNIT(N) are
+C                defined by XGETUA.  The values of IUNIT(N+1),...,
+C                IUNIT(5) are not defined (for N .LT. 5) or altered
+C                in any way by XGETUA.
+C        N     - the number of units to which copies of the
+C                error messages are being sent.  N will be in the
+C                range from 1 to 5.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  J4SAVE
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XGETUA
+      DIMENSION IUNITA(5)
+C***FIRST EXECUTABLE STATEMENT  XGETUA
+      N = J4SAVE(5,0,.FALSE.)
+      DO 30 I=1,N
+         INDEX = I+4
+         IF (I.EQ.1) INDEX = 3
+         IUNITA(I) = J4SAVE(INDEX,0,.FALSE.)
+   30 CONTINUE
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xsetf.f
@@ -0,0 +1,60 @@
+*DECK XSETF
+      SUBROUTINE XSETF (KONTRL)
+C***BEGIN PROLOGUE  XSETF
+C***PURPOSE  Set the error control flag.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3A
+C***TYPE      ALL (XSETF-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        XSETF sets the error control flag value to KONTRL.
+C        (KONTRL is an input parameter only.)
+C        The following table shows how each message is treated,
+C        depending on the values of KONTRL and LEVEL.  (See XERMSG
+C        for description of LEVEL.)
+C
+C        If KONTRL is zero or negative, no information other than the
+C        message itself (including numeric values, if any) will be
+C        printed.  If KONTRL is positive, introductory messages,
+C        trace-backs, etc., will be printed in addition to the message.
+C
+C              ABS(KONTRL)
+C        LEVEL        0              1              2
+C        value
+C          2        fatal          fatal          fatal
+C
+C          1     not printed      printed         fatal
+C
+C          0     not printed      printed        printed
+C
+C         -1     not printed      printed        printed
+C                                  only           only
+C                                  once           once
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  J4SAVE, XERMSG
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   890531  Changed all specific intrinsics to generic.  (WRB)
+C   890531  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900510  Change call to XERRWV to XERMSG.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XSETF
+      CHARACTER *8 XERN1
+C***FIRST EXECUTABLE STATEMENT  XSETF
+      IF (ABS(KONTRL) .GT. 2) THEN
+         WRITE (XERN1, '(I8)') KONTRL
+         CALL XERMSG ('SLATEC', 'XSETF',
+     *      'INVALID ARGUMENT = ' // XERN1, 1, 2)
+         RETURN
+      ENDIF
+C
+      JUNK = J4SAVE(2,KONTRL,.TRUE.)
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/libcruft/slatec-err/xsetua.f
@@ -0,0 +1,59 @@
+*DECK XSETUA
+      SUBROUTINE XSETUA (IUNITA, N)
+C***BEGIN PROLOGUE  XSETUA
+C***PURPOSE  Set logical unit numbers (up to 5) to which error
+C            messages are to be sent.
+C***LIBRARY   SLATEC (XERROR)
+C***CATEGORY  R3B
+C***TYPE      ALL (XSETUA-A)
+C***KEYWORDS  ERROR, XERROR
+C***AUTHOR  Jones, R. E., (SNLA)
+C***DESCRIPTION
+C
+C     Abstract
+C        XSETUA may be called to declare a list of up to five
+C        logical units, each of which is to receive a copy of
+C        each error message processed by this package.
+C        The purpose of XSETUA is to allow simultaneous printing
+C        of each error message on, say, a main output file,
+C        an interactive terminal, and other files such as graphics
+C        communication files.
+C
+C     Description of Parameters
+C      --Input--
+C        IUNIT - an array of up to five unit numbers.
+C                Normally these numbers should all be different
+C                (but duplicates are not prohibited.)
+C        N     - the number of unit numbers provided in IUNIT
+C                must have 1 .LE. N .LE. 5.
+C
+C***REFERENCES  R. E. Jones and D. K. Kahaner, XERROR, the SLATEC
+C                 Error-handling Package, SAND82-0800, Sandia
+C                 Laboratories, 1982.
+C***ROUTINES CALLED  J4SAVE, XERMSG
+C***REVISION HISTORY  (YYMMDD)
+C   790801  DATE WRITTEN
+C   861211  REVISION DATE from Version 3.2
+C   891214  Prologue converted to Version 4.0 format.  (BAB)
+C   900510  Change call to XERRWV to XERMSG.  (RWC)
+C   920501  Reformatted the REFERENCES section.  (WRB)
+C***END PROLOGUE  XSETUA
+      DIMENSION IUNITA(5)
+      CHARACTER *8 XERN1
+C***FIRST EXECUTABLE STATEMENT  XSETUA
+C
+      IF (N.LT.1 .OR. N.GT.5) THEN
+         WRITE (XERN1, '(I8)') N
+         CALL XERMSG ('SLATEC', 'XSETUA',
+     *      'INVALID NUMBER OF UNITS, N = ' // XERN1, 1, 2)
+         RETURN
+      ENDIF
+C
+      DO 10 I=1,N
+         INDEX = I+4
+         IF (I.EQ.1) INDEX = 3
+         JUNK = J4SAVE(INDEX,IUNITA(I),.TRUE.)
+   10 CONTINUE
+      JUNK = J4SAVE(5,N,.TRUE.)
+      RETURN
+      END
new file mode 100644
--- /dev/null
+++ b/liboctave/strftime.c
@@ -0,0 +1,895 @@
+/* Copyright (C) 1991, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
+
+   NOTE: The canonical source of this file is maintained with the GNU C
+   Library.  Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+   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 2, 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, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef HAVE_STRFTIME
+
+#ifdef _LIBC
+# define HAVE_LIMITS_H 1
+# define HAVE_MBLEN 1
+# define HAVE_MBRLEN 1
+# define HAVE_STRUCT_ERA_ENTRY 1
+# define HAVE_TM_GMTOFF 1
+# define HAVE_TM_ZONE 1
+# define MULTIBYTE_IS_FORMAT_SAFE 1
+# define STDC_HEADERS 1
+# include <ansidecl.h>
+# include "../locale/localeinfo.h"
+#endif
+
+#include <sys/types.h>		/* Some systems define `time_t' here.  */
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_TZNAME
+extern char *tzname[];
+#endif
+
+/* Do multibyte processing if multibytes are supported, unless
+   multibyte sequences are safe in formats.  Multibyte sequences are
+   safe if they cannot contain byte sequences that look like format
+   conversion specifications.  The GNU C Library uses UTF8 multibyte
+   encoding, which is safe for formats, but strftime.c can be used
+   with other C libraries that use unsafe encodings.  */
+#define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
+
+#if DO_MULTIBYTE
+# if HAVE_MBRLEN
+#  include <wchar.h>
+# else
+   /* Simulate mbrlen with mblen as best we can.  */
+#  define mbstate_t int
+#  define mbrlen(s, n, ps) mblen (s, n)
+#  define mbsinit(ps) (*(ps) == 0)
+# endif
+  static const mbstate_t mbstate_zero;
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#if STDC_HEADERS
+# include <stddef.h>
+# include <stdlib.h>
+# include <string.h>
+#else
+# define memcpy(d, s, n) bcopy (s, d, n)
+#endif
+
+#ifndef __P
+#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
+#define __P(args) args
+#else
+#define __P(args) ()
+#endif  /* GCC.  */
+#endif  /* Not __P.  */
+
+#ifndef PTR
+#ifdef __STDC__
+#define PTR void *
+#else
+#define PTR char *
+#endif
+#endif
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#define TYPE_SIGNED(t) ((t) -1 < 0)
+
+/* Bound on length of the string representing an integer value of type t.
+   Subtract one for the sign bit if t is signed;
+   302 / 1000 is log10 (2) rounded up;
+   add one for integer division truncation;
+   add one more for a minus sign if t is signed.  */
+#define INT_STRLEN_BOUND(t) \
+  ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 100 + 1 + TYPE_SIGNED (t))
+
+#define TM_YEAR_BASE 1900
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+   except every 100th isn't, and every 400th is).  */
+#define __isleap(year)	\
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+
+#ifdef _LIBC
+# define gmtime_r __gmtime_r
+# define localtime_r __localtime_r
+#else
+# if ! HAVE_LOCALTIME_R
+#  if ! HAVE_TM_GMTOFF
+/* Approximate gmtime_r as best we can in its absence.  */
+#define gmtime_r my_gmtime_r
+static struct tm *gmtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+gmtime_r (t, tp)
+     const time_t *t;
+     struct tm *tp;
+{
+  struct tm *l = gmtime (t);
+  if (! l)
+    return 0;
+  *tp = *l;
+  return tp;
+}
+#  endif /* ! HAVE_TM_GMTOFF */
+
+/* Approximate localtime_r as best we can in its absence.  */
+#define localtime_r my_localtime_r
+static struct tm *localtime_r __P ((const time_t *, struct tm *));
+static struct tm *
+localtime_r (t, tp)
+     const time_t *t;
+     struct tm *tp;
+{
+  struct tm *l = localtime (t);
+  if (! l)
+    return 0;
+  *tp = *l;
+  return tp;
+}
+# endif /* ! HAVE_LOCALTIME_R */
+#endif /* ! defined (_LIBC) */
+
+
+#define	add(n, f)							      \
+  do									      \
+    {									      \
+      i += (n);								      \
+      if (i >= maxsize)							      \
+	return 0;							      \
+      else								      \
+	if (p)								      \
+	  {								      \
+	    f;								      \
+	    p += (n);							      \
+	  }								      \
+    } while (0)
+#define	cpy(n, s)	add ((n), memcpy((PTR) p, (PTR) (s), (n)))
+
+#if ! HAVE_TM_GMTOFF
+/* Yield the difference between *A and *B,
+   measured in seconds, ignoring leap seconds.  */
+static int tm_diff __P ((const struct tm *, const struct tm *));
+static int
+tm_diff (a, b)
+     const struct tm *a;
+     const struct tm *b;
+{
+  /* Compute intervening leap days correctly even if year is negative.
+     Take care to avoid int overflow in leap day calculations,
+     but it's OK to assume that A and B are close to each other.  */
+  int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
+  int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
+  int a100 = a4 / 25 - (a4 % 25 < 0);
+  int b100 = b4 / 25 - (b4 % 25 < 0);
+  int a400 = a100 >> 2;
+  int b400 = b100 >> 2;
+  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+  int years = a->tm_year - b->tm_year;
+  int days = (365 * years + intervening_leap_days
+	      + (a->tm_yday - b->tm_yday));
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+		+ (a->tm_min - b->tm_min))
+	  + (a->tm_sec - b->tm_sec));
+}
+#endif /* ! HAVE_TM_GMTOFF */
+
+
+
+/* The number of days from the first day of the first ISO week of this
+   year to the year day YDAY with week day WDAY.  ISO weeks start on
+   Monday; the first ISO week has the year's first Thursday.  YDAY may
+   be as small as YDAY_MINIMUM.  */
+#define ISO_WEEK_START_WDAY 1 /* Monday */
+#define ISO_WEEK1_WDAY 4 /* Thursday */
+#define YDAY_MINIMUM (-366)
+static int iso_week_days __P ((int, int));
+#ifdef __GNUC__
+inline
+#endif
+static int
+iso_week_days (yday, wday)
+     int yday;
+     int wday;
+{
+  /* Add enough to the first operand of % to make it nonnegative.  */
+  int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
+  return (yday
+	  - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
+	  + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
+}
+
+
+#ifndef _NL_CURRENT
+static char const weekday_name[][10] =
+  {
+    "Sunday", "Monday", "Tuesday", "Wednesday",
+    "Thursday", "Friday", "Saturday"
+  };
+static char const month_name[][10] =
+  {
+    "January", "February", "March", "April", "May", "June",
+    "July", "August", "September", "October", "November", "December"
+  };
+#endif
+
+/* Write information from TP into S according to the format
+   string FORMAT, writing no more that MAXSIZE characters
+   (including the terminating '\0') and returning number of
+   characters written.  If S is NULL, nothing will be written
+   anywhere, so to determine how many characters would be
+   written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
+size_t
+strftime (s, maxsize, format, tp)
+      char *s;
+      size_t maxsize;
+      const char *format;
+      register const struct tm *tp;
+{
+  int hour12 = tp->tm_hour;
+#ifdef _NL_CURRENT
+  const char *const a_wkday = _NL_CURRENT (LC_TIME, ABDAY_1 + tp->tm_wday);
+  const char *const f_wkday = _NL_CURRENT (LC_TIME, DAY_1 + tp->tm_wday);
+  const char *const a_month = _NL_CURRENT (LC_TIME, ABMON_1 + tp->tm_mon);
+  const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
+  const char *const ampm = _NL_CURRENT (LC_TIME,
+					hour12 > 11 ? PM_STR : AM_STR);
+  size_t aw_len = strlen (a_wkday);
+  size_t am_len = strlen (a_month);
+  size_t ap_len = strlen (ampm);
+#else
+  const char *const f_wkday = weekday_name[tp->tm_wday];
+  const char *const f_month = month_name[tp->tm_mon];
+  const char *const a_wkday = f_wkday;
+  const char *const a_month = f_month;
+  const char *const ampm = "AMPM" + 2 * (hour12 > 11);
+  size_t aw_len = 3;
+  size_t am_len = 3;
+  size_t ap_len = 2;
+#endif
+  size_t wkday_len = strlen (f_wkday);
+  size_t month_len = strlen (f_month);
+  const char *zone;
+  size_t zonelen;
+  register size_t i = 0;
+  register char *p = s;
+  register const char *f;
+
+  zone = 0;
+#if HAVE_TM_ZONE
+  zone = (const char *) tp->tm_zone;
+#endif
+#if HAVE_TZNAME
+  if (!(zone && *zone) && tp->tm_isdst >= 0)
+    zone = tzname[tp->tm_isdst];
+#endif
+  if (! zone)
+    zone = "";		/* POSIX.2 requires the empty string here.  */
+
+  zonelen = strlen (zone);
+
+  if (hour12 > 12)
+    hour12 -= 12;
+  else
+    if (hour12 == 0) hour12 = 12;
+
+  for (f = format; *f != '\0'; ++f)
+    {
+      int pad;			/* Padding for number ('-', '_', or 0).  */
+      int modifier;		/* Field modifier ('E', 'O', or 0).  */
+      int digits;		/* Max digits for numeric format.  */
+      int number_value; 	/* Numeric value to be printed.  */
+      int negative_number;	/* 1 if the number is negative.  */
+      const char *subfmt;
+      char *bufp;
+      char buf[1 + (sizeof (int) < sizeof (time_t)
+		    ? INT_STRLEN_BOUND (time_t)
+		    : INT_STRLEN_BOUND (int))];
+
+#if DO_MULTIBYTE
+
+       switch (*f)
+	{
+	case '%':
+	  break;
+
+	case '\a': case '\b': case '\t': case '\n':
+	case '\v': case '\f': case '\r':
+	case ' ': case '!': case '"': case '#': case '&': case'\'':
+	case '(': case ')': case '*': case '+': case ',': case '-':
+	case '.': case '/': case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7': case '8': case '9':
+	case ':': case ';': case '<': case '=': case '>': case '?':
+	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+	case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+	case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+	case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+	case 'Y': case 'Z': case '[': case'\\': case ']': case '^':
+	case '_': case 'a': case 'b': case 'c': case 'd': case 'e':
+	case 'f': case 'g': case 'h': case 'i': case 'j': case 'k':
+	case 'l': case 'm': case 'n': case 'o': case 'p': case 'q':
+	case 'r': case 's': case 't': case 'u': case 'v': case 'w':
+	case 'x': case 'y': case 'z': case '{': case '|': case '}':
+	case '~':
+	  /* The C Standard requires these 98 characters (plus '%') to
+	     be in the basic execution character set.  None of these
+	     characters can start a multibyte sequence, so they need
+	     not be analyzed further.  */
+	  add (1, *p = *f);
+	  continue;
+
+	default:
+	  /* Copy this multibyte sequence until we reach its end, find
+	     an error, or come back to the initial shift state.  */
+	  {
+	    mbstate_t mbstate = mbstate_zero;
+	    size_t len = 0;
+
+	    do
+	      {
+		size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
+
+		if (bytes == 0)
+		  break;
+
+		if (bytes == (size_t) -2 || bytes == (size_t) -1)
+		  {
+		    len++;
+		    break;
+		  }
+
+		len += bytes;
+	      }
+	    while (! mbsinit (&mbstate));
+
+	    cpy (len, f);
+	    continue;
+	  }
+	}
+
+#else /* ! DO_MULTIBYTE */
+
+      /* Either multibyte encodings are not supported, or they are
+	 safe for formats, so any non-'%' byte can be copied through.  */
+      if (*f != '%')
+	{
+	  add (1, *p = *f);
+	  continue;
+	}
+
+#endif /* ! DO_MULTIBYTE */
+
+      /* Check for flags that can modify a number format.  */
+      ++f;
+      switch (*f)
+	{
+	case '_':
+	case '-':
+	  pad = *f++;
+	  break;
+
+	default:
+	  pad = 0;
+	  break;
+	}
+
+      /* Check for modifiers.  */
+      switch (*f)
+	{
+	case 'E':
+	case 'O':
+	  modifier = *f++;
+	  break;
+
+	default:
+	  modifier = 0;
+	  break;
+	}
+
+      /* Now do the specified format.  */
+      switch (*f)
+	{
+#define DO_NUMBER(d, v) \
+	  digits = d; number_value = v; goto do_number
+#define DO_NUMBER_SPACEPAD(d, v) \
+	  digits = d; number_value = v; goto do_number_spacepad
+
+	case '%':
+	  if (modifier != 0)
+	    goto bad_format;
+	  add (1, *p = *f);
+	  break;
+
+	case 'a':
+	  if (modifier != 0)
+	    goto bad_format;
+	  cpy (aw_len, a_wkday);
+	  break;
+
+	case 'A':
+	  if (modifier != 0)
+	    goto bad_format;
+	  cpy (wkday_len, f_wkday);
+	  break;
+
+	case 'b':
+	case 'h':		/* POSIX.2 extension.  */
+	  if (modifier != 0)
+	    goto bad_format;
+	  cpy (am_len, a_month);
+	  break;
+
+	case 'B':
+	  if (modifier != 0)
+	    goto bad_format;
+	  cpy (month_len, f_month);
+	  break;
+
+	case 'c':
+	  if (modifier == 'O')
+	    goto bad_format;
+#ifdef _NL_CURRENT
+	  if (! (modifier == 'E'
+		 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT)) != '\0'))
+	    subfmt = _NL_CURRENT (LC_TIME, D_T_FMT);
+#else
+	  subfmt = "%a %b %e %H:%M:%S %Y";
+#endif
+
+	subformat:
+	  {
+	    size_t len = strftime (p, maxsize - i, subfmt, tp);
+	    if (len == 0 && *subfmt)
+	      return 0;
+	    add (len, ;);
+	  }
+	  break;
+
+	case 'C':		/* POSIX.2 extension.  */
+	  if (modifier == 'O')
+	    goto bad_format;
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  size_t len = strlen (era->name_fmt);
+		  cpy (len, era->name_fmt);
+		  break;
+		}
+	    }
+#endif
+	  {
+	    int year = tp->tm_year + TM_YEAR_BASE;
+	    DO_NUMBER (1, year / 100 - (year % 100 < 0));
+	  }
+
+	case 'x':
+	  if (modifier == 'O')
+	    goto bad_format;
+#ifdef _NL_CURRENT
+	  if (! (modifier == 'E'
+		 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_D_FMT)) != '\0'))
+	    subfmt = _NL_CURRENT (LC_TIME, D_FMT);
+	  goto subformat;
+#endif
+	  /* Fall through.  */
+	case 'D':		/* POSIX.2 extension.  */
+	  if (modifier != 0)
+	    goto bad_format;
+	  subfmt = "%m/%d/%y";
+	  goto subformat;
+
+	case 'd':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, tp->tm_mday);
+
+	case 'e':		/* POSIX.2 extension.  */
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER_SPACEPAD (2, tp->tm_mday);
+
+	  /* All numeric formats set DIGITS and NUMBER_VALUE and then
+	     jump to one of these two labels.  */
+
+	do_number_spacepad:
+	  /* Force `_' flag.  */
+	  pad = '_';
+
+	do_number:
+	  /* Format the number according to the MODIFIER flag.  */
+
+#ifdef _NL_CURRENT
+	  if (modifier == 'O' && 0 <= number_value)
+	    {
+	      /* Get the locale specific alternate representation of
+		 the number NUMBER_VALUE.  If none exist NULL is returned.  */
+	      const char *cp = _nl_get_alt_digit (number_value);
+
+	      if (cp != NULL)
+		{
+		  size_t digitlen = strlen (cp);
+		  if (digitlen != 0)
+		    {
+		      cpy (digitlen, cp);
+		      break;
+		    }
+		}
+	    }
+#endif
+	  {
+	    unsigned int u = number_value;
+
+	    bufp = buf + sizeof (buf);
+	    negative_number = number_value < 0;
+
+	    if (negative_number)
+	      u = -u;
+
+	    do
+	      *--bufp = u % 10 + '0';
+	    while ((u /= 10) != 0);
+  	  }
+
+	do_number_sign_and_padding:
+	  if (negative_number)
+	    *--bufp = '-';
+
+	  if (pad != '-')
+	    {
+	      int padding = digits - (buf + sizeof (buf) - bufp);
+
+	      if (pad == '_')
+		{
+		  while (0 < padding--)
+		    *--bufp = ' ';
+		}
+	      else
+		{
+		  bufp += negative_number;
+		  while (0 < padding--)
+		    *--bufp = '0';
+		  if (negative_number)
+		    *--bufp = '-';
+		}
+	    }
+
+	  cpy (buf + sizeof (buf) - bufp, bufp);
+	  break;
+
+
+	case 'H':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, tp->tm_hour);
+
+	case 'I':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, hour12);
+
+	case 'k':		/* GNU extension.  */
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER_SPACEPAD (2, tp->tm_hour);
+
+	case 'l':		/* GNU extension.  */
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER_SPACEPAD (2, hour12);
+
+	case 'j':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (3, 1 + tp->tm_yday);
+
+	case 'M':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, tp->tm_min);
+
+	case 'm':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, tp->tm_mon + 1);
+
+	case 'n':		/* POSIX.2 extension.  */
+	  add (1, *p = '\n');
+	  break;
+
+	case 'p':
+	  cpy (ap_len, ampm);
+	  break;
+
+	case 'R':		/* GNU extension.  */
+	  subfmt = "%H:%M";
+	  goto subformat;
+
+	case 'r':		/* POSIX.2 extension.  */
+#ifdef _NL_CURRENT
+	  if (*(subfmt = _NL_CURRENT (LC_TIME, T_FMT_AMPM)) == '\0')
+#endif
+	    subfmt = "%I:%M:%S %p";
+	  goto subformat;
+
+	case 'S':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, tp->tm_sec);
+
+	case 's':		/* GNU extension.  */
+  	  {
+	    struct tm ltm;
+	    time_t t;
+
+	    ltm = *tp;
+	    t = mktime (&ltm);
+
+	    /* Generate string value for T using time_t arithmetic;
+	       this works even if sizeof (long) < sizeof (time_t).  */
+
+	    bufp = buf + sizeof (buf);
+	    negative_number = t < 0;
+
+	    do
+	      {
+		int d = t % 10;
+		t /= 10;
+
+		if (negative_number)
+		  {
+		    d = -d;
+
+		    /* Adjust if division truncates to minus infinity.  */
+		    if (0 < -1 % 10 && d < 0)
+		      {
+			t++;
+			d += 10;
+		      }
+		  }
+
+		*--bufp = d + '0';
+	      }
+	    while (t != 0);
+
+	    digits = 1;
+	    goto do_number_sign_and_padding;
+	  }
+
+	case 'X':
+	  if (modifier == 'O')
+	    goto bad_format;
+#ifdef _NL_CURRENT
+	  if (! (modifier == 'E'
+		 && *(subfmt = _NL_CURRENT (LC_TIME, ERA_T_FMT)) != '\0'))
+	    subfmt = _NL_CURRENT (LC_TIME, T_FMT);
+	  goto subformat;
+#endif
+	  /* Fall through.  */
+	case 'T':		/* POSIX.2 extension.  */
+	  subfmt = "%H:%M:%S";
+	  goto subformat;
+
+	case 't':		/* POSIX.2 extension.  */
+	  add (1, *p = '\t');
+	  break;
+
+	case 'u':		/* POSIX.2 extension.  */
+	  DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
+
+	case 'U':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
+
+	case 'V':
+	case 'g':		/* GNU extension.  */
+	case 'G':		/* GNU extension.  */
+	  if (modifier == 'E')
+	    goto bad_format;
+	  {
+	    int year = tp->tm_year + TM_YEAR_BASE;
+	    int days = iso_week_days (tp->tm_yday, tp->tm_wday);
+
+	    if (days < 0)
+	      {
+		/* This ISO week belongs to the previous year.  */
+		year--;
+		days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
+				      tp->tm_wday);
+	      }
+	    else
+	      {
+		int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
+				       tp->tm_wday);
+		if (0 <= d)
+		  {
+		    /* This ISO week belongs to the next year.  */
+		    year++;
+		    days = d;
+		  }
+	      }
+
+	    switch (*f)
+	      {
+	      case 'g':
+		DO_NUMBER (2, (year % 100 + 100) % 100);
+
+	      case 'G':
+		DO_NUMBER (1, year);
+
+	      default:
+		DO_NUMBER (2, days / 7 + 1);
+	      }
+	  }
+
+	case 'W':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
+
+	case 'w':
+	  if (modifier == 'E')
+	    goto bad_format;
+
+	  DO_NUMBER (1, tp->tm_wday);
+
+	case 'Y':
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  subfmt = strchr (era->name_fmt, '\0') + 1;
+		  goto subformat;
+		}
+	    }
+#endif
+	  if (modifier == 'O')
+	    goto bad_format;
+	  else
+	    DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
+
+	case 'y':
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  int delta = tp->tm_year - era->start_date[0];
+		  DO_NUMBER (1, (era->offset
+				 + (era->direction == '-' ? -delta : delta)));
+		}
+	    }
+#endif
+	  DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
+
+	case 'Z':
+	  cpy (zonelen, zone);
+	  break;
+
+	case 'z':		/* GNU extension.  */
+	  if (tp->tm_isdst < 0)
+	    break;
+
+	  {
+	    int diff;
+#if HAVE_TM_GMTOFF
+	    diff = tp->tm_gmtoff;
+#else
+	    struct tm gtm;
+	    struct tm ltm;
+	    time_t lt;
+
+	    ltm = *tp;
+	    lt = mktime (&ltm);
+
+	    if (lt == (time_t) -1)
+	      {
+		/* mktime returns -1 for errors, but -1 is also a
+		   valid time_t value.  Check whether an error really
+		   occurred.  */
+		struct tm tm;
+		localtime_r (&lt, &tm);
+
+		if ((ltm.tm_sec ^ tm.tm_sec)
+		    | (ltm.tm_min ^ tm.tm_min)
+		    | (ltm.tm_hour ^ tm.tm_hour)
+		    | (ltm.tm_mday ^ tm.tm_mday)
+		    | (ltm.tm_mon ^ tm.tm_mon)
+		    | (ltm.tm_year ^ tm.tm_year))
+		  break;
+	      }
+
+	    if (! gmtime_r (&lt, &gtm))
+	      break;
+
+	    diff = tm_diff (&ltm, &gtm);
+#endif
+
+	    if (diff < 0)
+	      {
+		add (1, *p = '-');
+		diff = -diff;
+	      }
+	    else
+	      add (1, *p = '+');
+
+	    diff /= 60;
+	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
+	  }
+
+	case '\0':		/* GNU extension: % at end of format.  */
+	    --f;
+	    /* Fall through.  */
+	default:
+	  /* Unknown format; output the format, including the '%',
+	     since this is most likely the right thing to do if a
+	     multibyte string has been misparsed.  */
+	bad_format:
+	  {
+	    int flen;
+	    for (flen = 1; f[1 - flen] != '%'; flen++)
+	      continue;
+	    cpy (flen, &f[1 - flen]);
+	  }
+	  break;
+	}
+    }
+
+  if (p)
+    *p = '\0';
+  return i;
+}
+
+#endif