Skip to content
Snippets Groups Projects
argv_split.c 1.78 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jeremy Fitzhardinge's avatar
    Jeremy Fitzhardinge committed
    /*
     * Helper function for splitting a string into an argv-like array.
     */
    
    #include <linux/kernel.h>
    #include <linux/ctype.h>
    
    #include <linux/slab.h>
    
    #include <linux/export.h>
    
    Jeremy Fitzhardinge's avatar
    Jeremy Fitzhardinge committed
    
    static const char *skip_arg(const char *cp)
    {
    	while (*cp && !isspace(*cp))
    		cp++;
    
    	return cp;
    }
    
    static int count_argc(const char *str)
    {
    	int count = 0;
    
    	while (*str) {
    
    Jeremy Fitzhardinge's avatar
    Jeremy Fitzhardinge committed
    		if (*str) {
    			count++;
    			str = skip_arg(str);
    		}
    	}
    
    	return count;
    }
    
    /**
     * argv_free - free an argv
     * @argv - the argument vector to be freed
     *
     * Frees an argv and the strings it points to.
     */
    void argv_free(char **argv)
    {
    	char **p;
    	for (p = argv; *p; p++)
    		kfree(*p);
    
    	kfree(argv);
    }
    EXPORT_SYMBOL(argv_free);
    
    /**
     * argv_split - split a string at whitespace, returning an argv
     * @gfp: the GFP mask used to allocate memory
     * @str: the string to be split
     * @argcp: returned argument count
     *
     * Returns an array of pointers to strings which are split out from
     * @str.  This is performed by strictly splitting on white-space; no
     * quote processing is performed.  Multiple whitespace characters are
     * considered to be a single argument separator.  The returned array
     * is always NULL-terminated.  Returns NULL on memory allocation
     * failure.
     */
    char **argv_split(gfp_t gfp, const char *str, int *argcp)
    {
    	int argc = count_argc(str);
    	char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
    	char **argvp;
    
    	if (argv == NULL)
    		goto out;
    
    
    Jeremy Fitzhardinge's avatar
    Jeremy Fitzhardinge committed
    	argvp = argv;
    
    	while (*str) {
    
    Jeremy Fitzhardinge's avatar
    Jeremy Fitzhardinge committed
    
    		if (*str) {
    			const char *p = str;
    			char *t;
    
    			str = skip_arg(str);
    
    			t = kstrndup(p, str-p, gfp);
    			if (t == NULL)
    				goto fail;
    			*argvp++ = t;
    		}
    	}
    	*argvp = NULL;
    
      out:
    	return argv;
    
      fail:
    	argv_free(argv);
    	return NULL;
    }
    EXPORT_SYMBOL(argv_split);