[c] Format code

This commit is contained in:
Sami Samhuri 2022-01-22 15:48:02 -08:00
parent 94ca5e6024
commit 5a9cf1a0ab
No known key found for this signature in database
GPG key ID: 4B4195422742FC16
10 changed files with 519 additions and 582 deletions

View file

@ -20,124 +20,103 @@
#include <unistd.h> #include <unistd.h>
#include "builtins.h" #include "builtins.h"
#include "main.h"
#include "exec.h" #include "exec.h"
#include "jobs.h" #include "jobs.h"
#include "main.h"
#include "utils.h" #include "utils.h"
int builtin_bg ( int argc, char **argv ) int builtin_bg(int argc, char **argv) {
{ if (argc < 2) {
if ( argc < 2 ) queue_message("bg: usage 'bg <command>'");
{ queue_message(" runs <command> in the background");
queue_message ("bg: usage 'bg <command>'"); return -1;
queue_message (" runs <command> in the background"); }
return -1;
}
pid_t pid = exec_command (&argv[1], 1); /* &argv[1] skips 'bg' */ pid_t pid = exec_command(&argv[1], 1); /* &argv[1] skips 'bg' */
if (pid > 0) if (pid > 0) {
{ job j = add_job(pid, &argv[1]);
job j = add_job (pid, &argv[1]);
char *message = (char *)myxmalloc (MSGLEN); char *message = (char *)myxmalloc(MSGLEN);
snprintf (message, MSGLEN, snprintf(message, MSGLEN, "Running job " YELLOW "%i" WHITE " (pid %i) in background" CLEAR, j->id, pid);
"Running job " YELLOW "%i" WHITE " (pid %i) in background" CLEAR, queue_message(message);
j->id, pid); free(message);
queue_message (message); }
free (message); return pid;
}
return pid;
} }
int builtin_bgkill ( int argc, char **argv ) int builtin_bgkill(int argc, char **argv) {
{ if (argc != 2) {
if ( argc != 2 ) queue_message("bgkill: usage 'bgkill <job number>'");
{ queue_message(" type 'bglist' to see running jobs");
queue_message ("bgkill: usage 'bgkill <job number>'"); return -1;
queue_message (" type 'bglist' to see running jobs"); }
return -1;
}
int job_id = atoi (argv[1]); int job_id = atoi(argv[1]);
job j = job_with_id (job_id); job j = job_with_id(job_id);
if (!j) if (!j) {
{ queue_message(YELLOW "Invalid job number");
queue_message (YELLOW "Invalid job number"); queue_message("(type 'bglist' to see running jobs)");
queue_message ("(type 'bglist' to see running jobs)"); return -1;
return -1; }
}
kill (j->pid, SIGTERM); kill(j->pid, SIGTERM);
/*delete_job (j);*/ /*delete_job (j);*/
/* queue_message ("Job killed");*/ /* queue_message ("Job killed");*/
return 1; return 1;
} }
int builtin_bglist ( void ) int builtin_bglist(void) {
{ int num_jobs;
int num_jobs; if (!(num_jobs = get_num_jobs()))
if ( !(num_jobs = get_num_jobs()) ) return 0;
return 0;
job j; job j;
char *message = (char *)myxmalloc (MSGLEN); char *message = (char *)myxmalloc(MSGLEN);
for (j = get_job_list(); j; j = j->next) for (j = get_job_list(); j; j = j->next) {
{ snprintf(message, MSGLEN, YELLOW "%i" WHITE ": (pid %i)" YELLOW " %s" CLEAR, j->id, j->pid, j->cmdline);
snprintf (message, MSGLEN, queue_message(message);
YELLOW "%i" WHITE ": (pid %i)" YELLOW " %s" CLEAR, }
j->id, j->pid, j->cmdline); snprintf(message, MSGLEN, GREEN "Total: %i background job(s) running" CLEAR, num_jobs);
queue_message (message); queue_message(message);
} free(message);
snprintf (message, MSGLEN, return num_jobs;
GREEN "Total: %i background job(s) running" CLEAR, num_jobs);
queue_message (message);
free (message);
return num_jobs;
} }
int builtin_cd ( int argc, char **argv ) int builtin_cd(int argc, char **argv) {
{ static char *lastdir = NULL;
static char *lastdir = NULL; char *dir, *pwd = getcwd(NULL, 0);
char *dir, *pwd = getcwd(NULL, 0);
if (!lastdir) /* initialize */ if (!lastdir) /* initialize */
lastdir = pwd; lastdir = pwd;
if ( argc < 2 ) /* cd w/ no args acts like cd $HOME */ if (argc < 2) /* cd w/ no args acts like cd $HOME */
dir = getenv("HOME"); dir = getenv("HOME");
else else {
{ if (!strncmp(argv[1], "-", 1))
if ( !strncmp(argv[1], "-", 1) ) dir = lastdir; /* cd - changes to previous dir */
dir = lastdir; /* cd - changes to previous dir */ else
else dir = argv[1];
dir = argv[1]; }
}
if ( chdir (dir) < 0 ) if (chdir(dir) < 0) { /* error */
{ /* error */ size_t len = strlen(dir);
size_t len = strlen (dir); char *message = (char *)myxmalloc(len + MSGLEN);
char *message = (char *)myxmalloc (len + MSGLEN); (void)snprintf(message, len + MSGLEN, RED "cd: %s: %s" CLEAR, strerror(errno), dir);
(void) snprintf (message, len + MSGLEN, queue_message(message);
RED "cd: %s: %s" CLEAR, strerror (errno), dir); free(message);
queue_message (message); return -1;
free (message); }
return -1;
}
/* save the last dir for cd -, if it's different */ /* save the last dir for cd -, if it's different */
if ( strcmp(pwd, dir) ) if (strcmp(pwd, dir))
lastdir = pwd; lastdir = pwd;
return 1; return 1;
} }
void builtin_clear ( void ) void builtin_clear(void) { printf("\033[2J"); }
{
printf ("\033[2J");
}
void builtin_pwd ( void ) void builtin_pwd(void) {
{ char *pwd = getcwd(NULL, 0);
char *pwd = getcwd(NULL, 0); queue_message(pwd);
queue_message (pwd); xfree(pwd);
xfree (pwd);
} }

