#!/usr/bin/env slsh %_debug_info = 1; % A simple ls designed primarily for windows. static variable Months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; static variable Six_Months_Ago = _time () - 3600*24*30*6; static define parse_mode (mode, x) { variable m; if (mode & 4) m = "r"; else m = "-"; if (mode & 2) m += "w"; else m += "-"; if (x != "x") m += x; else if (mode & 1) m += "x"; else m += "-"; return m; } static define ls_long (file_list, st_list) { _for (0, length(file_list)-1, 1) { variable i = (); variable file = file_list[i]; variable st = st_list[i]; variable size, mode, owner, group, symlink, mtime; variable mstring; variable tm; size = st.st_size; mtime = st.st_mtime; mode = st.st_mode; owner = st.st_uid; group = st.st_gid; tm = localtime (mtime); #ifdef WIN32 if (tm == NULL) mtime = "Jan 01 1980"; else #endif if (mtime < Six_Months_Ago) mtime = sprintf ("%s %2d %4d", Months[tm.tm_mon], tm.tm_mday, 1900 + tm.tm_year); else mtime = sprintf ("%s %2d %2d:%02d", Months[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min); symlink = ""; if (stat_is ("reg", mode)) mstring = "-"; else if (stat_is ("dir", mode)) mstring = "d"; else if (stat_is ("lnk", mode)) { %symlink = " -> " + mstring = "l"; } else if (stat_is ("chr")) mstring = "c"; else mstring = "?"; variable x = "x"; if (mode & 04000) x = "s"; mstring += parse_mode (mode shr 6, x); x = "x"; if (mode & 02000) x = "g"; mstring += parse_mode (mode shr 3, x); x = "x"; if (mode & 02000) x = "t"; mstring += parse_mode (mode, x); () = fprintf (stdout, "%8s %8S %8S %10S %s %s%s\n", mstring, owner, group, size, mtime, file, symlink); } } static variable Use_Long_Form = 0, Use_atime = 0, Sort_By_Time = 0, Sort_By_Size = 0, Use_a_Option = 0, Use_F_Option = 1, Use_d_Option = 0; static define parse_args (args) { variable ch; foreach (args) { ch = (); switch (ch) { case 'l': Use_Long_Form = 1; } { case 'u': Use_atime = 1; } { case 't': Sort_By_Time = 1; } { case 'S': Sort_By_Size = 1; } { case 'd': Use_d_Option = 1; } { case 'a': Use_a_Option = 1; } { case '-':} % ignore it { () = fprintf (stderr, "Option '%c' not supported.\n", ch); } } } define ls_short (dirs) { variable max_len; variable ncols; variable num, num_per_row, num_rows; variable stride; num = length (dirs); max_len = 0; foreach (dirs) { variable dir; dir = (); if (strlen (dir) > max_len) max_len = strlen (dir); } max_len += 2; variable format = "%-" + string (max_len) + "s"; ncols = 80; num_per_row = ncols / max_len; if (num_per_row == 0) num_per_row = 1; num_rows = (num + num_per_row - 1) / num_per_row; _for (0, num_rows-1, 1) { variable r = (); _for (0, num_per_row-1, 1) { variable c = (); variable i = r + num_rows * c; if (i < num) () = fprintf (stdout, format, dirs[i]); } () = fputs ("\n", stdout); } } static define size_sort (a, b) { b.st_size - a.st_size; } static define time_sort (a, b) { b.st_mtime - a.st_mtime; } static define is_non_null_fun (a) { a != NULL; } define sort_files (dirs, sts) { variable st, i, non_null; % Some of the sts structs may be NULL. Get rid of those non_null = array_map (Char_Type, &is_non_null_fun, sts); i = where (non_null); dirs = dirs [i]; sts = sts [i]; if (Use_atime) { foreach (sts) { st = (); st.st_mtime = st.st_atime; } } if (Sort_By_Time) i = array_sort (sts, &time_sort); else if (Sort_By_Size) i = array_sort (sts, &size_sort); else i = array_sort (dirs); return dirs[i], sts[i]; } static define isdir_fun (st) { stat_is ("dir", st.st_mode); } define do_ls (dirs, recurse); define do_ls (dirs, this_dir, recurse, prune_hidden) { variable i, len, st, sts, dir; if (dirs == NULL) return; len = length(dirs); sts = Struct_Type [len]; _for (0, len-1, 1) { i = (); dir = dirs[i]; if (prune_hidden) { if ((dir[0] == '.') and (Use_a_Option == 0)) continue; } st = lstat_file (path_concat (this_dir, dir)); if (st == NULL) () = fprintf (stderr, "%s: %s: %s\n", __argv[0], path_concat (this_dir, dir), errno_string (errno)); else sts[i] = st; } (dirs, sts) = sort_files (dirs, sts); variable isdir = array_map (Char_Type, &isdir_fun, sts); variable i_reg = where (isdir == 0); variable i_dir = where (isdir); if (Use_F_Option) dirs[i_dir] = array_map (String_Type, &path_concat, dirs[i_dir], ""); if ((recurse == 0) or Use_d_Option) { if (Use_Long_Form) ls_long (dirs, sts); else ls_short (dirs); return; } if (Use_Long_Form) ls_long (dirs[i_reg], sts[i_reg]); else ls_short (dirs[i_reg]); if (length(i_dir) == 1) { dir = dirs[i_dir][0]; do_ls (listdir (dir), dir, 0, 1); return; } foreach (dirs[i_dir]) { dir = (); () = fprintf (stdout, "%s:\n", dir); do_ls (listdir (dir), dir, 0, 1); () = fprintf (stdout, "\n"); } } define main (argc, argv) { variable dirs; if (argc == 1) return do_ls (listdir("."), ".", 0, 1); else if (__argv[1][0] == '-') { parse_args (__argv[1]); if (__argc > 2) dirs = __argv[[2:]]; else return do_ls (listdir("."), ".", 0, 1); } else dirs = __argv[[1:]]; do_ls (dirs, ".", 1, 0); } main (__argc, __argv);