Lindenii Project Forge
Login

go-lindenii-common

Common library for the Lindenii Project
Commit info
ID
b626ea8beb4bc1eef134a990eb1a7361c1c126b1
Author
Runxi Yu <me@runxiyu.org>
Author date
Mon, 13 Jan 2025 14:12:37 +0800
Committer
Runxi Yu <me@runxiyu.org>
Committer date
Mon, 13 Jan 2025 14:12:37 +0800
Actions
Reformat code
package misc

import (
	"os"
	"errors"
	"os"
	"path"
	"strings"
	"syscall"
	"path"
)

type Dir_t struct {
	fd int
	fd   int
	name string
}

var (
	Err_illegal_filename = errors.New("illegal filename")
	Err_illegal_filename        = errors.New("illegal filename")
	Err_invalid_file_descriptor = errors.New("invalid file descriptor")
)

// Open a file at exactly the given directory.
func Open_file_at(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) {
	if strings.IndexByte(filename, '/') != -1 {
		return nil, Err_illegal_filename
	}
	return Open_file_beneath(dir, filename, flags, perms)
}

// Open a file at or beneath the given directory.
func Open_file_beneath(dir Dir_t, filename string, flags int, perms os.FileMode) (*os.File, error) {
	fd, err := Openat2(dir.fd, filename, &Open_how_t{
		Flags: uint64(flags)|syscall.O_CLOEXEC,
		Mode: uint64(syscallMode(perms)),
		Resolve: RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS,
		Flags:   uint64(flags) | syscall.O_CLOEXEC,
		Mode:    uint64(syscallMode(perms)),
		Resolve: RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS,
	})
	if err != nil {
		return nil, err
	}
	file := os.NewFile(uintptr(fd), path.Join(dir.name, filename))
	if file == nil {
		return nil, Err_invalid_file_descriptor
	} else {
		return file, nil
	}
}

// Open a directory as read-only and return a Dir_t to it. The caller is
// responsible for closing the directory with [Close_directory].
func Open_directory_readonly(path string) (Dir_t, error) {
	_fd, err := syscall.Open(path, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_CLOEXEC, 0)
	return Dir_t{fd: _fd, name: path}, err
}

// Close a directory returned by [Open_directory_readonly].
func (dir *Dir_t) Close() error {
	return syscall.Close(dir.fd)
}

// syscallMode returns the syscall-specific mode flags from Go's portable mode flags.
func syscallMode(i os.FileMode) (o uint32) {
	// This part actually came from Go's os/file_posix.go but IMO it's too
	// small and should fall under fair use.
	o |= uint32(i.Perm())
	if i&os.ModeSetuid != 0 {
		o |= syscall.S_ISUID
	}
	if i&os.ModeSetgid != 0 {
		o |= syscall.S_ISGID
	}
	if i&os.ModeSticky != 0 {
		o |= syscall.S_ISVTX
	}
	// No mapping for Go's ModeTemporary (plan9 only).
	return
}
package scfg

import (
	"errors"
	"io"
	"strings"
)

var (
	errDirEmptyName = errors.New("scfg: directive with empty name")
)
var errDirEmptyName = errors.New("scfg: directive with empty name")

// Write writes a parsed configuration to the provided io.Writer.
func Write(w io.Writer, blk Block) error {
	enc := newEncoder(w)
	err := enc.encodeBlock(blk)
	return err
}

// encoder write SCFG directives to an output stream.
type encoder struct {
	w   io.Writer
	lvl int
	err error
}

// newEncoder returns a new encoder that writes to w.
func newEncoder(w io.Writer) *encoder {
	return &encoder{w: w}
}

func (enc *encoder) push() {
	enc.lvl++
}

func (enc *encoder) pop() {
	enc.lvl--
}

func (enc *encoder) writeIndent() {
	for i := 0; i < enc.lvl; i++ {
		enc.write([]byte("\t"))
	}
}

func (enc *encoder) write(p []byte) {
	if enc.err != nil {
		return
	}
	_, enc.err = enc.w.Write(p)
}

func (enc *encoder) encodeBlock(blk Block) error {
	for _, dir := range blk {
		enc.encodeDir(*dir)
	}
	return enc.err
}

func (enc *encoder) encodeDir(dir Directive) error {
	if enc.err != nil {
		return enc.err
	}

	if dir.Name == "" {
		enc.err = errDirEmptyName
		return enc.err
	}

	enc.writeIndent()
	enc.write([]byte(maybeQuote(dir.Name)))
	for _, p := range dir.Params {
		enc.write([]byte(" "))
		enc.write([]byte(maybeQuote(p)))
	}

	if len(dir.Children) > 0 {
		enc.write([]byte(" {\n"))
		enc.push()
		enc.encodeBlock(dir.Children)
		enc.pop()

		enc.writeIndent()
		enc.write([]byte("}"))
	}
	enc.write([]byte("\n"))

	return enc.err
}

const specialChars = "\"\\\r\n'{} \t"

func maybeQuote(s string) string {
	if s == "" || strings.ContainsAny(s, specialChars) {
		var sb strings.Builder
		sb.WriteByte('"')
		for _, ch := range s {
			if strings.ContainsRune(`"\`, ch) {
				sb.WriteByte('\\')
			}
			sb.WriteRune(ch)
		}
		sb.WriteByte('"')
		return sb.String()
	}
	return s
}