Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package crudini for openSUSE:Factory checked 
in at 2025-09-12 21:10:00
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crudini (Old)
 and      /work/SRC/openSUSE:Factory/.crudini.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crudini"

Fri Sep 12 21:10:00 2025 rev:11 rq:1304151 version:0.9.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/crudini/crudini.changes  2023-11-16 
20:31:06.886017498 +0100
+++ /work/SRC/openSUSE:Factory/.crudini.new.1977/crudini.changes        
2025-09-12 21:10:20.905297612 +0200
@@ -1,0 +2,21 @@
+Thu Sep 11 20:09:11 UTC 2025 - Dirk Müller <[email protected]>
+
+- update to 0.9.6:
+  * Support BOM correctly.  Previously we would have stripped
+    any Byte Order Mark, and incorrectly matched items on the first
+    line.
+  * Extraneous blank lines are avoided when deleting a section.
+  * Previously blank lines preceeding a [section] were not
+    removed.
+  * Support creating a section called "default".  Previously
+    this would have been disallowed, with an invalid section name
+    error.
+  * Support ensuring a single space in all 'name = value'
+    entries in the file with --ini-options=space.  This is
+    symmetric and opposite to the existing --ini-options=nospace
+    option.
+  * Support ensuring a single blank line between sections, and
+    no blank lines at the start or end of the file, with --ini-
+    options=sectionspace.
+
+-------------------------------------------------------------------

Old:
----
  crudini-0.9.5.tar.gz

New:
----
  crudini-0.9.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crudini.spec ++++++
--- /var/tmp/diff_new_pack.eTOzZu/_old  2025-09-12 21:10:21.473321564 +0200
+++ /var/tmp/diff_new_pack.eTOzZu/_new  2025-09-12 21:10:21.473321564 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package crudini
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           crudini
-Version:        0.9.5
+Version:        0.9.6
 Release:        0
 Summary:        A utility for manipulating ini files
 License:        GPL-2.0-only

++++++ crudini-0.9.5.tar.gz -> crudini-0.9.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/EXAMPLES new/crudini-0.9.6/EXAMPLES
--- old/crudini-0.9.5/EXAMPLES  2023-10-03 15:50:11.000000000 +0200
+++ new/crudini-0.9.6/EXAMPLES  2025-04-16 16:44:05.000000000 +0200
@@ -60,5 +60,9 @@
 # Add/Update a var, ensuring complete file in name=value format
   crudini --ini-options=nospace --set config_file section parameter value
 
+# Rewrite ini file to ensure a single blank line between sections,
+# and no leading or trailing blank lines
+  crudini --ini-options=sectionspace --set config_file ""
+
 # Read indented ini file, like .gitconfig
   crudini --ini-options=ignoreindent --format=lines --get ~/.gitconfig
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/INSTALL new/crudini-0.9.6/INSTALL
--- old/crudini-0.9.5/INSTALL   2022-07-19 16:24:05.000000000 +0200
+++ new/crudini-0.9.6/INSTALL   2025-04-16 17:04:00.000000000 +0200
@@ -23,3 +23,10 @@
 dependency is appropriately installed on your system.
 You can also download and run the single crudini.py file directly
 to use latest version.