View file

@ -9,9 +9,9 @@
* $Id: builtins.h 184 2006-01-29 08:53:30Z sjs $ * $Id: builtins.h 184 2006-01-29 08:53:30Z sjs $
*/ */
int builtin_bg ( int argc, char **argv ); int builtin_bg(int argc, char **argv);
int builtin_bgkill ( int argc, char **argv ); int builtin_bgkill(int argc, char **argv);
int builtin_bglist ( void ); int builtin_bglist(void);
int builtin_cd ( int argc, char **argv ); int builtin_cd(int argc, char **argv);
void builtin_clear ( void ); void builtin_clear(void);
void builtin_pwd ( void ); void builtin_pwd(void);

129
c/exec.c
View file

@ -12,87 +12,76 @@
/*#define _GNU_SOURCE*/ /*#define _GNU_SOURCE*/
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> /* waitpid */ #include <sys/types.h> /* waitpid */
#include <sys/wait.h> /* waitpid */ #include <sys/wait.h> /* waitpid */
#include <unistd.h> #include <unistd.h>
#include "exec.h" #include "exec.h"
#include "utils.h"
#include "main.h" #include "main.h"
#include "utils.h"
char *is_executable ( char *file ) char *is_executable(char *file) {
{ if (strchr(file, '/')) { /* process absolute and relative paths directly */
if ( strchr (file, '/') ) if (access(file, X_OK) == 0)
{ /* process absolute and relative paths directly */ return strdup(file);
if ( access (file, X_OK) == 0 ) else
return strdup (file); return NULL;
else }
return NULL;
}
char *path = strdup ( getenv ("PATH") ); char *path = strdup(getenv("PATH"));
int file_len = strlen (file); int file_len = strlen(file);
char *dir = strtok (path, ":"); char *dir = strtok(path, ":");
char *filename = NULL; char *filename = NULL;
while ( dir ) while (dir) {
{ filename = (char *)myxmalloc(strlen(dir) + file_len + 2);
filename = (char *)myxmalloc (strlen (dir) + file_len + 2); sprintf(filename, "%s/%s", dir, file);
sprintf (filename, "%s/%s", dir, file); if (access(filename, X_OK) == 0)
if ( access (filename, X_OK) == 0 ) break;
break; free(filename);
free (filename); filename = NULL;
filename = NULL; dir = strtok(NULL, ":");
dir = strtok (NULL, ":"); }
} xfree(path);
xfree (path); return filename;
return filename;
} }
pid_t exec_command ( char **argv, int background ) pid_t exec_command(char **argv, int background) {
{ int status;
int status; pid_t pid;
pid_t pid; char *filename;
char *filename;
if ( !(filename = is_executable (argv[0])) ) if (!(filename = is_executable(argv[0]))) { /* error, not executable */
{ /* error, not executable */ char *msg = (char *)myxmalloc(MSGLEN);
char *msg = (char *)myxmalloc (MSGLEN); sprintf(msg, RED "%s: %s" CLEAR, argv[0], strerror(errno));
sprintf (msg, RED "%s: %s" CLEAR, argv[0], strerror (errno)); queue_message(msg);
queue_message (msg); free(msg);
free (msg); return -1;
return -1; }
}
if ( (pid = fork()) > 0 ) if ((pid = fork()) > 0) { /* parent */
{ /* parent */ if (background)
if ( background ) waitpid(pid, &status, WNOHANG);
waitpid (pid, &status, WNOHANG); else
else waitpid(pid, &status, 0);
waitpid (pid, &status, 0); } else if (pid == 0) { /* child */
} /* kludge, briefly wait for the job to be created so that if the
else if ( pid == 0 ) * command exits quickly, the job is found and removed. otherwise there
{ /* child */ * are zombie jobs erroneously lying around. note, this isn't guaranteed
/* kludge, briefly wait for the job to be created so that if the * to work, it just seems to be enough time in tests here.
* command exits quickly, the job is found and removed. otherwise there */
* are zombie jobs erroneously lying around. note, this isn't guaranteed usleep(100);
* to work, it just seems to be enough time in tests here. execv(filename, argv);
*/
usleep (100);
execv (filename, argv);
/* if we get here there was an error, display it */ /* if we get here there was an error, display it */
printf (RED "\nCannot execute '%s' (%s)\n" CLEAR, argv[0], printf(RED "\nCannot execute '%s' (%s)\n" CLEAR, argv[0], strerror(errno));
strerror(errno)); free(filename);
free (filename); _exit(EXIT_FAILURE);
_exit (EXIT_FAILURE); } else { /* error, pid < 0 */
} queue_message(RED "Unable to fork(), uh oh..." CLEAR);
else }
{ /* error, pid < 0 */ free(filename);
queue_message (RED "Unable to fork(), uh oh..." CLEAR); return pid;
}
free (filename);
return pid;
} }

View file

@ -11,4 +11,4 @@
/* execute the command argv[0], with arg list argv[], background can be /* execute the command argv[0], with arg list argv[], background can be
* non-zero to run the task in the background under our limited job control */ * non-zero to run the task in the background under our limited job control */
pid_t exec_command ( char **argv, int background ); pid_t exec_command(char **argv, int background);

180
c/jobs.c
View file

@ -24,120 +24,102 @@ static job job_list_head = NULL;
static int num_jobs = 0; static int num_jobs = 0;
static int next_id = 1; static int next_id = 1;
static int get_next_id ( void ) static int get_next_id(void) {
{ while (job_with_id(next_id))
while ( job_with_id (next_id) ) next_id++;
next_id++; return next_id++;
return next_id++;
} }
job add_job ( pid_t pid, char **argv ) job add_job(pid_t pid, char **argv) {
{ job i, j = (job)myxmalloc(sizeof(struct job));
job i, j = (job)myxmalloc (sizeof (struct job)); j->id = get_next_id();
j->id = get_next_id(); j->pid = pid;
j->pid = pid; j->cmdline = array_cat(argv);
j->cmdline = array_cat (argv); if (DEBUG)
if (DEBUG) printf("DEBUG: cmdline='%s'\n", j->cmdline);
printf("DEBUG: cmdline='%s'\n", j->cmdline); j->next = NULL;
j->next = NULL; j->prev = NULL;
j->prev = NULL;
for (i = job_list_head; i && i->next; i = i->next) for (i = job_list_head; i && i->next; i = i->next) { /* insert jobs in job_id order */
{ /* insert jobs in job_id order */ if (i->id > j->id) { /* insert BEFORE i */
if ( i->id > j->id ) if (DEBUG)
{ /* insert BEFORE i */ printf("DEBUG: i=%i, i->next=%i, i->prev=%p\n", i->id, i->next->id, i->prev);
if (DEBUG) j->next = i;
printf("DEBUG: i=%i, i->next=%i, i->prev=%p\n", i->id, i->next->id, i->prev); j->prev = i->prev;
j->next = i; if (i->prev)
j->prev = i->prev; i->prev->next = j;
if (i->prev) i->prev = j;
i->prev->next = j;
i->prev = j;
if ( job_list_head == i ) if (job_list_head == i)
job_list_head = j; job_list_head = j;
break; break;
} }
} }
if ( i == NULL ) /* empty list */ if (i == NULL) /* empty list */
{ {
if (DEBUG) if (DEBUG)
printf("DEBUG: i=%p, job_list_head=%p\n", i, job_list_head); printf("DEBUG: i=%p, job_list_head=%p\n", i, job_list_head);
job_list_head = j; job_list_head = j;
} } else if (!i->next) /* at the end, i->next == NULL */
else if ( !i->next ) /* at the end, i->next == NULL */ { /* at this point, append the new job to the end of the list */
{ /* at this point, append the new job to the end of the list */ if (DEBUG)
if (DEBUG) printf("DEBUG: i=%i\n", i->id);
printf("DEBUG: i=%i\n", i->id); i->next = j;
i->next = j; j->prev = i;
j->prev = i; }
} if (DEBUG)
if (DEBUG) printf("DEBUG: job added: (%i,%i)\n", j->id, j->pid);
printf("DEBUG: job added: (%i,%i)\n", j->id, j->pid); num_jobs++;
num_jobs++; return j;
return j;
} }
void delete_job ( job j ) void delete_job(job j) {
{ next_id = MIN(next_id, j->id); /* prefer the lower id */
next_id = MIN(next_id, j->id); /* prefer the lower id */
if ( j == job_list_head ) if (j == job_list_head) {
{ if (j->next)
if (j->next) job_list_head = j->next;
job_list_head = j->next; else
else job_list_head = NULL;
job_list_head = NULL; }
} if (j->prev)
if (j->prev) j->prev->next = j->next;
j->prev->next = j->next; if (j->next)
if (j->next) j->next->prev = j->prev;
j->next->prev = j->prev;
if (DEBUG) if (DEBUG)
printf("DEBUG: str=%p\n", j->cmdline); printf("DEBUG: str=%p\n", j->cmdline);
xfree (j->cmdline); xfree(j->cmdline);
xfree (j); xfree(j);
num_jobs--; num_jobs--;
} }
void free_job_list ( void ) void free_job_list(void) {
{ while (job_list_head)
while ( job_list_head ) delete_job(job_list_head);
delete_job ( job_list_head );
} }
job job_with_id ( int job_id ) job job_with_id(int job_id) {
{ job j;
job j; for (j = job_list_head; j; j = j->next) {
for (j = job_list_head; j; j = j->next) /* printf("DEBUG: id=%i, j=%p:%i:%i\n", job_id, j, j->id, j->pid); */
{ if (j->id == job_id)
/* printf("DEBUG: id=%i, j=%p:%i:%i\n", job_id, j, j->id, j->pid); */ return j;
if (j->id == job_id) }
return j; return NULL;
}
return NULL;
} }
job job_with_pid ( pid_t pid ) job job_with_pid(pid_t pid) {
{ job j;
job j; for (j = job_list_head; j; j = j->next) {
for (j = job_list_head; j; j = j->next) printf("DEBUG: pid=%i, j=%p:%i:%i\n", pid, j, j->id, j->pid);
{ if (j->pid == pid)
printf("DEBUG: pid=%i, j=%p:%i:%i\n", pid, j, j->id, j->pid); return j;
if (j->pid == pid) }
return j; return NULL;
}
return NULL;
} }
job get_job_list ( void ) job get_job_list(void) { return job_list_head; }
{
return job_list_head;
}
int get_num_jobs ( void ) int get_num_jobs(void) { return num_jobs; }
{
return num_jobs;
}

View file

@ -12,18 +12,18 @@
#include <stdlib.h> #include <stdlib.h>
struct job { struct job {
int id; int id;
pid_t pid; pid_t pid;
char *cmdline; char *cmdline;
struct job *next; struct job *next;
struct job *prev; struct job *prev;
}; };
typedef struct job *job; typedef struct job *job;
job add_job ( pid_t pid, char **argv ); job add_job(pid_t pid, char **argv);
void delete_job ( job j ); void delete_job(job j);
void free_job_list ( void ); void free_job_list(void);
int get_num_jobs ( void ); int get_num_jobs(void);
job get_job_list ( void ); job get_job_list(void);
job job_with_id ( int job_id ); job job_with_id(int job_id);
job job_with_pid ( pid_t pid ); job job_with_pid(pid_t pid);

429
c/main.c
View file

@ -11,271 +11,262 @@
/*#define _GNU_SOURCE*/ /*#define _GNU_SOURCE*/
#include <assert.h> /* This must be included before readline or FILE won't be defined. */
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <assert.h>
#include <readline/history.h>
#include <readline/readline.h>
#include <signal.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <unistd.h> #include <unistd.h>
#include <wordexp.h> #include <wordexp.h>
#include "utils.h"
#include "jobs.h"
#include "exec.h"
#include "builtins.h" #include "builtins.h"
#include "exec.h"
#include "jobs.h"
#include "utils.h"
#define MAX(a, b) (a) > (b) ? (a) : (b) #define MAX(a, b) ((a) > (b) ? (a) : (b))
#define PROMPT BLUE "%s" WHITE "%% " CLEAR /* looks like this: /path/to/somewhere% */
#define INVALID_CHARS "&|;<>" /* for wordexp */ /* looks like this: /path/to/somewhere% */
#define PROMPT BLUE "%s" WHITE "%% " CLEAR
/* for wordexp */
#define INVALID_CHARS "&|;<>"
struct message { struct message {
char *data; char *data;
struct message *next; struct message *next;
}; };
typedef struct message *message; typedef struct message *message;
static message msg_queue_head = NULL; /* message queue */ static message msg_queue_head = NULL; /* message queue */
void queue_message ( char *msg ) /** queue messages so they don't mix with a running program's output
{ /* queue messages so they don't mix with a running program's output * instead they're only displayed while waiting on input w/ readline
* instead they're only displayed while waiting on input w/ readline * message m: freed in print_messages()
* message m: freed in print_messages() */
*/ void queue_message(char *msg) {
message i, m = (message)myxmalloc (sizeof (struct message)); message i, m = (message)myxmalloc(sizeof(struct message));
m->data = strdup (msg); m->data = strdup(msg);
m->next = NULL; m->next = NULL;
for (i = msg_queue_head; i && i->next; i = i->next) for (i = msg_queue_head; i && i->next; i = i->next)
; ;
if (!i) /* if i is NULL, then i == msg_queue_head == NULL */ if (!i) /* if i is NULL, then i == msg_queue_head == NULL */
msg_queue_head = m; msg_queue_head = m;
else /* queue m */ else /* queue m */
i->next = m; i->next = m;
} }
void free_message_queue ( void ) void free_message_queue(void) {
{ message m, n = msg_queue_head;
message m, n = msg_queue_head; while ((m = n)) {
while ( (m = n) ) n = m->next;
{ xfree(m->data);
n = m->next; free(m);
xfree (m->data); }
free (m); msg_queue_head = NULL;
}
msg_queue_head = NULL;
} }
int print_messages ( void ) int print_messages(void) {
{ if (!msg_queue_head)
if (!msg_queue_head) return 0;
return 0;
/* there must be an easier way to interrupt readline... */ /* there must be an easier way to interrupt readline... */
char *old = rl_line_buffer; char *old = rl_line_buffer;
rl_line_buffer = strdup (""); rl_line_buffer = strdup("");
rl_save_prompt(); rl_save_prompt();
rl_clear_message(); rl_clear_message();
message m; message m;
for (m = msg_queue_head; m; m = m->next) for (m = msg_queue_head; m; m = m->next)
printf (WHITE "%s\n" CLEAR, m->data); printf(WHITE "%s\n" CLEAR, m->data);
free_message_queue (); free_message_queue();
xfree (rl_line_buffer); xfree(rl_line_buffer);
rl_line_buffer = old; rl_line_buffer = old;
rl_restore_prompt(); rl_restore_prompt();
rl_forced_update_display(); rl_forced_update_display();
return 1; return 1;
} }
char *strsignal ( int status ) /* like strerror for waitpid */
{ /* like strerror for waitpid */ char *strsignal(int status) {
char *str = (char *)myxmalloc (MSGLEN); char *str = (char *)myxmalloc(MSGLEN);
if ( WIFEXITED(status) ) if (WIFEXITED(status)) {
{ if (WEXITSTATUS(status)) /* non-zero exit status */
if ( WEXITSTATUS(status) ) /* non-zero exit status */ sprintf(str, RED "exit %i", WEXITSTATUS(status));
sprintf (str, RED "exit %i", WEXITSTATUS(status)); else /* clean exit */
else /* clean exit */ sprintf(str, GREEN "done");
sprintf (str, GREEN "done"); }
} if (WIFSIGNALED(status)) {
if ( WIFSIGNALED(status) ) switch (WTERMSIG(status)) {
{ case SIGTERM:
switch ( WTERMSIG(status) ) sprintf(str, RED "terminated");
{ break;
case SIGTERM:
sprintf (str, RED "terminated");
break;
case SIGKILL: case SIGKILL:
sprintf (str, RED "killed"); sprintf(str, RED "killed");
break; break;
case SIGPIPE: case SIGPIPE:
sprintf (str, RED "broken pipe"); sprintf(str, RED "broken pipe");
break; break;
case SIGSEGV: case SIGSEGV:
sprintf (str, RED "segmentation fault"); sprintf(str, RED "segmentation fault");
break; break;
case SIGABRT: case SIGABRT:
sprintf (str, RED "aborted"); sprintf(str, RED "aborted");
break; break;
default: default:
sprintf (str, RED "signal %i", WTERMSIG(status)); sprintf(str, RED "signal %i", WTERMSIG(status));
break; break;
} }
} }
return str; return str;
} }
void child_state_changed ( int signum ) /* handler for SIGCHLD when a child's state changes */
{ /* handler for SIGCHLD when a child's state changes */ void child_state_changed(int signum) {
int status; int status;
pid_t pid; pid_t pid;
/* linux resets the sighandler after each call */ /* linux resets the sighandler after each call */
signal (SIGCHLD, child_state_changed); signal(SIGCHLD, child_state_changed);
pid = waitpid (-1, &status, WNOHANG); pid = waitpid(-1, &status, WNOHANG);
job j = job_with_pid (pid); job j = job_with_pid(pid);
if (j) if (j) {
{ char *strstatus = strsignal(status);
char *strstatus = strsignal (status); /* alert the user of the termination, and delete the job */
/* alert the user of the termination, and delete the job */ size_t len = strlen(j->cmdline);
size_t len = strlen (j->cmdline); char *msg = (char *)myxmalloc(len + MSGLEN);
char *msg = (char *)myxmalloc (len + MSGLEN); snprintf(msg, len + MSGLEN, YELLOW "%i" WHITE ": (pid %i) %s" YELLOW ": %s" CLEAR, j->id, j->pid, strstatus, j->cmdline);
snprintf (msg, len + MSGLEN, queue_message(msg);
YELLOW "%i" WHITE ": (pid %i) %s" YELLOW ": %s" CLEAR, xfree(msg);
j->id, j->pid, strstatus, j->cmdline); xfree(strstatus);
queue_message (msg); delete_job(j);
xfree (msg); }
xfree (strstatus);
delete_job (j);
}
} }
char *get_prompt ( void ) /* display the pwd in the prompt */
{ /* display the pwd in the prompt */ char *get_prompt(void) {
char *pwd, *prompt; char *pwd, *prompt;
pwd = getcwd(NULL, 0); pwd = getcwd(NULL, 0);
size_t len = strlen (pwd) + strlen (PROMPT); size_t len = strlen(pwd) + strlen(PROMPT);
prompt = (char *)myxmalloc (len); prompt = (char *)myxmalloc(len);
snprintf (prompt, len, PROMPT, pwd); snprintf(prompt, len, PROMPT, pwd);
xfree (pwd); xfree(pwd);
return prompt; return prompt;
} }
int cmd_matches ( char *trigger, char *cmd ) int cmd_matches(char *trigger, char *cmd) { return !strcmp(trigger, cmd); }
{
return !strcmp (trigger, cmd); int handle_wordexp_result(int result, char *cmd) {
switch (result) {
case WRDE_BADCHAR:
/* gcc chokes if the int decl is first, lame */
;
int invalid_char = strcspn(cmd, INVALID_CHARS);
char *msg = (char *)myxmalloc(strlen(cmd) + MSGLEN);
int i;
for (i = 0; i < invalid_char; i++)
*(msg + i) = ' ';
sprintf(msg + invalid_char, RED "^ invalid character in column %i", invalid_char + 1);
queue_message(cmd);
queue_message(msg);
xfree(msg);
result = 0;
break;
case WRDE_BADVAL:
queue_message("undefined variable");
result = 0;
break;
case WRDE_CMDSUB:
queue_message("no command substitution allowed");
result = 0;
break;
case WRDE_NOSPACE:
queue_message("not enough memory");
result = 0;
break;
case WRDE_SYNTAX:
queue_message("syntax error");
result = 0;
break;
default:
/* success */
result = 1;
}
return result;
} }
int handle_wordexp_result ( int result, char *cmd ) void repl_start(void) {
{ for (;;) {
switch (result) char *prompt = get_prompt();
{ char *cmd = readline(prompt);
case WRDE_BADCHAR: xfree(prompt);
; /* gcc chokes if the int decl is first, lame */
int invalid_char = strcspn (cmd, INVALID_CHARS); if (!cmd) /* exit if we get an EOF, which returns NULL */
char *msg = (char *)myxmalloc (strlen (cmd) + MSGLEN); break;
int i;
for (i = 0; i < invalid_char; i++) wordexp_t words;
*(msg + i) = ' '; int result = wordexp(cmd, &words, WRDE_SHOWERR);
sprintf (msg + invalid_char, if (handle_wordexp_result(result, cmd) && words.we_wordc > 0) {
RED "^ invalid character in column %i", invalid_char + 1); if (DEBUG) {
queue_message (cmd); int i;
queue_message (msg); printf("DEBUG: args = { ");
xfree (msg); for (i = 0; i < words.we_wordc; i++)
result = 0; printf("'%s', ", words.we_wordv[i]);
break; printf("}\n");
case WRDE_BADVAL: }
queue_message ("undefined variable"); /* try the built-in commands */
result = 0; if (cmd_matches("bg", words.we_wordv[0]))
break; builtin_bg(words.we_wordc, words.we_wordv);
case WRDE_CMDSUB: else if (cmd_matches("bgkill", words.we_wordv[0]))
queue_message ("no command substitution allowed"); builtin_bgkill(words.we_wordc, words.we_wordv);
result = 0; else if (cmd_matches("bglist", words.we_wordv[0]))
break; builtin_bglist();
case WRDE_NOSPACE: else if (cmd_matches("cd", words.we_wordv[0]))
queue_message ("not enough memory"); builtin_cd(words.we_wordc, words.we_wordv);
result = 0; else if (cmd_matches("clear", words.we_wordv[0]))
break; builtin_clear();
case WRDE_SYNTAX: else if (cmd_matches("pwd", words.we_wordv[0]))
queue_message ("syntax error"); builtin_pwd();
result = 0; else if (cmd_matches("exit", words.we_wordv[0])) { /* quick clean-up, then break */
break; wordfree(&words);
default: free(cmd);
/* success */ break;
result = 1; } else /* default to trying to execute the cmd line */
} exec_command(words.we_wordv, 0);
return result;
add_history(cmd); /* add to the readline history */
wordfree(&words);
} /* if handle_wordexp_result (result) */
free(cmd);
} /* for (;;) */
} }
int main ( void ) int main(int argc, char *argv[]) {
{ signal(SIGCHLD, child_state_changed); /* catch SIGCHLD */
signal (SIGCHLD, child_state_changed); /* catch SIGCHLD */
/* while waiting for input, display messasges */ /* while waiting for input, display messasges */
rl_event_hook = print_messages; rl_event_hook = print_messages;
/* register clean-up function */ /* register clean-up function */
atexit (free_job_list); atexit(free_job_list);
atexit (free_message_queue); atexit(free_message_queue);
for (;;) repl_start();
{
char *prompt = get_prompt();
char *cmd = readline (prompt);
xfree (prompt);
if (!cmd) /* exit if we get an EOF, which returns NULL */ return 0;
break;
wordexp_t words;
int result = wordexp (cmd, &words, WRDE_SHOWERR);
if ( handle_wordexp_result (result, cmd) && words.we_wordc > 0 )
{
if (DEBUG)
{
int i;
printf("DEBUG: args = { ");
for (i = 0; i < words.we_wordc; i++)
printf ("'%s', ", words.we_wordv[i]);
printf ("}\n");
}
/* try the built-in commands */
if ( cmd_matches ("bg", words.we_wordv[0]) )
builtin_bg ( words.we_wordc, words.we_wordv );
else if ( cmd_matches ("bgkill", words.we_wordv[0]) )
builtin_bgkill ( words.we_wordc, words.we_wordv );
else if ( cmd_matches ("bglist", words.we_wordv[0]) )
builtin_bglist ();
else if ( cmd_matches ("cd", words.we_wordv[0]) )
builtin_cd ( words.we_wordc, words.we_wordv );
else if ( cmd_matches ("clear", words.we_wordv[0]) )
builtin_clear ();
else if ( cmd_matches ("pwd", words.we_wordv[0]) )
builtin_pwd ();
else if ( cmd_matches ("exit", words.we_wordv[0]) )
{ /* quick clean-up, then break */
wordfree (&words);
free (cmd);
break;
}
else /* default to trying to execute the cmd line */
exec_command (words.we_wordv, 0);
add_history (cmd); /* add to the readline history */
wordfree (&words);
} /* if handle_wordexp_result (result) */
free (cmd);
} /* for (;;) */
return 0;
} }

