org.renjin.primitives.io.DebianControlFiles.java Source code

Java tutorial

Introduction

Here is the source code for org.renjin.primitives.io.DebianControlFiles.java

Source

package org.renjin.primitives.io;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.renjin.eval.Context;
import org.renjin.eval.EvalException;
import org.renjin.invoke.annotations.Current;
import org.renjin.invoke.annotations.Builtin;
import org.renjin.invoke.annotations.Internal;
import org.renjin.primitives.io.connections.Connections;
import org.renjin.primitives.io.connections.PushbackBufferedReader;
import org.renjin.primitives.matrix.StringMatrixBuilder;
import org.renjin.sexp.SEXP;
import org.renjin.sexp.StringVector;
import org.renjin.sexp.Vector;

import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * Primitives for reading Debian Control Files (DCF), which are used to store
 * the package descriptions and the license files.
 *
 */
public class DebianControlFiles {

    private static class Cell {

        private int row;
        private String field;

        public Cell(int row, String column) {
            super();
            this.row = row;
            this.field = column;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + field.hashCode();
            result = prime * result + row;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            Cell other = (Cell) obj;
            return row == other.row && field.equals(other.field);
        }
    }

    /**
     * Internal primitive used by the read.dcf() function in the base library.
     * 
     * @param conn
     * @param fields a list of fields to return or NULL for all fields 
     * @param keepWhiteSpace
     * @return
     * @throws IOException
     */
    @Internal
    public static SEXP readDCF(@Current Context context, SEXP conn, Vector requestedFields, boolean keepWhiteSpace)
            throws IOException {

        Map<Cell, String> cells = Maps.newHashMap();
        List<String> fields = Lists.newArrayList();

        // if specific fields are requested, the fields parameter
        // dictates the order
        boolean allFields = true;
        if (requestedFields instanceof StringVector) {
            Iterables.addAll(fields, (StringVector) requestedFields);
            allFields = false;
        }

        int rowIndex = 0;
        boolean lastLineWasBlank = false;
        String line;
        PushbackBufferedReader reader = Connections.getConnection(context, conn).getReader();
        Cell lastCell = null;
        while ((line = reader.readLine()) != null) {
            boolean lineIsBlank = line.trim().length() == 0;
            if (lineIsBlank) {
                if (!lastLineWasBlank) {
                    rowIndex++;
                }
                lastCell = null;

            } else if (isContinuation(line)) {
                if (lastCell == null) {
                    throw new EvalException("Malformed DCF exception '%s'", line);
                } else {
                    StringBuilder value = new StringBuilder();
                    value.append(cells.get(lastCell));
                    value.append(" ");
                    value.append(line.trim());
                    cells.put(lastCell, value.toString());
                }
            } else {
                String[] fieldValue = parseLine(line);
                String fieldName = fieldValue[0];

                boolean includeValue = false;
                if (fields.contains(fieldName)) {
                    includeValue = true;
                } else if (allFields) {
                    fields.add(fieldName);
                    includeValue = true;
                }
                Cell cell = new Cell(rowIndex, fieldName);
                if (includeValue) {
                    cells.put(cell, fieldValue[1]);
                }
                lastCell = cell;
            }
            lastLineWasBlank = lineIsBlank;
        }
        int numRows = rowIndex;
        if (!lastLineWasBlank) {
            numRows++;
        }
        return constructMatrix(numRows, cells, fields);
    }

    protected static SEXP constructMatrix(int numRows, Map<Cell, String> cells, List<String> fields) {
        StringMatrixBuilder matrix = new StringMatrixBuilder(numRows, fields.size());
        for (int row = 0; row != numRows; ++row) {
            for (int col = 0; col != fields.size(); ++col) {
                String value = cells.get(new Cell(row, fields.get(col)));
                matrix.setValue(row, col, value);
            }
        }
        matrix.setColNames(fields);
        return matrix.build();
    }

    private static boolean isContinuation(String line) {
        return Character.isWhitespace(line.charAt(0));
    }

    private static String[] parseLine(String line) {
        int colon = line.indexOf(':');
        if (colon == -1) {
            throw new EvalException("Malformed DCF line: '" + line + "'");
        }
        String fieldName = line.substring(0, colon).trim();
        String value = line.substring(colon + 1).trim();
        return new String[] { fieldName, value };
    }

}