tdmenu_path.c (shell is a bottleneck) - dmenu - Dmenu fork with xft fonts.
 (HTM) git clone git://r-36.net/dmenu
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit bf7b8e37ee2a53f0f1bed75dd84e5214269cfac8
 (DIR) parent 610a0a8d126b5caa7fec60632c999ca326ca2eff
 (HTM) Author: Connor Lane Smith <cls@lubutu.com>
       Date:   Fri,  8 Oct 2010 23:24:22 +0100
       
       dmenu_path.c (shell is a bottleneck)
       Diffstat:
         Makefile                            |      15 +++++++--------
         dmenu_path                          |      26 --------------------------
         dmenu_path.c                        |     101 +++++++++++++++++++++++++++++++
       
       3 files changed, 108 insertions(+), 34 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -3,7 +3,7 @@
        
        include config.mk
        
       -all: options dmenu
       +all: options dmenu dmenu_path
        
        options:
                @echo dmenu build options:
       t@@ -11,22 +11,21 @@ options:
                @echo "LDFLAGS  = ${LDFLAGS}"
                @echo "CC       = ${CC}"
        
       -dmenu.o: dmenu.c config.mk
       -        @echo CC $<
       -        @${CC} -c ${CFLAGS} $<
       +dmenu: dmenu.c config.mk
       +dmenu_path: dmenu_path.c
        
       -dmenu: dmenu.o
       +dmenu dmenu_path:
                @echo CC -o $@
       -        @${CC} -o $@ $+ ${LDFLAGS}
       +        @${CC} -o $@ $< ${CFLAGS} ${LDFLAGS}
        
        clean:
                @echo cleaning
       -        @rm -f dmenu dmenu.o dmenu-${VERSION}.tar.gz
       +        @rm -f dmenu dmenu_path dmenu-${VERSION}.tar.gz
        
        dist: clean
                @echo creating dist tarball
                @mkdir -p dmenu-${VERSION}
       -        @cp LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path dmenu_run dmenu-${VERSION}
       +        @cp LICENSE Makefile README config.mk dmenu.1 dmenu.c dmenu_path.c dmenu_run dmenu-${VERSION}
                @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION}
                @gzip dmenu-${VERSION}.tar
                @rm -rf dmenu-${VERSION}
 (DIR) diff --git a/dmenu_path b/dmenu_path
       t@@ -1,26 +0,0 @@
       -#!/bin/sh
       -CACHE=$HOME/.dmenu_cache
       -IFS=:
       -
       -uptodate() {
       -        test -f "$CACHE" &&
       -        for dir in $PATH
       -        do
       -                test ! $dir -nt "$CACHE" || return 1
       -        done
       -}
       -
       -if ! uptodate
       -then
       -        for dir in $PATH
       -        do
       -                cd "$dir" &&
       -                for file in *
       -                do
       -                        test -x "$file" && echo "$file"
       -                done
       -        done | sort -u > "$CACHE".$$ &&
       -        mv "$CACHE".$$ "$CACHE"
       -fi
       -
       -cat "$CACHE"
 (DIR) diff --git a/dmenu_path.c b/dmenu_path.c
       t@@ -0,0 +1,101 @@
       +/* See LICENSE file for copyright and license details. */
       +#include <dirent.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <unistd.h>
       +#include <sys/stat.h>
       +
       +#define CACHE ".dmenu_cache"
       +
       +static int qstrcmp(const void *a, const void *b);
       +static void die(const char *s);
       +static void scan(void);
       +static int uptodate(void);
       +
       +static char **items = NULL;
       +static const char *Home, *Path;
       +static size_t count = 0;
       +
       +int
       +main(void) {
       +        if(!(Home = getenv("HOME")))
       +                die("no $HOME");
       +        if(!(Path = getenv("PATH")))
       +                die("no $PATH");
       +        if(chdir(Home) < 0)
       +                die("chdir failed");
       +        if(uptodate()) {
       +                execlp("cat", "cat", CACHE, NULL);
       +                die("exec failed");
       +        }
       +        scan();
       +        return EXIT_SUCCESS;
       +}
       +
       +void
       +die(const char *s) {
       +        fprintf(stderr, "dmenu_path: %s\n", s);
       +        exit(EXIT_FAILURE);
       +}
       +
       +int
       +qstrcmp(const void *a, const void *b) {
       +        return strcmp(*(const char **)a, *(const char **)b);
       +}
       +
       +void
       +scan(void) {
       +        char buf[PATH_MAX];
       +        char *dir, *path;
       +        size_t i;
       +        struct dirent *ent;
       +        DIR *dp;
       +        FILE *cache;
       +
       +        if(!(path = strdup(Path)))
       +                die("strdup failed");
       +        for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) {
       +                if(!(dp = opendir(dir)))
       +                        continue;
       +                while((ent = readdir(dp))) {
       +                        snprintf(buf, sizeof buf, "%s/%s", dir, ent->d_name);
       +                        if(ent->d_name[0] == '.' || access(buf, X_OK) < 0)
       +                                continue;
       +                        if(!(items = realloc(items, ++count * sizeof *items)))
       +                                die("malloc failed");
       +                        if(!(items[count-1] = strdup(ent->d_name)))
       +                                die("strdup failed");
       +                }
       +                closedir(dp);
       +        }
       +        qsort(items, count, sizeof *items, qstrcmp);
       +        if(!(cache = fopen(CACHE, "w")))
       +                die("open failed");
       +        for(i = 0; i < count; i++) {
       +                if(i > 0 && !strcmp(items[i], items[i-1]))
       +                        continue;
       +                fprintf(cache,  "%s\n", items[i]);
       +                fprintf(stdout, "%s\n", items[i]);
       +        }
       +        fclose(cache);
       +        free(path);
       +}
       +
       +int
       +uptodate(void) {
       +        char *dir, *path;
       +        time_t mtime;
       +        struct stat st;
       +
       +        if(stat(CACHE, &st) < 0)
       +                return 0;
       +        mtime = st.st_mtime;
       +        if(!(path = strdup(Path)))
       +                die("strdup failed");
       +        for(dir = strtok(path, ":"); dir; dir = strtok(NULL, ":"))
       +                if(!stat(dir, &st) && st.st_mtime > mtime)
       +                        return 0;
       +        free(path);
       +        return 1;
       +}