+
+On any system you should be able to pip install
+the latest code from github like:
+
+```
+pip install git+https://github.com/pixelb/crudini.git#egg=crudini
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/Makefile new/crudini-0.9.6/Makefile
--- old/crudini-0.9.5/Makefile  2023-10-04 11:51:36.000000000 +0200
+++ new/crudini-0.9.6/Makefile  2025-04-16 17:18:45.000000000 +0200
@@ -1,5 +1,5 @@
 name = crudini
-version = 0.9.5
+version = 0.9.6
 
 all:
        help2man -n "manipulate ini files" -o crudini.1 -N ./crudini-help
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/NEWS new/crudini-0.9.6/NEWS
--- old/crudini-0.9.5/NEWS      2023-10-03 16:53:15.000000000 +0200
+++ new/crudini-0.9.6/NEWS      2025-04-16 17:19:43.000000000 +0200
@@ -1,6 +1,26 @@
 crudini NEWS                                    -*- outline -*-
 
-* Noteworthy changes in release 0.9.5 (????-??-??)
+* Noteworthy changes in release 0.9.6 (2025-04-16)
+
+  Support BOM correctly.  Previously we would have stripped any
+  Byte Order Mark, and incorrectly matched items on the first line.
+
+  Extraneous blank lines are avoided when deleting a section.
+  Previously blank lines preceeding a [section] were not removed.
+  Note this will collapse multiple empty lines preceding all sections.
+
+  Support creating a section called "default".  Previously this
+  would have been disallowed, with an invalid section name error.
+
+  Support ensuring a single space in all 'name = value' entries in the file
+  with --ini-options=space.  This is symmetric and opposite to the existing
+  --ini-options=nospace option.
+
+  Support ensuring a single blank line between sections, and no blank lines
+  at the start or end of the file, with --ini-options=sectionspace.
+
+
+* Noteworthy changes in release 0.9.5 (2023-10-04)
 
 ** Improvements
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/README.md new/crudini-0.9.6/README.md
--- old/crudini-0.9.5/README.md 2023-10-04 11:52:00.000000000 +0200
+++ new/crudini-0.9.6/README.md 2025-04-16 17:23:01.000000000 +0200
@@ -24,6 +24,8 @@
                        Formats are 'sh','ini','lines'
   --ini-options=OPT  Set options for handling ini files.  Options are:
                        'nospace': use format name=value not name = value
+                       'space': ensure name = value format
+                       'sectionspace': ensure one blank line between sections
                        'ignoreindent': ignore leading whitespace
   --inplace          Lock and write files in place.
                        This is not atomic but has less restrictions
@@ -100,6 +102,10 @@
 # Add/Update a var, ensuring complete file in name=value format
   crudini --ini-options=nospace --set config_file section parameter value
 
+# Rewrite ini file to ensure a single blank line between sections,
+# and no leading or trailing blank lines
+  crudini --ini-options=sectionspace --set config_file ""
+
 # Read indented ini file, like .gitconfig
   crudini --ini-options=ignoreindent --format=lines --get ~/.gitconfig
 ```
@@ -128,3 +134,10 @@
 dependency is appropriately installed on your system.
 You can also download and run the single crudini.py file directly
 to use latest version.
+
+On any system you should be able to pip install
+the latest code from github like:
+
+```
+pip install git+https://github.com/pixelb/crudini.git#egg=crudini
+```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/crudini.1 new/crudini-0.9.6/crudini.1
--- old/crudini-0.9.5/crudini.1 2023-10-04 11:52:00.000000000 +0200
+++ new/crudini-0.9.6/crudini.1 2025-04-16 17:23:01.000000000 +0200
@@ -1,5 +1,5 @@
 .\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.49.3.
-.TH CRUDINI "1" "October 2023" "crudini 0.9.5" "User Commands"
+.TH CRUDINI "1" "April 2025" "crudini 0.9.6" "User Commands"
 .SH NAME
 crudini \- manipulate ini files
 .SH SYNOPSIS
@@ -36,6 +36,8 @@
 \fB\-\-ini\-options\fR=\fI\,OPT\/\fR
 Set options for handling ini files.  Options are:
 \&'nospace': use format name=value not name = value
+\&'space': ensure name = value format
+\&'sectionspace': ensure one blank line between sections
 \&'ignoreindent': ignore leading whitespace
 .TP
 \fB\-\-inplace\fR
@@ -143,6 +145,11 @@
 .IP
 crudini \-\-ini\-options=nospace \-\-set config_file section parameter value
 .PP
+# Rewrite ini file to ensure a single blank line between sections,
+# and no leading or trailing blank lines
+.IP
+crudini \-\-ini\-options=sectionspace \-\-set config_file ""
+.PP
 # Read indented ini file, like .gitconfig
 .IP
 crudini \-\-ini\-options=ignoreindent \-\-format=lines \-\-get ~/.gitconfig
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/crudini.py new/crudini-0.9.6/crudini.py
--- old/crudini-0.9.5/crudini.py        2023-10-04 11:42:39.000000000 +0200
+++ new/crudini-0.9.6/crudini.py        2025-04-16 17:18:35.000000000 +0200
@@ -16,6 +16,7 @@
 import getopt
 import hashlib
 import iniparse
+import io
 import os
 import re
 import shutil
@@ -24,14 +25,31 @@
 
 if sys.version_info[0] >= 3:
     import shlex as pipes
