config_unix.go raw

   1  //go:build aix || dragonfly || freebsd || (js && wasm) || nacl || linux || netbsd || openbsd || solaris
   2  
   3  package userdirs
   4  
   5  import (
   6  	"bufio"
   7  	"io"
   8  	"os"
   9  	"strings"
  10  
  11  	"github.com/adrg/xdg/internal/pathutil"
  12  )
  13  
  14  // ParseConfigFile parses the user directories config file at the
  15  // specified location.
  16  func ParseConfigFile(name string) (*Directories, error) {
  17  	f, err := os.Open(name)
  18  	if err != nil {
  19  		return nil, err
  20  	}
  21  	defer f.Close()
  22  
  23  	return ParseConfig(f)
  24  }
  25  
  26  // ParseConfig parses the user directories config file contained in
  27  // the provided reader.
  28  func ParseConfig(r io.Reader) (*Directories, error) {
  29  	dirs := &Directories{}
  30  	fieldsMap := map[string]*string{
  31  		EnvDesktopDir:     &dirs.Desktop,
  32  		EnvDownloadDir:    &dirs.Download,
  33  		EnvDocumentsDir:   &dirs.Documents,
  34  		EnvMusicDir:       &dirs.Music,
  35  		EnvPicturesDir:    &dirs.Pictures,
  36  		EnvVideosDir:      &dirs.Videos,
  37  		EnvTemplatesDir:   &dirs.Templates,
  38  		EnvPublicShareDir: &dirs.PublicShare,
  39  	}
  40  
  41  	scanner := bufio.NewScanner(r)
  42  	for scanner.Scan() {
  43  		line := strings.TrimSpace(scanner.Text())
  44  		if len(line) == 0 || line[0] == '#' {
  45  			continue
  46  		}
  47  		if !strings.HasPrefix(line, "XDG_") {
  48  			continue
  49  		}
  50  
  51  		parts := strings.Split(line, "=")
  52  		if len(parts) < 2 {
  53  			continue
  54  		}
  55  
  56  		// Parse key.
  57  		field, ok := fieldsMap[strings.TrimSpace(parts[0])]
  58  		if !ok {
  59  			continue
  60  		}
  61  
  62  		// Parse value.
  63  		runes := []rune(strings.TrimSpace(parts[1]))
  64  
  65  		lenRunes := len(runes)
  66  		if lenRunes <= 2 || runes[0] != '"' {
  67  			continue
  68  		}
  69  
  70  		for i := 1; i < lenRunes; i++ {
  71  			if runes[i] == '"' {
  72  				*field = pathutil.ExpandHome(string(runes[1:i]))
  73  				break
  74  			}
  75  		}
  76  	}
  77  	if err := scanner.Err(); err != nil {
  78  		return nil, err
  79  	}
  80  
  81  	return dirs, nil
  82  }
  83