Previously, I had written this program in C++ and asked about it here on Code Review. After spending some time with C++, I desired to become more familiar with its namesake. This is my first C program.
The purpose of the program is to help with remembering complex bash commands. It's invoked with arguments describing the desired operation and displays the commands matching the input ordered by closest match.
I'm trying to stick as close as possible to ANSI C, and I'm still not clear on when to use char []
or char *
.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_TEXT_LENGTH 100
#define MAX_DESC_LENGTH 100
#define MAX_KEYWORDS_LENGTH 100
#define NUM_COMMANDS 8
#define NUM_RESULTS 3
struct command {
char text[MAX_TEXT_LENGTH];
char description[MAX_DESC_LENGTH];
char keywords[MAX_KEYWORDS_LENGTH];
};
struct command commands[NUM_COMMANDS] = {
{ "amixer -Mq set Master 1%-", "decrease volume", "lower" },
{ "amixer -Mq set Master 1%+", "increase volume", "raise" },
{ "makepkg -sri", "build and install a package using a PKGBUILD" },
{ "makepkg -efi", "rebuild and reinstall a package using a PKGBUILD" },
{ "pacman -Qdt", "list orphaned packages", "find" },
{ "pacman -Qe", "list explicitly installed packages", "find" },
{ "pacman -Ql [package]", "list files owned by package", "find" },
{ "pacman -Qo [file]", "list packages that own file", "find owned" }
};
struct result {
int found;
char text[MAX_TEXT_LENGTH];
char description[MAX_DESC_LENGTH];
};
struct result results[NUM_COMMANDS];
int compare_results(const void *, const void *);
void convert_lower(char []);
int main(int argc, char *argv[])
{
char current[MAX_TEXT_LENGTH + MAX_DESC_LENGTH + MAX_KEYWORDS_LENGTH];
int a, c, found, r;
/* convert argv to lowercase */
for (a = 1; a < argc; ++a)
convert_lower(argv[a]);
for (c = 0; c < NUM_COMMANDS; ++c) {
strcpy(current, commands[c].text);
strcat(current, commands[c].description);
strcat(current, commands[c].keywords);
/* convert current to lowercase */
convert_lower(current);
found = 0;
/* count words in both argv and current */
for (a = 1; a < argc; ++a)
if (strstr(current, argv[a]) != NULL)
++found;
if (found == 0)
continue;
results[c].found = found;
strcpy(results[c].text, commands[c].text);
strcpy(results[c].description, commands[c].description);
}
/* sort commands with most words in common with argv at top */
qsort(results, NUM_COMMANDS, sizeof(*results), compare_results);
/* only print NUM_RESULTS results */
for (r = 0; r < NUM_RESULTS && results[r].found > 0; ++r) {
printf("%s\n", results[r].text);
printf(" %s\n", results[r].description);
}
return 0;
}
int compare_results(const void *a, const void *b)
{
struct result *r1 = (struct result *)a;
struct result *r2 = (struct result *)b;
return r2->found - r1->found;
}
void convert_lower(char string[])
{
int c;
for (c = 0; string[c] != '\0'; ++c)
string[c] = tolower(string[c]);
}
pacman -Qdt
, so I have to read the man page again or ask Google. It's much easier to type at the command linebh orphan
. \$\endgroup\$