-    from io import StringIO
     import configparser
 else:
+    import codecs
     import pipes
-    from cStringIO import StringIO
     import ConfigParser as configparser
 
 
+user_encoding = 'utf-8'  # user specified items
+file_encoding = 'utf-8'  # encoding of ini file contents
+
+
+# Python 2/3 wrapper to convert strings to unicode
+try:  # Python 2
+    unicode
+
+    def s2u(s, e=user_encoding):
+        return unicode(s, e)
+    # Also add conversion wrapper for print()
+    sys.stdout = codecs.getwriter(user_encoding)(sys.stdout)
+except NameError:  # Python 3
+    def s2u(s, e=user_encoding):
+        return str(s)
+    unicode = str
+
+
 def error(message=None):
     if message:
         sys.stderr.write(message + '\n')
@@ -73,6 +91,7 @@
         self.last_section = 'DEFAULT'
         self.section_indents = {}
         self.windows_eol = None
+        self.bom = None
         # Note [ \t] used rather than \s to avoid adjusting \r\n when no value
         # Unicode spacing around the delimiter would be very unusual anyway
         self.delimiter_spacing = re.compile(r'(.*?)[ \t]*([:=])[ \t]*(.*)')
@@ -83,6 +102,16 @@
 
     def readline(self):
         line = self.fp.readline()
+
+        # Strip BOM. iniparse tracks it but simpler for us to replace later
+        # as we're munging the data in various ways.
+        if self.bom is None:
+            if line and line[0] == u'\ufeff':
+                line = line[1:]
+                self.bom = True
+            else:
+                self.bom = False
+
         # XXX: This doesn't handle ;inline comments.
         # Really should be done within iniparse.
 
@@ -123,6 +152,10 @@
                 # But if need to remove the spacing, then should for all params
 
                 line = self.delimiter_spacing.sub(r'\1\2\3', line)
+            elif not section and 'space' in self.iniopt:
+                # Convert _all_ existing params. New params will be correct
+
+                line = self.delimiter_spacing.sub(r'\1 \2 \3', line)
 
             if line[0] in ' \t':
                 self.indented = True
@@ -148,7 +181,7 @@
     def readline(self):
         if self.first:
             self.first = False
-            return '[%s]' % iniparse.DEFAULTSECT
+            return s2u('[%s]' % iniparse.DEFAULTSECT)
         else:
             return CrudiniInputFilter.readline(self)
 
@@ -214,7 +247,6 @@
         atexit.register(self.delete)
 
         open_mode = os.O_RDONLY
-        open_args = {}
         if operation != "--get":
             # We're only reading here, but we check now for write
             # permissions we'll need in --inplace case to avoid
@@ -225,13 +257,11 @@
             if create and operation != '--del':
                 open_mode += os.O_CREAT
 
-            # Don't convert line endings, so we maintain CRLF in files
-            if sys.version_info[0] >= 3:
-                open_args = {'newline': ''}
-
         try:
-            self.fp = os.fdopen(os.open(self.filename, open_mode, 0o666),
-                                **open_args)
+            # Note we open in binary mode to avoid newline processing,
+            # and also to give more control over the decoding process later.
+            # This avoids platform encoding inconsistencies as per PEP 597.
+            self.fp = os.fdopen(os.open(self.filename, open_mode, 0o666), 'rb')
             if inplace:
                 # In general readers (--get) are protected by file_replace(),
                 # but using read lock here gives AC of the ACID properties
@@ -243,7 +273,7 @@
                 while True:
                     self.lock()
                     fpnew = os.fdopen(os.open(self.filename, open_mode, 0o666),
-                                      **open_args)
+                                      'rb')
                     if (os.name == 'nt' or
                        os.path.sameopenfile(self.fp.fileno(), fpnew.fileno())):
                         # Note we don't fpnew.close() here as that would break
@@ -262,7 +292,7 @@
             # We don't exit early here so that --verbose is also handled.
             if create and operation == '--del' \
                and e.errno in (errno.ENOTDIR, errno.ENOENT):
-                self.fp = StringIO('')
+                self.fp = io.BytesIO(b'')
             else:
                 error(str(e))
                 sys.exit(1)
@@ -289,7 +319,7 @@
         # We ignore lines starting with '%' which mercurial uses to include
         iniparse.change_comment_syntax('%;#', allow_rem=False)
         if preserve_case:
