Module ini + ajout de convert.ToInteger
This commit is contained in:
		
							parent
							
								
									6637db7be4
								
							
						
					
					
						commit
						0a1722dd44
					
				
					 2 changed files with 244 additions and 0 deletions
				
			
		| 
						 | 
					@ -641,6 +641,10 @@ func ToUint[T UintType](src any, def ...T) T {
 | 
				
			||||||
	return toSingle(src, def...)
 | 
						return toSingle(src, def...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToInteger[T IntegerType](src any, def ...T) T {
 | 
				
			||||||
 | 
						return toSingle(src, def...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ToFloat[T FloatType](src any, def ...T) T {
 | 
					func ToFloat[T FloatType](src any, def ...T) T {
 | 
				
			||||||
	return toSingle(src, def...)
 | 
						return toSingle(src, def...)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										240
									
								
								ini/ini.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								ini/ini.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,240 @@
 | 
				
			||||||
 | 
					package ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bufio"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"gitea.zaclys.com/bvaudour/gob/convert"
 | 
				
			||||||
 | 
						. "gitea.zaclys.com/bvaudour/gob/option"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Setting représente le contenu d’un fichier de configuration de la forme .ini.
 | 
				
			||||||
 | 
					Un fichier .ini a la forme suivante :
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[section1]
 | 
				
			||||||
 | 
						clé1 = valeur
 | 
				
			||||||
 | 
						clé2 = valeur
 | 
				
			||||||
 | 
						; un commentaire éventuel
 | 
				
			||||||
 | 
						#un autre commentaire
 | 
				
			||||||
 | 
						[section2]
 | 
				
			||||||
 | 
						clé1 = valeur
 | 
				
			||||||
 | 
						<...>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					L’accès aux clés de la configuration se fait en préfixant la clé souhaitée par la section
 | 
				
			||||||
 | 
					d’appartenance suivie d’un point (exemple : section1.clé1).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Les types de valeurs supportées actuellement sont :
 | 
				
			||||||
 | 
					- les chaînes de caractère
 | 
				
			||||||
 | 
					- les booléens : 0, 1, true, false
 | 
				
			||||||
 | 
					- les entiers
 | 
				
			||||||
 | 
					- les tableaux de chaînes : ce sont des chaînes séparées par des virgules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					La conversion entre ces différents types se fait sans panic et aucun contrôle n’est effectué sur la cohérence des données.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					type Setting struct {
 | 
				
			||||||
 | 
						t []string
 | 
				
			||||||
 | 
						m map[string]string
 | 
				
			||||||
 | 
						i map[string]int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// New crée une nouvelle configuration à partir d’un template.
 | 
				
			||||||
 | 
					// Le template doit avoir la structure d’un fichier .ini.
 | 
				
			||||||
 | 
					func New(template string) *Setting {
 | 
				
			||||||
 | 
						c := &Setting{
 | 
				
			||||||
 | 
							m: make(map[string]string),
 | 
				
			||||||
 | 
							i: make(map[string]int),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b := bufio.NewScanner(strings.NewReader(template))
 | 
				
			||||||
 | 
						var section string
 | 
				
			||||||
 | 
						i := -1
 | 
				
			||||||
 | 
						for b.Scan() {
 | 
				
			||||||
 | 
							i++
 | 
				
			||||||
 | 
							line := b.Text()
 | 
				
			||||||
 | 
							c.t = append(c.t, line)
 | 
				
			||||||
 | 
							line = strings.TrimSpace(line)
 | 
				
			||||||
 | 
							l := len(line)
 | 
				
			||||||
 | 
							// Line is comment or blank line
 | 
				
			||||||
 | 
							if l == 0 || line[0] == '#' || line[0] == ';' {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// line is section header
 | 
				
			||||||
 | 
							if line[0] == '[' && line[l-1] == ']' {
 | 
				
			||||||
 | 
								section = line[1 : l-1]
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if idx := strings.Index(line, "="); idx > 0 {
 | 
				
			||||||
 | 
								key, value := strings.TrimSpace(line[:idx]), strings.TrimSpace(line[idx+1:])
 | 
				
			||||||
 | 
								k := section + "." + key
 | 
				
			||||||
 | 
								c.m[k] = value
 | 
				
			||||||
 | 
								c.i[k] = i
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return c
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Keys retourne la liste des clés de la configuration.
 | 
				
			||||||
 | 
					// Chaque clé est des la forme section.clé.
 | 
				
			||||||
 | 
					func (c *Setting) Keys() []string {
 | 
				
			||||||
 | 
						out := make([]string, 0, len(c.i))
 | 
				
			||||||
 | 
						for i := range c.i {
 | 
				
			||||||
 | 
							out = append(out, i)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sort.Slice(out, func(i, j int) bool {
 | 
				
			||||||
 | 
							return c.i[out[i]] < c.i[out[j]]
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return out
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Position retourne le numéro de ligne dans laquelle se trouve la clé donnée.
 | 
				
			||||||
 | 
					// Les n° de ligne commencent à partir de 0.
 | 
				
			||||||
 | 
					func (c *Setting) Position(key string) (position Option[int]) {
 | 
				
			||||||
 | 
						if p, ok := c.i[key]; ok {
 | 
				
			||||||
 | 
							position = Some(p)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func conv(e any) string {
 | 
				
			||||||
 | 
						var s string
 | 
				
			||||||
 | 
						t := convert.TypeOf(e)
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case t.Is(convert.Bool):
 | 
				
			||||||
 | 
							s = "0"
 | 
				
			||||||
 | 
							if b := convert.ToBool(e, false); b {
 | 
				
			||||||
 | 
								s = "1"
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case t.Is(convert.Slice):
 | 
				
			||||||
 | 
							a := convert.ToSlice[string](e)
 | 
				
			||||||
 | 
							s = strings.Join(a, ",")
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							s = convert.ToString(e, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Set définit la clé key à la valeur value.
 | 
				
			||||||
 | 
					// Si la clé n’existe pas, aucune modification n’est effectuée et la méthode retourne false.
 | 
				
			||||||
 | 
					func (c *Setting) Set(key string, value any) (ok bool) {
 | 
				
			||||||
 | 
						if _, ok = c.m[key]; ok {
 | 
				
			||||||
 | 
							c.m[key] = conv(value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Get retourne la valeur de la clé demandée.
 | 
				
			||||||
 | 
					// Si celle-ci n’existe pas, une chaîne vide est retournée.
 | 
				
			||||||
 | 
					func (c *Setting) Get(key string) string { return c.m[key] }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetBool retourne la valeur de la clé demandée, convertie en booléen.
 | 
				
			||||||
 | 
					func (c *Setting) GetBool(key string) (out bool) {
 | 
				
			||||||
 | 
						out = convert.ToBool(c.Get(key), false)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetInt retourne la valeur de la clé demandée, convertie en entier.
 | 
				
			||||||
 | 
					func (c *Setting) GetInt(key string) (out int) {
 | 
				
			||||||
 | 
						out = convert.ToInt(c.Get(key), 0)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetUint retourne la valeur de la clé demandée, convertie en entier non signé.
 | 
				
			||||||
 | 
					func (c *Setting) GetUint(key string) (out uint) {
 | 
				
			||||||
 | 
						out = convert.ToUint(c.Get(key), uint(0))
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetSlice retourne la valeur de la clé demandée, convertie en slice.
 | 
				
			||||||
 | 
					func (c *Setting) GetSlice(key string) (out []string) {
 | 
				
			||||||
 | 
						v := c.Get(key)
 | 
				
			||||||
 | 
						if len(v) > 0 {
 | 
				
			||||||
 | 
							out = strings.Split(v, ",")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Read parse la configuration du descripteur d’entrée.
 | 
				
			||||||
 | 
					func (c *Setting) Read(r io.Reader) {
 | 
				
			||||||
 | 
						b := bufio.NewScanner(r)
 | 
				
			||||||
 | 
						var section string
 | 
				
			||||||
 | 
						for b.Scan() {
 | 
				
			||||||
 | 
							line := b.Text()
 | 
				
			||||||
 | 
							line = strings.TrimSpace(line)
 | 
				
			||||||
 | 
							l := len(line)
 | 
				
			||||||
 | 
							// Line is comment or blank line
 | 
				
			||||||
 | 
							if l == 0 || line[0] == '#' || line[0] == ';' {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// line is section header
 | 
				
			||||||
 | 
							if line[0] == '[' && line[l-1] == ']' {
 | 
				
			||||||
 | 
								section = line[1 : l-1]
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if i := strings.Index(line, "="); i > 0 && i < l-1 {
 | 
				
			||||||
 | 
								key, value := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
 | 
				
			||||||
 | 
								k := section + "." + key
 | 
				
			||||||
 | 
								c.m[k] = value
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Write écrit la configuration dans le descripteur de sortie.
 | 
				
			||||||
 | 
					func (c *Setting) Write(w io.Writer) error {
 | 
				
			||||||
 | 
						for k, v := range c.m {
 | 
				
			||||||
 | 
							l := c.t[c.i[k]]
 | 
				
			||||||
 | 
							i := strings.Index(l, "=")
 | 
				
			||||||
 | 
							c.t[c.i[k]] = l[:i+1] + " " + v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						buf := bufio.NewWriter(w)
 | 
				
			||||||
 | 
						for _, l := range c.t {
 | 
				
			||||||
 | 
							if _, err := buf.WriteString(l + "\n"); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return buf.Flush()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IniFile représente un fichier de configuration.
 | 
				
			||||||
 | 
					type IniFile struct {
 | 
				
			||||||
 | 
						*Setting
 | 
				
			||||||
 | 
						Path string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewFile génère un nouveau fichier de de configuration.
 | 
				
			||||||
 | 
					// Rien n’est inscrit sur le chemin donné et cela reste en mémoire
 | 
				
			||||||
 | 
					// tant que la méthode Save n’est pas appelée explicitement.
 | 
				
			||||||
 | 
					// Par ailleurs, le fichier dans le filepath n’est pas parsé
 | 
				
			||||||
 | 
					// tant que la méthode Load n’est pas appelée explicitement.
 | 
				
			||||||
 | 
					func NewFile(template, filepath string) *IniFile {
 | 
				
			||||||
 | 
						return &IniFile{
 | 
				
			||||||
 | 
							Setting: New(template),
 | 
				
			||||||
 | 
							Path:    filepath,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Load charge la configuration
 | 
				
			||||||
 | 
					func (cf *IniFile) Load() error {
 | 
				
			||||||
 | 
						f, err := os.Open(cf.Path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer f.Close()
 | 
				
			||||||
 | 
						cf.Setting.Read(f)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Save enregistre la configuration sur le disque.
 | 
				
			||||||
 | 
					func (cf *IniFile) Save() error {
 | 
				
			||||||
 | 
						f, err := os.Create(cf.Path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer f.Close()
 | 
				
			||||||
 | 
						return cf.Setting.Write(f)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue