Daily Programming Challenge

Write a program that generates directory tree in console.


Bonus points for ascii tree design.
Example:
tree SolidOak/
SolidOak/
├── build.rs
├── Cargo.lock
├── Cargo.toml
├── README.md
├── resources
│ ├── soak
│ ├── soakrc
│ ├── SolidOak.desktop
│ └── solidoak.svg
├── screenshot.png
├── src
│ ├── builders.rs
│ ├── ffi.rs
│ ├── main.rs
│ ├── projects.rs
│ ├── ui.rs
│ └── utils.rs
└── UNLICENSE

Other urls found in this thread:

gnu.org/software/guile/
pastebin.com/SYy0ywJP
i.imgur.com/r6s5Xak.png
twitter.com/SFWRedditGifs

cmon user

@echo off

tree

cmon user
tree

tree.sh
#!/bin/bash
tree

>its another pajeet wants his homework done episode

tree /a /f

You said there would be a trig-related challenge today.

How come the challenges aren't daily?

probably a different user who made this thread.

bumping thread, may do this, and I don't want it to die.

they are daily in spirit

print """
/\
/\*\
/\O\*\
/*/\/\/\
/\O\/\*\/\
/\*\/\*\/\/\
/\O\/\/*/\/O/\
||
||
||
"""

(import (ice-9 ftw) (ice-9 rdelim))