-            self.optionxform = str
+            self.optionxform = lambda x: x
         # Adjust iniparse separator to default to no space around equals
         # Note this does NOT convert existing params with spaces,
         # that's done in CrudiniInputFilter.readline().
@@ -413,6 +443,8 @@
     data = None
     conf = None
     added_default_section = False
+    default_adjust = False
+    removed_section = False
     ini_section_blanks = []
     _print = None
 
@@ -465,10 +497,8 @@
                 st = os.stat(name)
                 os.fchown(f, st.st_uid, st.st_gid)
 
-            if sys.version_info[0] >= 3:
-                os.write(f, bytearray(data, 'utf-8'))
-            else:
-                os.write(f, data)
+            os.write(f, bytearray(data, file_encoding))
+
             # We assume the existing file is persisted,
             # so sync here to ensure new data is persisted
             # before referencing it.  Otherwise the metadata could
@@ -512,13 +542,9 @@
          - Less Durable as existing data truncated before I/O completes.
          - Requires write access to file rather than write access to dir.
         """
-        # Don't convert line endings, so we maintain CRLF in files
-        open_args = {}
-        if sys.version_info[0] >= 3:
-            open_args = {'newline': ''}
 
-        with open(name, 'w', **open_args) as f:
-            f.write(data)
+        with open(name, 'wb') as f:
+            f.write(bytearray(data, file_encoding))
             f.flush()
             os.fsync(f.fileno())
 
@@ -602,6 +628,8 @@
                        Formats are 'sh','ini','lines'
   --ini-options=OPT  Set options for handling ini files.  Options are:
                        'nospace': use format name=value not name = value
+                       'space': ensure name = value format
+                       'sectionspace': ensure one blank line between sections
                        'ignoreindent': ignore leading whitespace
   --inplace          Lock and write files in place.
                        This is not atomic but has less restrictions
@@ -623,9 +651,12 @@
         try:
             self.mode = operation[0]
             self.cfgfile = operation[1]
-            self.section = operation[2]
-            self.param = operation[3]
-            self.value = operation[4]
+            # Convert the following to unicode as
+            # we process in unicode explicitly in python2.
+            # Not needed on python3 where all strings are unicode.
+            self.section = s2u(operation[2])
+            self.param = s2u(operation[3])
+            self.value = s2u(operation[4])
         except IndexError:
             pass
 
@@ -693,7 +724,7 @@
             if o in ('--help',):
                 self.usage(0)
             elif o in ('--version',):
-                print('crudini 0.9.5')
+                print('crudini 0.9.6')
                 sys.exit(0)
             elif o in ('--verbose',):
                 self.verbose = True
@@ -705,9 +736,13 @@
             elif o in ('--ini-options',):
                 self.iniopt = a.split(',')
                 for opt in self.iniopt:
-                    if opt not in ('', 'nospace', 'ignoreindent'):
+                    if opt not in ('', 'nospace', 'space', 'sectionspace',
+                                   'ignoreindent'):
                         error('--ini-options not recognized: %s' % opt)
                         self.usage(1)
+                if 'nospace' in self.iniopt and 'space' in self.iniopt:
+                    error('--ini-options=space,nospace are mutually exclusive')
+                    sys.exit(1)
             elif o in ('--existing',):
                 self.update = a or 'param'  # 'param' implies all must exist
                 if self.update not in ('file', 'section', 'param'):
@@ -804,11 +839,13 @@
                 sys.exit(1)
 
             # A "param=with=equals = value" line can not be found with --get
-            # so avoid the ambiguity.  Restrict to 'nospace' to allow hack in
-            # https://github.com/pixelb/crudini/issues/33#issuecomment-\
+            # so avoid the ambiguity.  Note this precludes the "nospace" hack
+            # in https://github.com/pixelb/crudini/issues/33#issuecomment-\
             # 1151253988
-            if 'nospace' in self.iniopt and self.param and '=' in self.param:
+            if self.param and '=' in self.param:
                 error("param names should not contain '=': %s" % self.param)
+                if 'nospace' not in self.iniopt:
+                    error("Use --ini-options=nospace if you want that format")
                 sys.exit(1)
 
         if self.section_explicit_default is None:
@@ -825,7 +862,7 @@
         return operations
 
     def _has_default_section(self):
-        fp = StringIO(self.data)
+        fp = io.StringIO(self.data)
         for line in fp:
             if line.startswith('[%s]' % iniparse.DEFAULTSECT):
                 return True
@@ -833,10 +870,7 @@
 
     def _chksum(self, data):
         h = hashlib.sha256()
-        if sys.version_info[0] >= 3:
-            h.update(bytearray(data, 'utf-8'))
-        else:
-            h.update(data)
+        h.update(bytearray(data, file_encoding))
         return h.digest()
 
     def _parse_file(self, filename, add_default=False, preserve_case=False):
@@ -846,9 +880,10 @@
                 # Doing it here will avoid rereads on reparse and support
                 # correct parsing of stdin
                 if filename == '-':
-                    self.data = sys.stdin.read()
+                    ifp = os.fdopen(sys.stdin.fileno(), 'rb')
                 else:
-                    self.data = self.locked_file.fp.read()
+                    ifp = self.locked_file.fp
+                self.data = ifp.read().decode(file_encoding)
                 if self.mode != '--get':
                     # compare checksums to flag any changes
                     # (even spacing or case adjustments) with --verbose,
@@ -860,7 +895,8 @@
                 else:
                     self.newline_at_start = False
 
-            fp = StringIO(self.data)
+            # newline='' =-> don't convert line endings
+            fp = io.StringIO(self.data, newline='')
             if add_default:
                 fp = AddDefaultSection(fp, self.iniopt)
             else:
@@ -875,6 +911,7 @@
             self.replace_leading = fp.replace_leading
             self.section_indents = fp.section_indents
             self.windows_eol = fp.windows_eol
+            self.bom = fp.bom
             return conf
         except EnvironmentError as e:
             error(str(e))
@@ -961,12 +998,21 @@
             if self.mode == "--del":
                 return
             else:
+                # Adjust to allow adding a "default" section (issue #80)
+                skip_section_add = False
+                if section.lower() == "default":
+                    section = "crudini_default_adjust_%s" % section
+                    self.default_adjust = True
+                    if self.conf.has_section(section):  # We already added
+                        skip_section_add = True
+
                 # Note this always adds a '\n' before the section name
                 # resulting in double spaced sections or blank line at
                 # the start of a new file to which a new section is added.
                 # List the sections here to adjust when writing.
-                self.ini_section_blanks.append(section)
-                self.conf.add_section(section)
+                if not skip_section_add:
+                    self.ini_section_blanks.append(section)
+                    self.conf.add_section(section)
 
         if param is not None:
             try:
@@ -1048,9 +1094,11 @@
                 for name in self.conf.defaults():
                     self.conf.remove_option(iniparse.DEFAULTSECT, name)
             else:
-                if not self.conf.remove_section(self.section) \
-                   and self.update in ('param', 'section'):
-                    raise configparser.NoSectionError(self.section)
+                if not self.conf.remove_section(self.section):
+                    if self.update in ('param', 'section'):
+                        raise configparser.NoSectionError(self.section)
+                else:
+                    self.removed_section = True
         elif self.value is None:
             try:
                 if not self.conf.remove_option(self.section, self.param) \
@@ -1180,9 +1228,18 @@
                     self.command_get()
 
             if self.mode != '--get':
+                # Del possible extraneous blank line left with removed section
+                # XXX: This may collapse existing multiple blank lines
+                if self.removed_section and 'sectionspace' not in self.iniopt:
+                    iniparse.tidy(self.conf)
+
                 # XXX: Ideally we should just do conf.write(f) here, but to
                 # avoid iniparse issues, we massage the data a little here
-                str_data = str(self.conf.data)
+                if sys.version_info[0] >= 3:
+                    str_data = str(self.conf.data)
+                else:
+                    # XXX: Can't use uc() here as can't specify encoding
+                    str_data = unicode(self.conf.data)
                 if len(str_data) and str_data[-1] != '\n':
                     str_data += '\n'
 
@@ -1210,11 +1267,21 @@
                     else:
                         str_data = str_data.replace(default_sect, '', 1)
 
-                # Remove extraneous blanks added by iniparse.
-                # Note iniparse also has a tidy() function to do globally
-                for section in self.ini_section_blanks:
-                    section_s = '\n[%s]\n' % section
-                    str_data = str_data.replace(section_s, section_s[1:], 1)
+                # Handle creation of non special "default" section
+                if self.default_adjust:
+                    str_data = str_data.replace('crudini_default_adjust_', '')
+
+                # Process blank lines around sections
+                if 'sectionspace' in self.iniopt:
+                    # Ensure a single blank line before sections
+                    str_data = re.sub(r'\n*(\[[^\]]+\])', r'\n\n\1', str_data)
+                    str_data = str_data.lstrip('\n')  # remove leading \n
+                    str_data = str_data.rstrip('\n') + '\n'  # ensure \n at end
+                else:
+                    # Remove extraneous blanks iniparse adds when adding sects
+                    for section in self.ini_section_blanks:
+                        section_ = '\n[%s]\n' % section
+                        str_data = str_data.replace(section_, section_[1:], 1)
 
                 if self.windows_eol:
                     # iniparse uses '\n' for new/updated items
@@ -1230,6 +1297,9 @@
                     str_data = str_data.replace('%s=%scrudini_no_arg' %
                                                 (spacing, spacing), '')
 
+                if self.bom:
+                    str_data = u'\ufeff%s' % str_data
+
                 changed = self.chksum != self._chksum(str_data)
 
                 if self.output == '-':
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/setup.cfg new/crudini-0.9.6/setup.cfg
--- old/crudini-0.9.5/setup.cfg 2023-10-04 11:42:26.000000000 +0200
+++ new/crudini-0.9.6/setup.cfg 2025-04-16 17:18:25.000000000 +0200
@@ -3,7 +3,7 @@
 author = Pádraig Brady
 author_email = [email protected]
 license = GPLv2
-version = 0.9.5
+version = 0.9.6
 description = A utility for manipulating ini files
 keywords = ini, config, edit
 url = http://github.com/pixelb/crudini
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/tests/space-in.ini 
new/crudini-0.9.6/tests/space-in.ini
--- old/crudini-0.9.5/tests/space-in.ini        1970-01-01 01:00:00.000000000 
+0100
+++ new/crudini-0.9.6/tests/space-in.ini        2025-04-16 13:49:15.000000000 
+0200
@@ -0,0 +1,8 @@
+#comment=ignore
+p1=1
+p2=2=2
+p3:3=3
+p 4=4
+p5  = 5
+p6:6:6 a
+  multiline=ignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/tests/space-out.ini 
new/crudini-0.9.6/tests/space-out.ini
--- old/crudini-0.9.5/tests/space-out.ini       1970-01-01 01:00:00.000000000 
+0100
+++ new/crudini-0.9.6/tests/space-out.ini       2025-04-16 13:49:15.000000000 
+0200
@@ -0,0 +1,9 @@
+#comment=ignore
+p1 = 1
+p2 = 2=2
+p3 : 3=3
+p 4 = 4
+p5 = 5
+p6 : 6:6 a
+  multiline=ignore
+new = val
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crudini-0.9.5/tests/test.sh 
new/crudini-0.9.6/tests/test.sh
--- old/crudini-0.9.5/tests/test.sh     2023-10-03 17:26:02.000000000 +0200
+++ new/crudini-0.9.6/tests/test.sh     2025-04-16 17:16:21.000000000 +0200
@@ -54,25 +54,27 @@
 printf '%s\n' '[nonDEFAULT]' 'name = val' > good.ini
 diff -u test.ini good.ini && ok || fail
 
-printf '%s\n' 'global=val' > test.ini
-crudini --set test.ini '' global valnew
-printf '%s\n' 'global=valnew' > good.ini
-diff -u test.ini good.ini && ok || fail
+for bom in '' $'\xef\xbb\xbf'; do
+  printf '%s%s\n' "$bom" 'global=val' > test.ini
+  crudini --set test.ini '' global valnew
+  printf '%s%s\n' "$bom" 'global=valnew' > good.ini
+  diff -u test.ini good.ini && ok || fail
 
-printf '%s\n' 'global=val' > test.ini
-crudini --set test.ini DEFAULT global valnew
-printf '%s\n' '[DEFAULT]' 'global=valnew' > good.ini
-diff -u test.ini good.ini && ok || fail
+  printf '%s%s\n' "$bom" 'global=val' > test.ini
+  crudini --set test.ini DEFAULT global valnew
+  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini
+  diff -u test.ini good.ini && ok || fail
 
-printf '%s\n' '[DEFAULT]' 'global=val' > test.ini
-crudini --set test.ini DEFAULT global valnew
-printf '%s\n' '[DEFAULT]' 'global=valnew' > good.ini
-diff -u test.ini good.ini && ok || fail
+  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=val' > test.ini
+  crudini --set test.ini DEFAULT global valnew
+  printf '%s%s\n' "$bom" '[DEFAULT]' 'global=valnew' > good.ini
+  diff -u test.ini good.ini && ok || fail
 
-printf '%s\n' 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini
-crudini --set test.ini '' global valnew
-printf '%s\n' 'global=valnew' '' '[nonDEFAULT]' 'name=val' > good.ini
-diff -u test.ini good.ini && ok || fail
+  printf '%s%s\n' "$bom" 'global=val' '' '[nonDEFAULT]' 'name=val' > test.ini
+  crudini --set test.ini '' global valnew
+  printf '%s%s\n' "$bom" 'global=valnew' '' '[nonDEFAULT]' 'name=val' > 
good.ini
+  diff -u test.ini good.ini && ok || fail
+done
 
 # do these --sets which test [DEFAULT] handling also with --inplace
 for mode in '' '--inplace'; do
@@ -186,6 +188,9 @@
 # basic get
 test "$(crudini --get example.ini section1 cAps)" = 'not significant' && ok || 
fail
 
+# unicode get
+test "$(crudini --get example.ini non-sh-compat útf8name)" = 'val' && ok || 
fail
+
 # get sections
 crudini --get example.ini > test.ini
 printf '%s\n' DEFAULT section1 'empty section' non-sh-compat list > good.ini
@@ -541,6 +546,10 @@
 test "$(crudini --ini-options=nospace --output=- --set noequals.ini \
         noequals param1 value1 \
         | grep param1)" = 'param1=value1' && ok || fail
+#  Ensure correct spacing with --ini-options=space
+test "$(crudini --ini-options=space --output=- --set noequals.ini \
+        noequals param1 value1 \
+        | grep param1)" = 'param1 = value1' && ok || fail
 
 # Test can read windows format files
 printf '%s\r\n' '' 'empty' 'param=value' > test.ini
@@ -570,6 +579,13 @@
 diff -u <(crudini --output=- --ini-options=nospace \
           --set nospace-in.ini '' new val) \
         nospace-out.ini && ok || fail
+# Test --ini-options=space
+diff -u <(crudini --output=- --ini-options=space \
+          --set space-out.ini '' new val) \
+        space-out.ini && ok || fail
+# - Mixed space / nospace not allowed
+crudini --get file.conf '' param1 --ini-options=space,nospace \
+        2>/dev/null && fail || ok
 
 # Test multi operation
 # - Multiple set
@@ -674,3 +690,29 @@
         --set file.conf '' '  param1' a && ok || fail
 diff -u good.conf file.conf && ok || fail
 rm file.conf good.conf
+
+# Test removal of extraneous empty lines
+# implicitly enabled with --del
+printf '\n[%s]\n' 1 2 > good.conf
+cp good.conf file.conf
+for i in 1 2; do crudini --del file.conf $i; crudini --set file.conf $i; done
+diff -u good.conf file.conf && ok || fail
+rm file.conf good.conf
+
+# Test addition/removal of empty lines with sectionspace
+printf '\n[%s]\n[%s]\n\n[%s]\n\n\n[%s]\n\n' 1 2 3 4 > file.conf
+printf '[%s]\n\n[%s]\n\n[%s]\n\n[%s]\n' 1 2 3 4 > good.conf
+crudini --set --ini-options=sectionspace file.conf ''
+diff -u good.conf file.conf && ok || fail
+rm file.conf good.conf
+
+# Test creation of a "default" section
+printf '[%s]\n' 'default' > good.conf
+crudini --set file.conf default # new
+diff -u good.conf file.conf && ok || fail
+crudini --set file.conf default # existing
+diff -u good.conf file.conf && ok || fail
+rm file.conf
+crudini --set file.conf default --set file.conf default # double new
+diff -u good.conf file.conf && ok || fail
+rm file.conf good.conf

Reply via email to