libSL Overview

posted on 2017-08-06 by Ed van Bruggen

libsl is an extremely small library used to write better and clearer C programs. The code was created by the suckless community, a small group of C hackers and developers creating powerful yet simple programs for Linux designed to be lightweight, configurable, and easier to maintain then the many other unnecessarily bloated alternatives. You can read more about their philosophy on their website. Some of their most notable projects include dwm, dmenu, st, and surf.

libsl is composed of tiny C99 source and headers files designed to be simply copied into a project's source tree. This allows the library to be easily used and easily modified to fit every project's need.

All of libsl is protected under the MIT license, allowing you to use it in your own projects with little strings attached. See LICENSE in the source tree for more.

arg.h

One of the most utilized and most important files in libsl is arg.h, a C header designed to easily interpret short options from the command line. This removes the necessity to copy complex boiler plate or clunky libraries to simply see if an option has been supplied by the user. While arg.h does not support long options (--option vs -o), if your project's CLI is relatively straight forward it is a great, simple, and lightweight method to quickly parse short options in your C code.

To start reading short options simply use the macro ARGBEGIN followed by a { in your C program's main function, don't forget to #include "arg.h" at the top of the file. This macro loops through all the command line arguments and finds the short option (beginning with a single -) and allows you to select one in a switch statement by using case 'a':, where a can be any character for the desired option.

arg.h also defines other macros to read data in the ARGBEGIN block. One example is ARGC() which is defined to ARGBEGIN's internal variable argc_, the character for the short option currently being interpreted.

ARGF() is another useful macro to get an argument after an option. For example if a program prog is run as prog -s string then ARGF() in the s case will return string as a C string. This can also be converted to a number through a function such as atoi. A similar macro EARGF(x) can also run the supplied function upon an error. It is common to define a usage() function in suckless projects such as the one below.

void
usage(void)
{
	die("usage: %s [-ab] [-c STR] [-d STR] [-n NUM | -NUM]", argv0);
}

die() is a function in libsl defined in util.c, see the section below for more.

arg.h also defines a string, argv0, which is set to the program's name, equivalent to argv[0], but global allowing it to be used throughout your code, like in the usage message above.

In this example EARGF(usage()) would display usage info on an error reading the next string.

While ARGF() with atoi() can be used to get a number from given arguments, it is often faster to use the -NUM format (eg prog -4 to get the number 4 instead of prog -n 4). In order to achieve this I have added my own macros to arg.h that can be used.

/* handles -NUM syntax */
#define ARGNUM case '0':\
               case '1':\
               case '2':\
               case '3':\
               case '4':\
               case '5':\
               case '6':\
               case '7':\
               case '8':\
               case '9'

/* get option number */
#define ARGNUMF()	(brk_ = 1, atoi(argv[0]))

The first is ARGNUM which is used in replace of a case statement in the ARG block (eg case 'n': becomes ARGNUM:). Inside of this case replacement ARGNUMF() is used to get the number given by the argument supplied by the user. These macros, while only needing to be defined for 1-9, work on any number over 10 as well.

After running through all the options you want—remembering to use break after each one, possibly including a default in case an argument given is not supported—ARGBEGIN and the curly bracket we opened need to be closed via } ARGEND. ARGEND is essentially just closing all the brackets ARGBEGIN opened, not counting the one we placed.

A complete ARG block example is shown below, don't forget that it needs to be placed in inside the int main(int argc, char *argv[]) function.

ARGBEGIN {
case 'a':
	printf("option a selected\n");
case 'b':
	printf("option b also runs if your not careful\n");
	break;
case 'c':
	printf("options can also have arguments: %s\n", ARGF());
	break;
case 'd':
	printf("support for error messages: %s\n", EARGF(usage()));
	break;
case 'n':
	printf("they can also be numbers: %d\n", atoi(EARGF(usage())));
	break;
ARGNUM:
	printf("or in this format: %d\n", ARGNUMF());
	break;
case 'v':
	verbose++; /* define before ARGBEGIN block */
	printf("options can also be repeated: %d\n", verbose);
	break;
default:
	usage();
} ARGEND;

Note that arg.h modifies argv and argc. If, for example, after parsing the arguments you now want to read any strings after, such as file names, argv[0] is the first argument after the valid options. So if prog -s option filename anotherfile is used, the s case in ARGBEGIN is run with the argument option, then argv[0] will be equal to filename, argv[1] to anotherfile, etc.

util.c

The next file in libsl is util.c. This file defines many general purpose C functions used throughout different projects.

One function found here which is common in many C projects, including Linux, is die(). This utility takes a formatted string, adds a newline at the end, and prints it to stderr before exit()ing with a return value of 1. This is useful for writing simple and clean error messages which need to quit the program. die() is used above in the usage() example as well as the quick examples below.

struct MyData data;
data->str = init_str();
if (!data->str || !strcmp(data->str, ""))
	die("%s: error: could not init data->str", argv0);
int strlen = 20;
char *str;
if (!(str = calloc(strlen, sizeof(char))))
	die("fatal: could not calloc() %u bytes", strlen * sizeof(char));

