docs: def read_config_file(filename):
      """Reads the configuration file.
  
      :param filename: the name of the file containing the configuration.
  
      :type filename: str
  
      :returns: A tuple where the first element is a list of sections, and the
                second element is a map containing the configuration (options and
                values).
  
      The structure of the configuration file is important. Here is an example of
      a configuration file::
  
          [1] # Computes statistics on duplicated samples
          script = duplicated_samples
  
          [2] # Removes samples according to missingness
          script = sample_missingness
  
          [3] # Removes markers according to missingness
          script = snp_missingness
  
          [4] # Removes samples according to missingness (98%)
          script = sample_missingness
          mind = 0.02
  
          [5] # Performs a sex check
          script = sex_check
  
          [6] # Flags markers with MAF=0
          script = flag_maf_zero
  
          [7] # Flags markers according to Hardy Weinberg
          script = flag_hw
  
          [8] # Subset the dataset (excludes markers and remove samples)
          script = subset
          exclude = .../filename
          rempove = .../filename
  
      Sections are in square brackets and must be ``integer``. The section number
      represent the step at which the script will be run (*i.e.* from the
      smallest number to the biggest). The sections must be continuous.
  
      Each section contains the script names (``script`` variable) and options of
      the script (all other variables) (*e.g.* section 4 runs the
      ``sample_missingness`` script (:py:func:`run_sample_missingness`) with
      option ``mind`` sets to 0.02).
  
      Here is a list of the available scripts:
  
      * ``duplicated_samples`` (:py:func:`run_duplicated_samples`)
      * ``duplicated_snps`` (:py:func:`run_duplicated_snps`)
      * ``noCall_hetero_snps`` (:py:func:`run_noCall_hetero_snps`)
      * ``sample_missingness`` (:py:func:`run_sample_missingness`)
      * ``snp_missingness`` (:py:func:`run_snp_missingness`)
      * ``sex_check`` (:py:func:`run_sex_check`)
      * ``plate_bias`` (:py:func:`run_plate_bias`)
      * ``contamination`` (:py:func:`run_contamination`)
      * ``remove_heterozygous_haploid``
        (:py:func:`run_remove_heterozygous_haploid`)
      * ``find_related_samples`` (:py:func:`run_find_related_samples`)
      * ``check_ethnicity`` (:py:func:`run_check_ethnicity`)
      * ``flag_maf_zero`` (:py:func:`run_flag_maf_zero`)
      * ``flag_hw`` (:py:func:`run_flag_hw`)
      * ``subset`` (:py:func:`run_subset_data`)
      * ``compare_gold_standard`` (:py:func:`run_compare_gold_standard`)
  
      """
      # Creating the config parser
      config = ConfigParser.RawConfigParser(allow_no_value=True)
      config.optionxform = str
      config.read(filename)
  
      # Checking the section names
      sections = None
      try:
          sections = sorted([int(i) for i in config.sections()])
      except ValueError:
          # Section not integer
          msg = ("{}: sections must be integers: "
                 "{}".format(filename, config.sections()))
          raise ProgramError(msg)
      if sections != range(min(sections), max(sections)+1):
          # Missing a section
          msg = "{}: maybe a section is missing: {}".format(filename, sections)
          raise ProgramError(msg)
      sections = [str(i) for i in sections]
  
      # Reading the configuration for each sections
      configuration = {}
      for section in sections:
          # Getting the script variable (and check it)
          script_name = None
          try:
              script_name = config.get(section, "script")
          except ConfigParser.NoOptionError:
              msg = ("{}: section {}: no variable called 'script'".format(
                  filename,
                  section,
              ))
              raise ProgramError(msg)
          if script_name not in available_modules:
              msg = ("{}: section {}: script {}: invalid script name".format(
                  filename,
                  section,
                  script_name,
              ))
              raise ProgramError(msg)
  
          # Getting the variables
          options = []
          for variable_name, variable_value in config.items(section):
              unwanted_options = {"bfile", "tfile", "file", "out"}
              if script_name in {"sample_missingness", "subset"}:
                  unwanted_options |= {"ifile", "is-bfile", "is-tfile"}
              if script_name == "subset":
                  unwanted_options.add("is-file")
              for unwanted in unwanted_options:
                  if variable_name == unwanted:
                      msg = ("{}: section {}: do not use {} as an option for "
                             "{}".format(filename, section, unwanted,
                                         script_name))
                      raise ProgramError(msg)
              if variable_name != "script":
                  options.append("--" + variable_name)
                  if variable_value is not None:
                      if variable_name in {"indep-pairwise", "sge-nodes",
                                           "ibs-sge-nodes"}:
                          # This is a special option
                          options.extend(variable_value.split(" "))
                      else:
                          options.append(variable_value)
  
          # Saving the configuration
          configuration[section] = (script_name, options)
  
      return sections, configuration