(define* (print-trees trees #:optional (depth 0))
(define (print-prefix)
(if (> depth 0)
(begin
(map (lambda x (display "│ ")) (iota (- depth 1)))
(if (null? (cdr trees))
(display "└── ")
(display "├── ")))))
(if (not (null? trees))
(begin
(print-prefix)
(display (caar trees)) (newline)
(print-trees (cddar trees) (+ depth 1))
(print-trees (cdr trees) depth))))

(set-port-encoding! (current-output-port) "UTF-8")
(print-trees (list (file-system-tree (read-line) (const #t))))

is this racket?

It's Guile.

org 0x100
use16
mov ah, 0x47
xor dx, dx
mov si, starting_dir
int 0x21
xor ch, ch
mov cl, [0x80]
test cx, cx
jz @f
mov al, 0x0d
mov di, 0x82
cld
repne scasb
mov byte [di-1], 0
mov ah, 0x3b
mov dx, 0x82
int 0x21
jc exit
@@: mov bx, 1
search:
mov ah, 0x4e
mov cx, 0x37
mov dx, search_pattern
int 0x21
cmp bx, 1
jbe @f
mov cx, bx
.s: mov ah, 0x4f
int 0x21
loop .s
jnc @f
cmp [level], 1
je exit
mov ah, 0x3b
mov dx, previous_dir
int 0x21
dec [level]
ret
@@: cmp byte [0x9e], '.'
je .n
mov dl, '-'
mov cx, [level]
shl cx, 1
mov ah, 0x02
@@: int 0x21
loop @b
inc bx
xor ax, ax
mov di, 0x9e
mov cx, 14
repne scasb
mov word [di-1], 0x0d0a
mov byte [di+1], '$'
mov dx, 0x9e
mov ah, 0x09
int 0x21
test byte [0x95], 0x10
jz .n
mov byte [di-1], 0
mov ah, 0x3b
mov dx, 0x9e
int 0x21
inc [level]
push bx
mov bx, 1
call search
pop bx
jmp search
.n: mov cx, 1
jmp .s
exit:
mov ah, 0x3b
mov byte [starting_dir-1], '\'
mov dx, starting_dir-1
int 0x21
mov ax, 0x4cff
int 0x21

level dw 1
search_pattern db "*.*",0
previous_dir db "..",0
starting_dir rb 64
I may add some pretty ascii later. or maybe not. that would involve a whole new level of complexity.

Is that racket?

No.
gnu.org/software/guile/

#include
#include
#include
#include
#include

static void lsdir(const std::string &path, int level = 0)
{
DIR *dir = opendir(path.c_str());
struct dirent *dent;

if (!dir)
{
perror("opendir");
return;
}

while (dent = readdir(dir))
{
if (dent->d_name[0] == '.')
{
continue;
}

for (int i = 0; i < level - 1; i++)
{
printf("│ ");
}

if (level)
{
printf("├── ");
}

printf("%s\n", dent->d_name);

if (dent->d_type == DT_DIR)
{
lsdir(path + '/' + std::string(dent->d_name), level + 1);
}
}

closedir(dir);
}

int main()
{
lsdir(".");
}


Quick shitty attempt.

I've done something like this before, and if I remember right, going three directories deep made things harder. At that point, there needs to be some white space between your symbols, so you can't just repeat '|' until you get up by the start of the names.

For example, if "solidoak.svg" was a directory with its own sub-directories, you wouldn't continue the line down between those sub-directories and the root directory line, because solidoak.svg is at the end of the list it belongs to.

>C++
Why? You almost had proper, elegant C there, and then you go fuck it up with your STDs for no reason.

Like this to make things clearer:

tree SolidOak/
SolidOak/
├── build.rs
├── Cargo.lock
├── Cargo.toml
├── README.md
├── resources
│ ├── soak
│ ├── soakrc
│ ├── SolidOak.desktop
│ └── solidoak
│ ├── item1.svg
│ ├── item2.svg
│ └── item3.svg
├── screenshot.png
├── src
│ ├── builders.rs
│ ├── ffi.rs
│ ├── main.rs
│ ├── projects.rs
│ ├── ui.rs
│ └── utils.rs
└── UNLICENSE

#!/usr/bin/env powershell
Get-ChildItem -recurse

>#!/usr/bin/env powershell
delet dis

What's wrong with a shebang directive at the beginning of a powershell script? Powershell is available on Linux now. Might as well make it executable...

Can't post an image, it's got color. OOOOH!
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Directories; use Ada.Directories;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO.Unbounded_IO; use Ada.Text_IO.Unbounded_IO;
with Ada.Command_Line; use Ada.Command_Line;

procedure Filesystem is

Global_Indent : Unbounded_String := To_Unbounded_String("");

Current_Directory : String := Argument(1);

procedure Get_Files (Current_Directory : in String) is
Current_Search : Search_Type;
Dir_Entry : Directory_Entry_Type;
begin
Start_Search(Current_Search, Current_Directory, "");
while More_Entries(Current_Search) loop
Get_Next_Entry(Current_Search, Dir_Entry);
if Simple_Name(Dir_Entry) /= "." and
then Simple_Name(Dir_Entry) /= ".." and
then Kind(Dir_Entry) = Directory then
Put(Global_Indent);
Put_Line(Simple_Name(Dir_Entry));
if Length(Global_Indent) = 0 then
Global_Indent := Global_Indent & "|-->";
else
Global_Indent := "| " & Global_Indent;
end if;
Get_Files(Full_Name(Dir_Entry));
Delete(Global_Indent, 1, 4);
elsif Kind(Dir_Entry) = Ordinary_File then
Put(Global_Indent);
Put_Line(ASCII.esc & "[94m" & Simple_Name(Dir_Entry) & ASCII.esc & "[0m");
end if;
end loop;
end Get_Files;

begin

Get_Files(Current_Directory);

end Filesystem;

Pretty dense with no comments, but it seems alright.

#! /usr/bin/env racket
#lang racket
(require racket/cmdline)

;;; repeat a the given string 'n' times
(define (string-repeat s n)
(string-append* (build-list n (const s))))

;;; parse command line options
(command-line
#:args dirs
; traverse function
(define (trav dir [indent 0])
(printf "~a/\n" (last (explode-path dir)))
(let ([lst (directory-list dir)])
(for ([child (in-list lst)]
[i (in-naturals 1)]
; skip hidden files
#:unless (regexp-match #px"^\\." (path->string child)))
; build full path out of name of child
(let* ([fullpath (build-path dir child)]
[dir? (directory-exists? fullpath)])
; display prefix
(printf "~a~a\u2500\u2500 "
(string-repeat "\u2502 " indent)
(if (and (not dir?)
(= i (length lst)))
"\u2514" "\u251c"))
; recur if directory, or just show file name
(if dir?
(trav fullpath (add1 indent))
(displayln child))))))
; call on all arguments
(for-each trav
(if (empty? dirs)
; or, use cd if no arguments
'(".")
dirs)))

>seems alright
it couldn't be cleaner, other than the necessary escape characters.

>>>pastebin.com/SYy0ywJP
Now eligible for bonus points. But too long to fit in one post. Also fixed a bug where it would print a directory twice (see screenshot )
As far as I can tell, there's no way to know ahead of time if the current entry will be the last one in the directory, so I ended up storing the previous entry and adjusting the prefix as needed.

pic won't upload for some reason

+1 for Lisp

This is racket:

std::string is far more elegant than the crap I would of had to write if it was in C.

pic still won't upload
>>>i.imgur.com/r6s5Xak.png

Faggot

?

Who is this semen demon?

Needing to ask the OS for directory info means I don't get to use my own dumb language. Have one in befunge instead:
v
8y&
9u4%d
%&^652f
op$!*is$1
a2*_!1%fAg^
ov^3)(kgI93jf3

I uh either take advantage of some behavior of cfunge specifically or a use a hacky thing to get around a bug that at the very least doesn't work in pyfunge. Maybe it's cross platform. I'm a little confused about how the y command works to be honest, getting the command line args on to the stack was way trickier than I thought it would be

const fs = require('fs');

const tree = (path = './', abs = '.', prevBranch = '', nextBranch = '') => {
console.log(prevBranch + nextBranch + path);

if (!fs.statSync(abs).isDirectory()) return;

fs.readdirSync(abs).forEach((file, idx, files) => tree(
file,
`${abs}/${file}`,
`${nextBranch ? `│ ${prevBranch}` : ''}`,
`${files.length - 1 === idx ? '└──' : '├──'}`
));
};

tree();

>wake up at 7am everday.
>had really good breakfast.
>then go to he libary
>learn new things with lots of books and tutorials
>mfw i understand everthing just so well and everyday is gettin better than the yesterday

You're still a NEET

no i am not a neet

wagecucks BTFO

he didn't say he is self employed, from his post I would say he is a (uni?) student.

#define _XOPEN_SOURCE 500
#include
#include
#include
#include
#include
#include

#define error(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)

int node_print(const char *fpath, const struct stat *sb,
int typeflag, struct FTW *ftwbuf)
{
if (ftwbuf->level > 0) {
for (int i = 0; i < ftwbuf->level; i++)
printf("| ");

if (ftwbuf->level > 0)
printf("+-- ");
}

size_t len = strlen(fpath) + 1;
char filebuf[len];

strncpy(filebuf, fpath, len);
puts(basename(filebuf));

return 0;
}

int main(int argc, char **argv)
{
for (int i = 1; i < argc; i++) {
if (nftw(argv[i], node_print, 128, 0) < 0)
error("%s: error: %s: %s\n", basename(argv[0]), argv[i], strerror(errno));
}

return 0;
}

$ ./ftw ~/tmp/test
test
| +-- a
| | +-- a.txt
| | +-- c.txt
| | +-- b.txt
| +-- b
| | +-- a.txt
| | +-- c.txt
| | +-- b.txt
| +-- c
| | +-- a.txt
| | +-- c.txt
| | +-- b.txt

Oops, ignore the the second if (ftwbuf->level > 0).

Changed it at the last second and forgot to remove it.

>arial
not using helvetica

> tree.py
Folder PATH listing for volume Data G4TB
Volume serial number is XXXX-XXXX
N:.
├───.hg
│ ├───cache
│ └───store
│ └───data
│ └───src
└───src

>mfw g++ doesn't support the filesystem ts yet

that is pretty cool

not perfect but whatever

...

Thanks, it's still not perfect though, suffers from the same problem mentioned here: . But at least it happens less frequently since file-search syscalls in dos always return directories before files.
The only way to completely avoid that would require storing the entire tree in memory before printing, so you can iterate over it both ways and tell if the current directory has more files before recursing into a new directory.

% mkdir -p a/b/c a/d a/e/f
% find a | sort | perl -lne '$f=(split("/"))[-1]; $n=tr/\///; print "--"x$n,$f'
a
--b
----c
--d
--e
----f

Meh.

fix bug
add color
const fs = require('fs');

const red = str => `\x1b[31m${str}\x1b[0m`;
const blue = str => `\x1b[34m${str}\x1b[0m`;

const tree = (path = './', absPath = '.', prevBranch = '', nextBranch = '') => {
const which = !fs.statSync(absPath).isDirectory();
const color = which ? blue : red;

console.log(prevBranch + nextBranch + color(path));

if (which) return;

fs.readdirSync(absPath).forEach((file, idx, files) => tree(
file,
`${absPath}/${file}`,
`${nextBranch ? nextBranch === '└──'
? `${prevBranch} ` : `${prevBranch}│ `
: ''}`,
`${files.length - 1 === idx ? '└──' : '├──'}`
));
};

tree();

At least make it with a loop

This is from memory, so coud be off...

find -type f .

>python2

>Needing to ask the OS for directory info
Implement Erlang-style ports.

import System.Directory

main = do
dir FilePath -> IO ()
recDirs i dir = do
files do
b > recDirs (i+2) x
else putStrLn $ ("| " ++ replicate i '-') ++ x

import Control.Monad.State.Lazy
import System.Directory

addToList :: State [Int]()
addToList = modify (1:) >>= \x -> return x

add :: Int -> State [Int]()
add x = modify (x:)

multList :: Int -> State [Int] ()
multList x = get >>= \r -> put $ map (x*) r


main = do
dir FilePath -> IO ()
recDirs i dir = do
files do
b

>no screenshot

proc tree path {
set xs $path
set offset {}
while {$xs ne {}} {
set x [lindex $xs 0]
set xs [lrange $xs 1 end]
switch $x {
BEGIN_DIR { lappend offset 1 }
END_DIR { set offset [lrange $offset 0 end-1] }
FINAL { lset offset end 0 }
default {
if {[file isdirectory $x]} {
set subdir [glob -nocomplain -directory $x *]
set xs [concat BEGIN_DIR \
[lrange $subdir 0 end-1] \
FINAL \
[lindex $subdir end] \
END_DIR \
$xs]
}
set line ""
foreach y [lrange $offset 0 end-1] {
if {$y} {
append line "| "
} else {
append line " "
}
}
if {$offset ne {}} {
append line "+-- "
}
puts $line[file tail $x]
}
}
}
}
tree [lindex $argv 0]


.
+-- build.rs
+-- Cargo.lock
+-- Cargo.toml
+-- README.md
+-- resources
| +-- soak
| +-- soakrc
| +-- SolidOak.desktop
| +-- solidoak.svg
+-- screenshot.png
+-- src
| +-- builders.rs
| +-- ffi.rs
| +-- foo
| | +-- bar
| +-- main.rs
| +-- projects.rs
| +-- ui.rs
| +-- utils.rs
| +-- www
| +-- grav
| | +-- smack
| +-- holygrail.gif
| +-- index.html
+-- tree.tcl
+-- UNLICENSE

>UNLICENSE
stop being cucks and use the GPL

yeah I rolled my eyes at that user

import os, sys

def tree(dir, level):
try:
for item in os.listdir(dir):
print(' ' * level + item)
tree(dir + '/' + item, level + 1)
except:
return

tree(sys.argv[1], 0)

No formatting but it's short and sweet

find|sed 's@[^./]*/@ @g'

>short and sweet
That's because it doesn't do the hard thing, which is drawing the lines correctly.

Kono Rakketto desu?

It's also wrong and retarded.

Goodnuff? Also, what the fuck am I supposed to do about the 3rd level?

>actually doing these challenges
Christ if you do it at least don't post your code
All you're doing is helping Rajesh do his homework

>Anyone's homework is this trivial