As well as formatting the output similar to printf(), libsl's die() also supports automatic error messages for functions which set the C global errno. If the string given ends in a colon (:), die() will append a space and the error message thrown by a called function with errno support. Thus the above calloc example can be replaced with the more adaptive:

int strlen = 20;
char *str;
if (!(str = calloc(strlen, sizeof(char))))
	die("calloc:"); /* example error: "calloc: out of memory" */

The above example is the bases for another useful function util defines, ecalloc(). This new function makes sure the pointer allocated by calloc is not NULL, which indicates an error occurred. Using this new wrapper we can replace the example above with the following.

int strlen = 20;
char *str = ecalloc(strlen, sizeof(char));

This function can also be duplicated for other similar functions such as realloc(), malloc(), strdup(), etc. A new example erealloc() function is displayed below.

void *
erealloc(void *p, size_t size)
{
	if (!(p = realloc(p, size)))
		die("realloc:");

	return p;
}

util.h

The header, as well as defining the previous functions, creates some useful macros.

Two macros which are often copy and pasted between projects and files is MAX() and MIN(). They are fairly simple, two integers are given as arguments and the biggest or smallest one is returned respectively.

#define MAX(A, B)   ((A) > (B) ? (A) : (B))
#define MIN(A, B)   ((A) < (B) ? (A) : (B))
MAX(4, 8);     /* => 8   */
MIN(-38, -18); /* => -38 */
MAX(10, -47);  /* => 10  */

In a similar vain BETWEEN() returns whether the first integer supplied is between the next two given integers.

#define BETWEEN(X, A, B)   ((A) <= (X) && (X) <= (B))
BETWEEN(4, -8, 12); /* => 1 (true)  */
BETWEEN(9, 20, 67); /* => 0 (flase) */

LEN() is also often defined here, it is used to return the size of an array.

#define LEN(X)            (sizeof(X) / sizeof((X)[0]))

drw.c

drw.c and its header drw.h are used as an X interfaced for making basic graphical programs, for example dmenu. An in depth overview of the many functions and typedefs offered in this file is coming soon as its own post.

conclusion

I hope this post has be beneficial and will help you create more elegant and cleaner code in C. For other projects putting this philosophy into practice checkout some of my projects, the suckless git repo, and their other recommended projects page.

posted in c

My History of Shell Prompts

posted on 2014-12-08 by Spencer Bravo

As odd as it might seem, until recently I was using the basic, out of the box, shell prompt. The code for this, in my bashrc, was just the basic:

PS1='\u@\h \w \$'
If you don't know what PS1 or bash is then this is probably the setup you have. This produces a shell prompt such as:
spencer@plutonium ~/dotfiles $
This prompt works just fine. But its so boring! I kept this setup for probably the first 6 months I started using linux. But then I wanted to start to spice things up with my shell prompt. So I downloaded Ed's colors.sh file from his dotfiles. To utilize this all you have to do is include it in your bashrc(see my dotfiles for an example). I went through his colors and decided to make my prompt purple. So all I had to do was change my prompt to this:
PS1='${Purple}\u@\h \w \$'
I kept this setup for about a month but then thought "why do I bother keeping my hostname? It just takes up space." So I changed it to
PS1='${Purple}\u: \w \$'
I kept this configuration for quite some time but then I saw something cool that Ed did. He created a small script that checks to see if the command was succesful or not and if it was succesful it would place a green smiley, but if it wasn't it would give back a red frown. You can find that script: here. Then I just changed my PS1 to:
 PS1='${Purple}\u: \w [$(checkium_color)\]$(checkium_random_face) \$'
At this point I had a prompt like this(note:colors not included):
spencer: ~/dotfiles :) $
I kept this configuration for probably about two months but then noticed that I had an issue. Some directories were very long and took up a lot of space so my prompt looked something like this:
spencer: ~/Dropbox/codeshrub/posts/code :) $
This took up way too much space so I changed the w in my PS1 to W to only show the latest directory:
PS1='${Purple}\u: \W [$(checkium_color)\]$(checkium_random_face) \$'
So now that long directory is just
spencer: code :) $
Much easier to read, takes up less space, and it's not likely I'll forget my earlier directory path. I made one last change to my prompt. I removed the external script to check for a succesful command and place a smiley face and to replace it, I added this to my bash profile:
cmd_check() {
if [[ $? = 0 ]]; then
    echo " ${Green}✓";
else
    echo " ${Red}❌";
fi; 
And also changed my PS1 to:
PS1='${BIGreen}\u: ${IWhite}\W $(cmd_check) \$${Color_Off} '
This changes my colors, removes the smileys and adds the x and check, and also makes sure colors are off at the end of the prompt. This is my final product(on the actual one there are the pretty colors :) ):
spencer: ~ ✓ $
I hope you enjoyed this post and I hope it helps you on your PS1 endevors.

posted in bash

include vs. include_once in PHP

posted on 2014-10-08 by Spencer Bravo

A few months ago I was building this site and while looking up how to do something, I noticed the person whose code I was looking at used:

