grib/src/main/java/ucar/nc2/grib/grib1/tables/Grib1ParamTableReader.java
private Map<Integer, Grib1Parameter> readParameterTableEcmwfEcCodes() throws IOException {
    HashMap<Integer, Grib1Parameter> result = new HashMap<>();

    try (InputStream is = GribResourceReader.getInputStream(path);
      BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
      String line = br.readLine();
      if (line == null) {
        throw new FileNotFoundException(path + " is empty");
      }

      // create table name from file name
      String[] splitPath = path.split("/");
      String tableNum = splitPath[splitPath.length - 1].replace(".table", "");
      this.desc = "ECMWF GRIB API TABLE " + tableNum;

      // skip header
      while (line != null && !line.startsWith("#")) {
        line = br.readLine(); // skip
      }

      // keep going until the end of the file is reached (line == null)
      while (true) {
        // exmaple: 251 atte [Adiabatic tendency of temperature] (K)
        line = br.readLine();
        if (line == null) {
          break; // done with the file
        }
        if ((line.length() == 0) || line.startsWith("#")) {
          continue;
        }

        // get unit - (K)
        String[] tmpUnitArray = line.split("\\(");
        String tmpUnit = tmpUnitArray[tmpUnitArray.length - 1];
        int lastUnitIndex;
        while ((lastUnitIndex = tmpUnit.lastIndexOf(")")) > 0) {
          tmpUnit = tmpUnit.substring(0, lastUnitIndex).trim();
        }
        String unit = tmpUnit.trim();
        // unit = Util.cleanUnit(unit); // fixes some common unit mistakes  // jcaron - just use unit as it is

        // get parameter number - 251
        String[] lineArray = line.trim().split("\\s+"); // all and any white space
        String num = lineArray[0];

        // get shortName - atte
        String name = lineArray[1].trim();
        //if (name.equals("~")) {}; - todo create name from long name(?)

        // get description. bracketed by [] - [Adiabatic Tendency of temperature]
        int startDesc = line.indexOf("[");
        int endDesc = line.indexOf("]");
        String desc = line.substring(startDesc, endDesc).trim();

        // stuff information into a Grib1Parameter object
        int p1;
        try {
          p1 = Integer.parseInt(num);
        } catch (Exception e) {
          logger.warn("Cant parse " + num + " in file " + path);
          continue;
        }
        Grib1Parameter parameter = new Grib1Parameter(this, p1, name, desc, unit);
        result.put(parameter.getNumber(), parameter);
        logger.debug(" %s%n", parameter);
      }

      return Collections.unmodifiableMap(result);  // all at once - thread safe
    }
  }
private Map<Integer, Grib1Parameter> readParameterTableEcmwfEcCodes() throws IOException {
    HashMap<Integer, Grib1Parameter> result = new HashMap<>();

    try (InputStream is = GribResourceReader.getInputStream(path);
      BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
      String line = br.readLine();
      if (line == null) {
        throw new FileNotFoundException(path + " is empty");
      }

      // create table name from file name
      String[] splitPath = path.split("/");
      String tableNum = splitPath[splitPath.length - 1].replace(".table", "");
      this.desc = "ECMWF GRIB API TABLE " + tableNum;

      // skip header
      while (line != null && !line.startsWith("#")) {
        line = br.readLine(); // skip
      }

      // keep going until the end of the file is reached (line == null)
      while (true) {
        // exmaple: 251 atte [Adiabatic tendency of temperature] (K)
        line = br.readLine();
        if (line == null) {
          break; // done with the file
        }
        if ((line.length() == 0) || line.startsWith("#")) {
          continue;
        }

        // get unit - (K)
        String[] tmpUnitArray = line.split("\\(");
        String tmpUnit = tmpUnitArray[tmpUnitArray.length - 1];
        int lastUnitIndex;
        while ((lastUnitIndex = tmpUnit.lastIndexOf(")")) > 0) {
          tmpUnit = tmpUnit.substring(0, lastUnitIndex).trim();
        }
        String unit = tmpUnit.trim();
        // unit = Util.cleanUnit(unit); // fixes some common unit mistakes  // jcaron - just use unit as it is

        // get parameter number - 251
        String[] lineArray = line.trim().split("\\s+"); // all and any white space
        String num = lineArray[0];

        // get shortName - atte
        String name = lineArray[1].trim();
        //if (name.equals("~")) {}; - todo create name from long name(?)

        // get description. bracketed by [] - [Adiabatic Tendency of temperature]
        int startDesc = line.indexOf("[");
        int endDesc = line.indexOf("]");
        String desc = line.substring(startDesc, endDesc).trim();

        // stuff information into a Grib1Parameter object
        int p1;
        try {
          p1 = Integer.parseInt(num);
        } catch (Exception e) {
          logger.warn("Cant parse " + num + " in file " + path);
          continue;
        }
        Grib1Parameter parameter = new Grib1Parameter(this, p1, name, desc, unit);
        result.put(parameter.getNumber(), parameter);
        logger.debug(" %s%n", parameter);
      }

      return Collections.unmodifiableMap(result);  // all at once - thread safe
    }
  }
This method will read in ECMWF grib1 tables. Note that these tables are generated locally by
Unidata, and come directly from the ECMWF GRIB-API package localConcepts files. They are
generated by:
<p>
ucar.nc2.grib.grib1.tables.EcmwfLocalConcepts
<p>
The original localConcepts files are located in:
<p/>
grib/src/main/sources/ecmwfEcCodes/
<p/>
Since we write the table file that are ultimately read by CDM, the format is controled and is
the following:
<p>
paramNum shortName [description] (units)
<p>
for example,
<p>
251 atte [Adiabatic tendency of temperature] (K)