1
 
 

136 times is for arm-unknown-linux-gnueabihf target.

Obviously, this number varies for different targets, for example fli is 88x smaller for aarch64-unknown-linux-gnu etc.

you can compare yourself for other targets here:

https://github.com/eza-community/eza/releases

https://github.com/tracyspacy/fli/releases

2
 
 

Last 24 hours were good for fli:

3
4
 
 

2 major changes:

  • added -r flag for reverse sorting

  • paths can be specified as an argument: fli / or fli target/release/fli or combined with other flags like fli -l -S -r -0 target/relese

Also added 2 new release targets: aarch64-unknown-linux-gnu and x86_64-apple-darwin

binary size for arm-unknown-linux-gnueabihf remains 18KB.

repo: https://github.com/tracyspacy/fli

5
submitted 3 weeks ago by to c/fli@programming.dev
 
 

Here is a simple program, that parses and prints 2 options: -n (w/o associated value) and -t (with numeric value) and an argument after options.

C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  int flags, opt;
  int nsecs, tfnd;

  nsecs = 0;
  tfnd = 0;
  flags = 0;

  while ((opt = getopt(argc, argv, "nt:")) != -1) {
    switch (opt) {
    case 'n':
      flags = 1;
      break;
    case 't':
      // converting string to integer
      nsecs = atoi(optarg);
      tfnd = 1;
      break;
    default: /* '?' */
      exit(EXIT_FAILURE);
    }
  }
  printf("flags=%d; tfnd=%d; nsecs=%d; optind=%d\n", flags, tfnd, nsecs,
         optind);

  if (optind >= argc) {
    fprintf(stderr, "Expected argument after options\n");
    exit(EXIT_FAILURE);
  }

  printf("name argument = %s\n", argv[optind]);

  exit(EXIT_SUCCESS);
}

and the same program in no_std rust

Rust

#![no_std]
#![no_main]

//use libc; // 0.2.186

#[cfg(not(test))]
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
    unsafe { libc::abort() }
}

unsafe extern "C" {
    static mut optarg: *mut libc::c_char;
    static mut optind: i32;
}

#[unsafe(no_mangle)]
extern "C" fn main(argc: i32, argv: *const *mut libc::c_char) {
    let (mut nsecs, mut tfnd, mut flags) = (0, 0, 0);

    loop {
        let opt = unsafe { libc::getopt(argc, argv, c"nt:".as_ptr()) };
        if opt == -1 {
            break;
        }
        match opt as u8 {
            b'n' => {
                flags = 1;
            }
            b't' => {
                nsecs = unsafe { libc::atoi(optarg) };
                tfnd = 1;
            }
            _ => unsafe { libc::exit(libc::EXIT_FAILURE) },
        }
    }
    unsafe {
        libc::printf(
            c"flags=%d; tfnd=%d; nsecs=%d; optind=%d\n".as_ptr(),
            flags,
            tfnd,
            nsecs,
            optind,
        );
    }
    unsafe {
        if optind >= argc {
            libc::printf(c"Expected argument after options\n".as_ptr());
            libc::exit(libc::EXIT_FAILURE)
        }

        libc::printf(c"name argument = %s\n".as_ptr(), *argv.add(optind as usize));
    }

    unsafe { libc::exit(libc::EXIT_SUCCESS) }
}

Important notice: it is not some dismiss of rust, it is just a factual state. MacOS for example pushes you to use libc, since their syscalls ABI is not stable. So there is no way to avoid it

6
 
 

Update: fli now support path arguments like :

# root dir
fli /

# general dirs
fli target/release

#file or symliink
fli target/release/fli

#combined with flags  
fli -l -S -r -0 /bin/gmake
# example output of command above 
rwxrwxrwx  1  root  root  4  2025-04-06 15:01  gmake -> >make

fli bin size for arm-unknown-linux-gnueabihf target is still 18KB

size fli
  text    data     bss     dec     hex filename
 15308     520       4   15832    3dd8 fli

I'd like to know what features most people would want. Any suggestions are welcome, but I won't promise I'll implement them :-)

repo : https://github.com/tracyspacy/fli

By Developer @tracyspcy@lemmy.ml

7
 
 

Thing I stumbled upon:

I added boolean argument & if statement inside sort_unstable_by closure:

//from
|&a, &b| compare(a, b) 

//to
|&a, &b| if is_reverse { compare(b, a) } else { compare(a, b) }

I expected binary to grow slightly, but actually got 1KB smaller.

I dug into & found that the reason is: quicksort fn became 980 bytes smaller.

Why? Not sure. Inlining looks same, quicksort just has fewer instructions.

target: arm-unknown-linux-gnueabihf

commit: https://github.com/tracyspacy/fli/commit/a87a98be77cc1972a53e6399716a227d1135e76b

details: https://pastebin.com/qJdTw49n

OC by @tracyspcy@lemmy.ml

8
 
 

In this release:

  • use ISO8601 for date time format
  • sort by time
  • unsorted output option
  • colorized/text output modes for entry types

Full list of features and available flags is in repository readme.

rpi zero binary is still 18KB. It was both challenging and interesting to add new features keeping binary size small.

I don't have an intention to replace ls which is obviously preinstalled, I see fli as a complimentary daily driver. The north star of the project is to always have smaller binary size than ls , while extending or improving ls functionality

Interesting how much we can achieve with rust.

As for a new features, I see various sorting options could be implemented cheaply. If you have ideas, please share.

If you see ways to squeeze some more bytes, you are welcome.

upd:

repo : https://github.com/tracyspacy/fli

OC by @tracyspcy@lemmy.ml