include_once($_SERVER['DOCUMENT_ROOT']."/file.php");

Rather than what I was using:

include($_SERVER['DOCUMENT_ROOT']."/file.php");

I wasn't really sure what the difference was so I did the research. When you use "include" you tell the document just to include the file right there no matter what. When you use "include_once" if the file has been already included in that page it will skip over that command. For example: if you're workin gon a site and you have a seperate header file which you "include" into both your "config" and "index" page that means that if you include the "config" file in the "index" page it will "include" the header twice. Though if you use "include_once" it will understand that the header has already been included and skip it.

I hope this post is useful! If you have any questions or comments please don't hesitate to email us at CSTeam@CodeShrub.com

posted in web

Active Tab Navbar In PHP

posted on 2014-09-21 by Spencer Bravo

This post is about how I set up my navbars for websites. It enables the navbar to be highlighted based on the page you're on and doesn't require you to put a different <nav> section on every page. This setup also gives the ability to create the header on a completely different file (header.inc.php), while still making the navbar active based on the page.

Now to the code:

<?php
$category_explode = explode("/",$_SERVER['REQUEST_URI']);
$site = $category_explode[0];
$page = $category_explode[1];
$post = $category_explode[2];
$nnav = " ";
$nav = '<ul class="nav navbar-nav">
           <li class="inactive"><a href="/">Home</a></li>
           <li class="inactive"><a href="/bash/">Bash</a></li>
           <li class="inactive"><a href="/viml/">VimL</a></li>
           <li class="inactive"><a href="/web/">Web</a></li>
           <li class="inactive"><a href="/about/">About</a></li>
        </ul>';
switch ($page) {
    case "":
        $nnav = str_replace("<li class=\"inactive\"><a href=\"/\">Home</a></li>","<li class=\"active\"><a href=\"/\">Home</a></li>",$nav);
    break;
    case "bash":
        $nnav = str_replace("<li class=\"inactive\"><a href=\"/bash/\">Bash</a></li>","<li class=\"active\"><a href=\"/bash/\">Bash</a></li>",$nav);
    break;
    case "viml":
        $nnav = str_replace("<li class=\"inactive\"><a href=\"/viml/\">VimL</a></li>","<li class=\"active\"><a href=\"/viml/\">VimL</a></li>",$nav);
    break;
    case "web":
        $nnav = str_replace("<li class=\"inactive\"><a href=\"/web/\">Web</a></li>","<li class=\"active\"><a href=\"/web/\">Web</a></li>",$nav);
    break;
    case "about":
        $nnav = str_replace("<li class=\"inactive\"><a href=\"/about/\">About</a></li>","<li class=\"active\"><a href=\"/about/\">About</a></li>",$nav);
    break;
    default:
        $nnav = $nav;
    break;
}
?>

You can view the most current version of this code at https://github.com/spravo13/active-tab-navbar-codeshrub

All I did was create a variable ($nav) to store the basic navigation and then based on what page the user is on I used a switch statement to edit $nav and store the changes in the variable $nnav.

Then all you have to do is include the variable "$nnav" where you want your navigation. Heres an example of using it(this example is later on in the same file, if you don't include your navigation in a seperate file, just include the file with this code in the file you want.

<div class="nav">
    <?php
        echo $nnav;
    ?>
</div>

I hope this post is useful! If you have any questions or comments please don't hesitate to email us at CSTeam@CodeShrub.com

posted in web

Connection to MySQL Database in PHP

posted on 2014-09-15 by Spencer Bravo

This post explains how I connect to MySQL Databases when writing in PHP. This post will mostly be used as a post I will refer to in later MySQL posts, so I won't need to include in those posts how to connect and I can get to the point. For those of you who will need this post at some place in those tutorials I will be sure to include a link to this post.

Now to the code! So when I set up my connection I acctually include it in a seperate file in a seperate directory. The directory is /inc in which I place all the files I will use by including them in other pages. In this directory I include files such as my header, footer, and my config file (in which I include the MySQL database connect setup). This file is named "config.inc.php". This is what the database connect part looks like:

<php
$db_host = ' '; // location of your database(localhost ussualy works)
$db_user = ' '; // your MySQL database username
$db_password = ' '; // your MySQL database password
$database = ' '; // name of your MySQL database

$db_connect = mysql_connect($db_host, $db_user, $db_password);
$db = mysql_select_db($database,$db_connect);
?>

You can view the most current version of this code at https://github.com/spravo13/mysql-db-connect-php-codeshrub

Then all you have to do is include this file anywhere you want to use the database and your variables will be there. Heres an example of using these variables. Note: I have already included the config file earlier on in this following code.

<php
$post_select = "SELECT * FROM post WHERE name = 'phil' LIMIT 1";
$post_query = mysql_query($post_select,$db_connect) or die($db_connect);
while ($post_row = mysql_fetch_assoc($post_query)){
}
?>

Here it is looking for a post named phil. As you see we use the variable "db_connect".

I hope this post is useful! If you have any questions or comments please don't hesitate to email us at CSTeam@CodeShrub.com

posted in web