Re: files > 2G under Solaris



Hi, Maksym!

[Moving to the list with your permission]

> > > Were you be able to see correct file sizes on 32 bit system with large
> > > files enabled?
> >
> > Yes, but not always :-)
> >
> I suspected that ...prinf could not understand 8 bit integers in 32 bit
> environment:-)

You mean 8-byte integers. Actually, some versions of printf understand
"%lld", "%Ld" and "%qd". All three correspond to "long long int".

> But I tested, at least under Solaris >> and << works fine for them. It
> should not be problem to use this kind of test. (Especially taking into
> account that in MC field width is fixed -- FAR works fine somehow with
> variable field width)

But doing it portably wasn't easy. There is no standard format
specification for off_t. Searching for a type with the same sizeof (in
preprocessor language!) is ugly.

So I just wrote a new function, size_trunc_len(), similar in spirit to
size_trunc() from util.c but using off_t instead of double and supporting
maximal string length.

Support for yottabytes is probably an overkill, but you never know, and,
most importantly, it was trivial to implement.

Unless somebody finds any bugs I'll apply the following patch.

ChangeLog:
	* util.c (size_trunc_len): New function - print file size to
	a buffer of limited length.
	* util.h: Declare size_trunc_len().
	* screen.c (string_file_size): Use size_trunc_len().

_____________________________________________
--- screen.c
+++ screen.c
@@ -197,7 +197,6 @@ char *
 string_file_size (file_entry *fe, int len)
 {
     static char buffer [BUF_TINY];
-    int i;

 #ifdef HAVE_ST_RDEV
     if (S_ISBLK (fe->buf.st_mode) || S_ISCHR (fe->buf.st_mode))
@@ -207,16 +206,7 @@ string_file_size (file_entry *fe, int le
     else
 #endif
     {
-        g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->buf.st_size);
-        if (len && (i = strlen (buffer)) > len) {
-            if (i - 2 > len) {
-                if (i - 5 > len)
-                    g_snprintf (buffer, sizeof (buffer), "%luG", (unsigned long) ((fe->buf.st_size) >> 30));
-                else
-                    g_snprintf (buffer, sizeof (buffer), "%luM", (unsigned long) ((fe->buf.st_size) >> 20));
-            } else
-                g_snprintf (buffer, sizeof (buffer), "%luK", (unsigned long) ((fe->buf.st_size) >> 10));
-        }
+	size_trunc_len (buffer, len, fe->buf.st_size);
     }
     return buffer;
 }
--- util.c
+++ util.c
@@ -313,6 +313,38 @@ char *size_trunc_sep (double size)
     return d;
 }

+/*
+ * Print file SIZE to BUFFER, but don't exceed LEN characters,
+ * not including trailing 0. BUFFER should be at least LEN+1 long.
+ * This function is called for every file on panels, so avoid
+ * floating point by any means.
+ */
+void
+size_trunc_len (char *buffer, int len, off_t size)
+{
+    /* Avoid taking power for every file.  */
+    static const off_t power10 [] =
+	{1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
+	 1000000000};
+    static const char *suffix [] =
+	{"", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL};
+    int j = 0;
+
+    /* Don't print more than 9 digits - use suffix.  */
+    if (len == 0 || len > 9)
+	len = 9;
+
+    for (j = 0; suffix [j] != NULL; j++) {
+	if (size < power10 [len - (j > 0)]) {
+	    g_snprintf (buffer, len + 1, "%lu%s", (unsigned long) size, suffix[j]);
+	    break;
+	}
+
+	/* Powers of 1024, no rounding.  */
+	size = size >> 10;
+    }
+}
+
 int is_exe (mode_t mode)
 {
     if ((S_IXUSR & mode) || (S_IXGRP & mode) || (S_IXOTH & mode))
--- util.h
+++ util.h
@@ -18,6 +18,7 @@
 char *name_trunc (char *txt, int trunc_len);
 char *size_trunc (double size);
 char *size_trunc_sep (double size);
+void size_trunc_len (char *buffer, int len, off_t size);
 int  is_exe (mode_t mode);
 char *string_perm (mode_t mode_bits);
 char *strip_password (char *path, int has_prefix);
_____________________________________________

Regards,
Pavel Roskin





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]