View file

@ -9,4 +9,4 @@
* $Id: main.h 183 2006-01-27 11:24:52Z sjs $ * $Id: main.h 183 2006-01-27 11:24:52Z sjs $
*/ */
void queue_message ( char *message ); void queue_message(char *message);

View file

@ -9,72 +9,66 @@
* $Id: utils.c 184 2006-01-29 08:53:30Z sjs $ * $Id: utils.c 184 2006-01-29 08:53:30Z sjs $
*/ */
#include "utils.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "utils.h"
char *array_cat ( char **array ) char *array_cat(char **array) {
{ char *p = NULL, *str = NULL;
char *p = NULL, *str = NULL; int i, pos = 0;
int i, pos = 0; for (i = 0; array[i]; i++) {
for (i = 0; array[i]; i++) if (DEBUG)
{ printf("DEBUG: array[%i]=%p:'%s'\n", i, array[i], array[i]);
if (DEBUG) int len = strlen(array[i]);
printf("DEBUG: array[%i]=%p:'%s'\n", i, array[i], array[i]); str = (char *)myxrealloc(str, pos + len + 1);
int len = strlen (array[i]); p = str + pos;
str = (char *)myxrealloc (str, pos + len + 1); memcpy(p, array[i], len);
p = str + pos;
memcpy (p, array[i], len);
p += len; p += len;
*p++ = ' '; *p++ = ' ';
pos += len + 1; pos += len + 1;
} }
*--p = '\0'; *--p = '\0';
if (DEBUG) if (DEBUG)
printf("DEBUG: str=%p\n", str); printf("DEBUG: str=%p\n", str);
return str; return str;
} }
void free_array ( void **array ) void free_array(void **array) {
{ int i = 0;
int i = 0;
if (!array) if (!array)
return; return;
while ( array[i] ) while (array[i])
free (array[i++]); free(array[i++]);
free (array); free(array);
} }
void *myxmalloc ( size_t size ) void *myxmalloc(size_t size) {
{ void *ptr = malloc(size);
void *ptr = malloc (size); if (ptr)
if (ptr) return ptr;
return ptr;
printf(RED "Out of memory, bailing!\n" CLEAR); printf(RED "Out of memory, bailing!\n" CLEAR);
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void *myxrealloc( void *ptr, size_t size ) void *myxrealloc(void *ptr, size_t size) {
{ void *new_ptr = realloc(ptr, size);
void *new_ptr = realloc (ptr, size); if (new_ptr)
if (new_ptr) return new_ptr;
return new_ptr;
printf(RED "Out of memory, bailing!\n" CLEAR); printf(RED "Out of memory, bailing!\n" CLEAR);
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void **array_realloc ( void **array, size_t size ) void **array_realloc(void **array, size_t size) {
{ void **ptr = realloc(array, size * sizeof(void *));
void **ptr = realloc (array, size * sizeof (void *)); if (ptr)
if (ptr) return ptr;
return ptr;
free_array (array); free_array(array);
printf (RED "Out of memory, bailing!\n" CLEAR); printf(RED "Out of memory, bailing!\n" CLEAR);
exit (EXIT_FAILURE); exit(EXIT_FAILURE);
} }

View file

@ -11,29 +11,31 @@
#include <stdlib.h> #include <stdlib.h>
#define DEBUG 1 #define DEBUG 1
#define MSGLEN 255 /* soft limit on message lengths */ #define MSGLEN 255 /* soft limit on message lengths */
/* these colours should be safe on dark and light backgrounds */ /* these colours should be safe on dark and light backgrounds */
#define BLUE "\033[1;34m" #define BLUE "\033[1;34m"
#define GREEN "\033[1;32m" #define GREEN "\033[1;32m"
#define YELLOW "\033[1;33m" #define YELLOW "\033[1;33m"
#define RED "\033[1;31m" #define RED "\033[1;31m"
#define WHITE "\033[1;37m" #define WHITE "\033[1;37m"
#define CLEAR "\033[0;m" #define CLEAR "\033[0;m"
/* free an array/list's elements (then the array itself) */ /* free an array/list's elements (then the array itself) */
void free_array ( void **array ); void free_array(void **array);
/* concatenate an array of strings, adding space between words */ /* concatenate an array of strings, adding space between words */
char *array_cat ( char **array ); char *array_cat(char **array);
/* safe malloc & realloc, they exit on failure */ /* safe malloc & realloc, they exit on failure */
void *myxmalloc ( size_t size ); void *myxmalloc(size_t size);
void *myxrealloc ( void *ptr, size_t size ); void *myxrealloc(void *ptr, size_t size);
#define xfree(ptr) if (ptr) free (ptr); #define xfree(ptr) \
if (ptr) \
free(ptr);
/* this takes n_elems of the original array, in case of failure it will /* this takes n_elems of the original array, in case of failure it will
* free_array (n_elems, array) before exiting */ * free_array (n_elems, array) before exiting */
void **array_realloc ( void **array, size_t size ); void **array_realloc(void **array, size_t size);