AS400Xtfr.java
上传用户:xiekaiwei
上传日期:2015-07-04
资源大小:620k
文件大小:25k
源码类别:

Telnet客户端

开发平台:

Java

  1. package org.tn5250j.sql;
  2. /**
  3.  * Title: AS400Xtfr.java
  4.  * Copyright:   Copyright (c) 2002
  5.  * Company:
  6.  * @author  Kenneth J. Pouncey
  7.  * @version 0.5
  8.  *
  9.  * Description:
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2, or (at your option)
  14.  * any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this software; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  24.  * Boston, MA 02111-1307 USA
  25.  *
  26.  */
  27. import java.util.*;
  28. import java.io.*;
  29. import java.text.*;
  30. import org.tn5250j.event.*;
  31. import org.tn5250j.tools.filters.*;
  32. import java.sql.*;
  33. import org.tn5250j.framework.tn5250.tnvt;
  34. public class AS400Xtfr {
  35.    private boolean loggedIn;
  36.    private String hostName;
  37.    private int timeout = 50000;
  38.    private boolean connected;
  39.    private ArrayList ffd;
  40.    private tnvt vt;
  41.    private Vector listeners;
  42.    private FTPStatusEvent status;
  43.    private boolean aborted;
  44.    private char decChar;
  45.    private OutputFilterInterface ofi;
  46.    private Thread getThread;
  47.    private String user;
  48.    private String pass;
  49.    private Connection connection;
  50.    public AS400Xtfr (tnvt v) {
  51.       vt = v;
  52.       status = new FTPStatusEvent(this);
  53.       // obtain the decimal separator for the machine locale
  54.       DecimalFormat formatter =
  55.             (DecimalFormat)NumberFormat.getInstance(Locale.getDefault());
  56.       decChar = formatter.getDecimalFormatSymbols().getDecimalSeparator();
  57.    }
  58.    public void setOutputFilter (OutputFilterInterface o) {
  59.       ofi = o;
  60.    }
  61.    public void setDecimalChar(char dec) {
  62.       decChar = dec;
  63.    }
  64.    /**
  65.     * Set up ftp sockets and connect to an as400
  66.     */
  67.    public boolean connect(String host) {
  68.       connection   = null;
  69.       hostName = host.toUpperCase();
  70.       try {
  71.          printFTPInfo("Connecting to " + hostName);
  72.          Driver driver2 = (Driver)Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
  73.          DriverManager.registerDriver(driver2);
  74.          // Get a connection to the database.  Since we do not
  75.          // provide a user id or password, a prompt will appear.
  76.          // modified the connection string to add the translate binary = true
  77.          //   as suggested from Luca
  78.          connection = DriverManager.getConnection ("jdbc:as400://" + hostName +
  79.                                                    ";decimal separator=" +
  80.                                                    decChar +
  81.                                                 ";extended metadata=true;translate binary=true",
  82.                                                       user,pass);
  83.          printFTPInfo("jdbc:as400://" + hostName +
  84.                         ";decimal separator=" +
  85.                         decChar +
  86.                         ";extended metadata=true;translate binary=true");
  87.          fireInfoEvent();
  88.          printFTPInfo("Connected to " + hostName);
  89.          return true;
  90.       }
  91.       catch (NoClassDefFoundError ncdf) {
  92.          printFTPInfo("Error: JDBC Driver not found.  Please check classpath." );
  93.       }
  94.       catch (Exception e) {
  95. //         JOptionPane.showMessageDialog(this,
  96. //                           "Error: " + e.getMessage() + "nn" +
  97. //                           "There was an error connecting to host "
  98. //                           + system.toUpperCase() +
  99. //                           "nnPlease make sure that you run " +
  100. //                           "the command STRHOSTSVR",
  101. //                           "Host connection error",
  102. //                           JOptionPane.ERROR_MESSAGE);
  103.          printFTPInfo("Error: " + e.getMessage() + "nn" +
  104.                            "There was an error connecting to host "
  105.                            + host.toUpperCase() +
  106.                            "nnPlease make sure that you run " +
  107.                            "the command STRHOSTSVR");
  108.          System.out.println ( "Exception while retrieving data : " + e.getMessage());
  109.       }
  110.       return false;
  111.    }
  112.    /**
  113.     * Send quit command to ftp server and close connections
  114.     */
  115.    public void disconnect() {
  116. //      try {
  117. //         if (isConnected()) {
  118. //            executeCommand("QUIT");
  119. //            ftpOutputStream.close();
  120. //            ftpInputStream.close();
  121. //            ftpConnectionSocket.close();
  122. //            connected = false;
  123. //         }
  124. //      }
  125. //      catch(Exception _ex) { }
  126.    }
  127.    /**
  128.     * returns whether or not the system is connected to an AS400 or not
  129.     */
  130.    public boolean isConnected() {
  131.       return connected;
  132.    }
  133.    /**
  134.     * Add a FTPStatusListener to the listener list.
  135.     *
  136.     * @param listener  The FTPStatusListener to be added
  137.     */
  138.    public synchronized void addFTPStatusListener(FTPStatusListener listener) {
  139.       if (listeners == null) {
  140.           listeners = new java.util.Vector(3);
  141.       }
  142.       listeners.addElement(listener);
  143.    }
  144.    /**
  145.     * Notify all registered listeners of the FTPStatusEvent.
  146.     *
  147.     */
  148.    private void fireStatusEvent() {
  149.       if (listeners != null) {
  150.          int size = listeners.size();
  151.          for (int i = 0; i < size; i++) {
  152.             FTPStatusListener target =
  153.                     (FTPStatusListener)listeners.elementAt(i);
  154.             target.statusReceived(status);
  155.          }
  156.       }
  157.    }
  158.    /**
  159.     * Notify all registered listeners of the command status.
  160.     *
  161.     */
  162.    private void fireCommandEvent() {
  163.       if (listeners != null) {
  164.          int size = listeners.size();
  165.          for (int i = 0; i < size; i++) {
  166.             FTPStatusListener target =
  167.                     (FTPStatusListener)listeners.elementAt(i);
  168.             target.commandStatusReceived(status);
  169.          }
  170.       }
  171.    }
  172.    /**
  173.     * Notify all registered listeners of the file information status.
  174.     *
  175.     */
  176.    private void fireInfoEvent() {
  177.       if (listeners != null) {
  178.          int size = listeners.size();
  179.          for (int i = 0; i < size; i++) {
  180.             FTPStatusListener target =
  181.                     (FTPStatusListener)listeners.elementAt(i);
  182.             target.fileInfoReceived(status);
  183.          }
  184.       }
  185.    }
  186.    /**
  187.     * Remove a FTPStatusListener from the listener list.
  188.     *
  189.     * @param listener  The FTPStatusListener to be removed
  190.     */
  191.    public synchronized void removeFTPStatusListener(FTPStatusListener listener) {
  192.       if (listeners == null) {
  193.           return;
  194.       }
  195.       listeners.removeElement(listener);
  196.    }
  197.    /**
  198.     * Send the user id and password to the connected host
  199.     *
  200.     * @param user  The user name
  201.     * @param password  The password of the user
  202.     */
  203.    public boolean login(String user, String passWord) {
  204.       aborted = false;
  205.       loggedIn = true;
  206.       this.user = user;
  207.       this.pass = passWord;
  208.       return true;
  209.    }
  210.    /**
  211.     * Returns whether a field is selected for output or not
  212.     *
  213.     */
  214.    public boolean isFieldSelected(int which) {
  215.       FileFieldDef ffD = (FileFieldDef)ffd.get(which);
  216.       return ffD.isWriteField();
  217.    }
  218.    /**
  219.     * Select all the fields for output
  220.     */
  221.    protected void selectAll() {
  222.       FileFieldDef f;
  223.       for (int x = 0; x < ffd.size(); x++) {
  224.          f = (FileFieldDef)ffd.get(x);
  225.          f.setWriteField(true);
  226.       }
  227.    }
  228.    /**
  229.     * Unselect all fields for output.  This is a convenience method to unselect
  230.     * all fields for a file that will only need to output a couple of fields
  231.     */
  232.    protected void selectNone() {
  233.       FileFieldDef f;
  234.       for (int x = 0; x < ffd.size(); x++) {
  235.          f = (FileFieldDef)ffd.get(x);
  236.          f.setWriteField(false);
  237.       }
  238.    }
  239.    /**
  240.     * Returns whether there are any fields selected or not
  241.     */
  242.    public boolean isFieldsSelected() {
  243.       FileFieldDef f;
  244.       for (int x = 0; x < ffd.size(); x++) {
  245.          f = (FileFieldDef)ffd.get(x);
  246.          if (f.isWriteField())
  247.             return true;
  248.       }
  249.       return false;
  250.    }
  251.    /**
  252.     * Convenience method to select or unselect a field for output
  253.     */
  254.    public void setFieldSelected(int which,boolean value) {
  255.       FileFieldDef ffD = (FileFieldDef)ffd.get(which);
  256.       ffD.setWriteField(value);
  257.    }
  258.    /**
  259.     * Convenience method to return the name of a field
  260.     */
  261.    public String getFieldName(int which) {
  262.       FileFieldDef ffD = (FileFieldDef)ffd.get(which);
  263.       return ffD.getFieldName();
  264.    }
  265.    /**
  266.     * Returns the number of fields in the File Field Definition array of fields
  267.     * returned from the DSPFFD command
  268.     */
  269.    public int getNumberOfFields() {
  270.       return ffd.size();
  271.    }
  272.    /**
  273.     * Transfer the file information to an output file
  274.     */
  275.    public boolean getFile(String remoteFile, String localFile, String statement,
  276.                            boolean useInternal) {
  277.       boolean flag = true;
  278.       if(connection == null) {
  279.          printFTPInfo("Not connected to any server!");
  280.          return false;
  281.       }
  282.       final String localFileF = localFile;
  283.       final String remoteFileF = remoteFile;
  284.       final String query = statement;
  285.       final boolean internal = useInternal;
  286.       Runnable getRun = new Runnable () {
  287.             // set the thread to run.
  288.             public void run() {
  289.                try {
  290.                   DatabaseMetaData dmd = connection.getMetaData ();
  291.                   // Execute the query.
  292.                   Statement select = connection.createStatement ();
  293.                   ResultSet rs = select.executeQuery (query);
  294.                   ResultSetMetaData rsmd = rs.getMetaData();
  295.                   int numCols = rsmd.getColumnCount();
  296.                   ResultSet rsd = dmd.getColumns(null,"VISIONR","CXREF",null);
  297.                   while (rsd.next ()) {
  298.                      System.out.println(rsd.getString(12));
  299.                   }
  300.                   if (ffd != null) {
  301.                      ffd.clear();
  302.                      ffd = null;
  303.                   }
  304.                   ffd = new ArrayList();
  305.                   printFTPInfo("Number of columns: " + rsmd.getColumnCount());
  306.                   for (int x = 1; x <= numCols; x++) {
  307.                      printFTPInfo("Column " + x + ": " + rsmd.getColumnLabel(x) +
  308.                                                    " " + rsmd.getColumnName(x) +
  309.                                                    " " + rsmd.getColumnType(x) +
  310.                                                    " " + rsmd.getColumnTypeName(x) +
  311.                                                    " " + rsmd.getPrecision(x) +
  312.                                                    " " + rsmd.getScale(x) +
  313.                                                    " cn " + rsmd.getCatalogName(x) +
  314.                                                    " tn " + rsmd.getTableName(x) +
  315.                                                    " sn " + rsmd.getSchemaName(x));
  316.                         FileFieldDef ffDesc = new FileFieldDef(vt,decChar);
  317.                         if (internal)
  318.                            // WHFLDI  Field name internal
  319.                            ffDesc.setFieldName(rsmd.getColumnName(x) );
  320.                         else
  321.                            // WHFLD  Field name text description
  322.                            ffDesc.setFieldName(rsmd.getColumnLabel(x));
  323.                         ffDesc.setNeedsTranslation(false);
  324.                         // WHFOBO  Field starting offset
  325.                         ffDesc.setStartOffset("0");
  326.                         // WHFLDB  Field length
  327.                         ffDesc.setFieldLength(Integer.toString(rsmd.getColumnDisplaySize(x)));
  328.                         // WHFLDD  Number of digits
  329.                         ffDesc.setNumDigits(Integer.toString(rsmd.getPrecision(x)));
  330.                         // WHFLDP  Number of decimal positions
  331.                         ffDesc.setDecPositions(Integer.toString(rsmd.getScale(x)));
  332.                         // WHFLDT  Field type
  333.                         switch (rsmd.getColumnType(x)) {
  334.                            case 2:
  335.                               ffDesc.setFieldType("S");
  336.                               break;
  337.                            case 3:
  338.                               ffDesc.setFieldType("P");
  339.                               break;
  340.                            default:
  341.                               ffDesc.setFieldType(" ");
  342.                         }
  343.                         // WHFTXT  Text description
  344.                         ffDesc.setFieldText("");
  345.                         // set selected
  346.                         ffDesc.setWriteField(true);
  347.                         ffd.add(ffDesc);
  348.                   }
  349.                   writeHeader(localFileF);
  350.                   int processed = 0;
  351.                   // Iterate throught the rows in the result set and output
  352.                   // the columns for each row.
  353.                   StringBuffer rb = new StringBuffer();
  354.                   while (rs.next () && !aborted) {
  355.                      for (int x = 1; x <= numCols; x++) {
  356.                         ((FileFieldDef)ffd.get(x - 1)).setFieldData(rs.getString(x));
  357.                      }
  358.                      status.setCurrentRecord(processed++);
  359.                      status.setFileLength(processed + 1);
  360.                      rb.setLength(0);
  361.                      ofi.parseFields(null,ffd,rb);
  362.                      fireStatusEvent();
  363. //                     System.out.println(" record > " + processed);
  364.                   }
  365.                   printFTPInfo("Transfer Successful ");
  366.                   status.setCurrentRecord(processed);
  367.                   status.setFileLength(processed);
  368.                   fireStatusEvent();
  369.                   writeFooter();
  370.                }
  371.                catch(SQLException sqle) {
  372.                   printFTPInfo("SQL Exception ! " + sqle.getMessage());
  373.                }
  374. //               catch(InterruptedException iioe) {
  375. //                  printFTPInfo("Interrupted! " + iioe.getMessage());
  376. //               }
  377.                catch(FileNotFoundException fnfe) {
  378.                   printFTPInfo("File Not found Exception ! " + fnfe.getMessage());
  379.                }
  380. //               catch(Exception _ex) {
  381. //                  printFTPInfo("Error! " + _ex);
  382. //                  System.out.println(_ex.printStackTrace());
  383. //               }
  384.                finally {
  385.                   // Clean up.
  386.                   try {
  387.                       if (connection != null)
  388.                           connection.close ();
  389.                   }
  390.                   catch (SQLException e) {
  391.                       // Ignore.
  392.                   }
  393.                   if (ffd != null) {
  394.                      ffd.clear();
  395.                      ffd = null;
  396.                   }
  397.                   // Clean up the memory a little
  398.                   System.gc();
  399.                }
  400.             }
  401.          };
  402.       getThread = new Thread(getRun);
  403.       getThread.start();
  404.       return flag;
  405.    }
  406. //   private void loadFields() {
  407. //
  408. //
  409. //        ResultSet resultSet = null;
  410. //        try
  411. //        {
  412. //            // Get database meta data
  413. //            DatabaseMetaData metaData = connection_.getMetaData();
  414. //
  415. //            // Create new array to hold table values.
  416. //            data_ = new String[ROW_INCREMENT][NUM_COLUMNS_];
  417. //            types_ = new int[ROW_INCREMENT];
  418. //
  419. //            // Loop through each database file.
  420. //            String library, table, tprefix;
  421. //            int sepIndex;
  422. //            int curRow;
  423. //            for (int i=0; i<tables_.length; ++i)
  424. //            {
  425. //                // Get meta data.
  426. //                sepIndex = tables_[i].indexOf(".");
  427. //                if (sepIndex == -1)
  428. //                {
  429. //                    // Incorrect table specification, send error
  430. //                    // and continue to next table.
  431. //                    // Create generic exception to hold error message
  432. //                    Exception e = new Exception(ResourceLoader.getText("EXC_TABLE_SPEC_NOT_VALID"));
  433. //                    errorListeners_.fireError(e);
  434. //                }
  435. //                else
  436. //                {
  437. //                    library = tables_[i].substring(0, sepIndex);
  438. //                    table = tables_[i].substring(sepIndex+1);
  439. //                    if (tables_.length > 1)
  440. //                        tprefix = table + "."; // need to qualify field names
  441. //                    else
  442. //                        tprefix = "";  // only 1 table, can just use field names
  443. //
  444. //                    resultSet = metaData.getColumns(null, library, table, null);
  445. //
  446. //                    // Loop through fields for this database file.
  447. //                    while (resultSet.next())
  448. //                    {
  449. //                        curRow = numRows_; // current row in table
  450. //
  451. //                        // make sure we have room in table for this row.
  452. //                        if (curRow >= data_.length)                         // @D1C
  453. //                        {
  454. //                            String[][] newData =
  455. //                                new String[data_.length + ROW_INCREMENT][NUM_COLUMNS_];
  456. //                            System.arraycopy(data_, 0, newData, 0, data_.length);
  457. //                            data_ = newData;
  458. //                            int[] newTypes =
  459. //                                new int[types_.length + ROW_INCREMENT];
  460. //                            System.arraycopy(types_, 0, newTypes, 0, types_.length);
  461. //                            types_ = newTypes;
  462. //                        }
  463. //
  464. //                        // Store SQL type for use by getSQLType,
  465. //                        // although this is not externalized in the table.
  466. //                        types_[curRow] = resultSet.getInt(5);
  467. //
  468. //                        // Add field info to table
  469. //                        data_[curRow][FIELD_NAME_] = tprefix + resultSet.getString(4).trim();
  470. //                        data_[curRow][FIELD_TYPE_] = resultSet.getString(6);
  471. //                        // The following code should not be necessary when using
  472. //                        // most drivers, but makes the length values correct
  473. //                        // when using the AS400 JDBC driver.
  474. //                        // These values came from the ODBC description of precision
  475. //                        // (in 2.0 ref, Appendix D page 624).
  476. //                        switch (types_[curRow])
  477. //                        {
  478. //                            case Types.SMALLINT:
  479. //                                data_[curRow][FIELD_LENGTH_] = "5";
  480. //                                break;
  481. //                            case Types.INTEGER:
  482. //                                data_[curRow][FIELD_LENGTH_] = "10";
  483. //                                break;
  484. //                            case Types.TIME:
  485. //                                data_[curRow][FIELD_LENGTH_] = "8";
  486. //                                break;
  487. //                            case Types.TIMESTAMP:
  488. //                                // We always give length = 23, even though
  489. //                                // we should give 19 if there is no decimals.
  490. //                                // In order to not mess up 'correct' values,
  491. //                                // only change it if we know the value is bad.
  492. //                                if (resultSet.getInt(7) == 10)
  493. //                                    data_[curRow][FIELD_LENGTH_] = "23";
  494. //                                break;
  495. //                            case Types.DATE:
  496. //                                data_[curRow][FIELD_LENGTH_] = "10";
  497. //                                break;
  498. //                            case Types.DOUBLE:
  499. //                                if (resultSet.getInt(7) == 4)
  500. //                                    // single precision (type REAL)
  501. //                                    data_[curRow][FIELD_LENGTH_] = "7";
  502. //                                else
  503. //                                    // double precison (type FLOAT)
  504. //                                    data_[curRow][FIELD_LENGTH_] = "15";
  505. //                                break;
  506. //                            default:
  507. //                                // Other types are correct.
  508. //                                data_[curRow][FIELD_LENGTH_] = resultSet.getString(7);
  509. //                        }
  510. //                        data_[curRow][FIELD_DECIMALS_] = resultSet.getString(9);
  511. //                        data_[curRow][FIELD_NULLS_] = resultSet.getString(18);
  512. //                        data_[curRow][FIELD_DESC_] = resultSet.getString(12);
  513. //
  514. //                        numRows_++;
  515. //                    }
  516. //                }
  517. //            }
  518. //        }
  519. //        catch (SQLException e)
  520. //        {
  521. //            // In case of error, set fields to init state
  522. //            data_ = new String[0][0];
  523. //            types_ = new int[0];
  524. //            numRows_ = 0;
  525. //            errorListeners_.fireError(e);
  526. //            error_ = true;
  527. //        }
  528. //        finally
  529. //        {
  530. //            if (resultSet != null)
  531. //            {
  532. //                try
  533. //                {
  534. //                    resultSet.close();
  535. //                }
  536. //                catch(SQLException e)
  537. //                {
  538. //                    errorListeners_.fireError(e);
  539. //                }
  540. //            }
  541. //        }
  542. //
  543. //
  544. //   }
  545.    /**
  546.     * Parse the field field definition of the data and return a string buffer of
  547.     * the output to be written
  548.     */
  549.    private void parseFFD(byte[] cByte,StringBuffer rb) {
  550.       ofi.parseFields(cByte,ffd,rb);
  551.    }
  552.    /**
  553.     * Abort the current file transfer
  554.     */
  555.    public void setAborted() {
  556.       aborted = true;
  557.    }
  558.    /**
  559.     * Print ftp command events and responses
  560.     */
  561.    private void printFTPInfo(String msgText) {
  562.       status.setMessage(msgText);
  563.       fireCommandEvent();
  564.    }
  565.    /**
  566.     * Write the html header of the output file
  567.     */
  568.    private void writeHeader(String fileName) throws
  569.                            FileNotFoundException {
  570.       ofi.createFileInstance(fileName);
  571.       ofi.writeHeader(fileName,hostName,ffd,decChar);
  572.    }
  573.    /**
  574.     * write the footer of the html output
  575.     */
  576.    private void writeFooter() {
  577.       ofi.writeFooter(ffd);
  578.    }
  579.    /**
  580.     * Convert an as400 packed field to an integer
  581.     */
  582.    private int packed2int(byte[] cByte,int startOffset, int length) {
  583.       StringBuffer sb = new StringBuffer();
  584.       int end = startOffset + length - 1;
  585.       // example field of buffer length 4 with decimal precision 0
  586.       //    output length is (4 * 2) -1 = 7
  587.       //
  588.       //    each byte of the buffer contains 2 digits, one in the zone
  589.       //    portion and one in the zone portion of the byte, the last
  590.       //    byte of the field contains the last digit in the ZONE
  591.       //    portion and the sign is contained in the DIGIT portion.
  592.       //
  593.       //    The number 1234567 would be represented as follows:
  594.       //    byte 1 of 4 -> 12
  595.       //    byte 2 of 4 -> 34
  596.       //    byte 3 of 4 -> 56
  597.       //    byte 4 of 4 -> 7F    The F siginifies a positive number
  598.       //
  599.       //    The number -1234567 would be represented as follows:
  600.       //    byte 1 of 4 -> 12
  601.       //    byte 2 of 4 -> 34
  602.       //    byte 3 of 4 -> 56
  603.       //    byte 4 of 4 -> 7D    The D siginifies a negative number
  604.       //
  605.       for (int f = startOffset-1;f < end -1; f++) {
  606.          byte bzd = cByte[f];
  607.          int byteZ = (bzd >> 4) & 0x0f ;  // get the zone portion
  608.          int byteD = (bzd & 0x0f);        // get the digit portion
  609.          sb.append(byteZ); // assign the zone portion as the first digit
  610.          sb.append(byteD); // assign the digit portion as the second digit
  611.       }
  612.       // here we obtain the last byte to determine the sign of the field
  613.       byte bzd = cByte[end-1];
  614.       int byteZ = (bzd >> 4) & 0x0f ;  // get the zone portion
  615.       int byteD = (bzd & 0x0f);        // get the digit portion
  616.       sb.append(byteZ);                // append the zone portion as the
  617.                                        // the last digit of the number
  618.       // convert to integer
  619.       int p2i = Integer.parseInt(sb.toString());
  620.       // Here we interrogate the the DIGIT portion for the sign
  621.       //    0x0f = positive   -> 0x0f | 0x0d = 0x0f
  622.       //    0x0d = negative   -> 0x0d | 0x0d = 0x0d
  623.       if ((byteD | 0x0d) == 0x0d)
  624.          p2i *= -1;
  625.       return p2i;
  626.    }
  627. }