#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <dirent.h>
#include <pwd.h>
#include <errno.h>
#include "proto.h"
#define BUF_SIZE 256
static int expLiteralChars(char *orig, char *new, int *oldl_ind, int *newl_ind, int *insideQuoteFlag)
{
if(orig[*oldl_ind] == '"') *insideQuoteFlag = !(*insideQuoteFlag);
new[*newl_ind] = orig[*oldl_ind];
(*newl_ind)++;
(*oldl_ind)++;
return 0;
}
static int expEnvVars(char *orig, char *new, int *oldl_ind, int *newl_ind)
{
char *envValue;
int envNameLen = 0;
(*oldl_ind)++;
while(orig[*oldl_ind + envNameLen] != '}')
{
if(orig[*oldl_ind + envNameLen] == 0 || orig[*oldl_ind + envNameLen] == '$')
{
fprintf(stderr, "msh: no matching }\n");
return 1;
}
envNameLen++;
}
orig[*oldl_ind + envNameLen] = 0;
envValue = getenv(&(orig[*oldl_ind]));
if(envValue != NULL)
{
strcpy(&(new[*newl_ind]), envValue);
*newl_ind = *newl_ind + strlen(envValue);
}
*oldl_ind = *oldl_ind + envNameLen + 1;
// envNameLen = 0;
return 0;
}
static int expShPid(char *orig, char *new, int *oldl_ind, int *newl_ind)
{
char pidBuff[8];
int pid = (int)getpid();
int i = 0;
if(sprintf(pidBuff, "%d", pid) > -1)
{
while(pidBuff[i])
{
new[*newl_ind] = pidBuff[i++];
(*newl_ind)++;
}
(*oldl_ind)++;
return 0;
}
return 1;
}
static int expMainArgs(char *orig, char *new, int *oldl_ind, int *newl_ind) //, int mainargc, char **mainargv, char **shiftedMArgV)
{
int argInd;
int argLen;
char tempChar;
char *argIndStr = &(orig[*oldl_ind]);
while(isdigit(orig[*oldl_ind])) (*oldl_ind)++;
tempChar = orig[(*oldl_ind)];
orig[*oldl_ind] = 0;
argInd = atoi(argIndStr);
orig[*oldl_ind] = tempChar;
if(m_argc == 1)
{
if(argInd >= m_shifted_argc) return 0;
argLen = strlen(m_argv[0]);
strcpy(&(new[*newl_ind]), m_argv[0]);
}
else
{
if((argInd+1) >= m_shifted_argc) return 0;
if(argInd == 0)
{
argLen = strlen(m_argv[1]);
strcpy(&(new[*newl_ind]), m_argv[1]);
}
else
{
argLen = strlen(m_shifted_argv[argInd+1]);
strcpy(&(new[*newl_ind]), m_shifted_argv[argInd+1]);
}
}
*newl_ind = *newl_ind + argLen;
return 0;
}
static int expMainCount(char *new, int *newl_ind) //, int mainargc)
{
int argStrLen;
int offset = 1;
if(m_argc == 1) offset = 0;
argStrLen = sprintf(&(new[*newl_ind]), "%d", (m_shifted_argc - offset));
*newl_ind = *newl_ind + argStrLen;
return 0;
}
static int expLastExitS(char *new, int *newl_ind)
{
int exStatStrLen = sprintf(&(new[*newl_ind]), "%d", (last_exit_status));
*newl_ind = *newl_ind + exStatStrLen;
return 0;
}
static int expWildCard(char *orig, char *new, int *oldl_ind, int *newl_ind, int filterFlag)
{
int i;
int dirLen;
int matchCount = 0;
int passedFilterFlag = 0;
int dirNameStrLen;
char *dirName;
char *filterStr;
char tempChar;
struct dirent **namelist;
/* GET ALL THE DIRECTORIES AND PUT THEM IN namelist */
dirLen = scandir(".", &namelist, 0, alphasort);
if(dirLen < 0)
{
perror("scandir");
return 1;
}
(*oldl_ind)++;
if(filterFlag)
{
filterStr = &(orig[*oldl_ind]);
while(orig[*oldl_ind] != ' ' && orig[*oldl_ind] != '"' && orig[*oldl_ind] != 0)
{
if(orig[*oldl_ind] == '/')
{
fprintf(stderr, "./msh: no match\n");
return 1;
}
(*oldl_ind)++;
}
tempChar = orig[*oldl_ind];
orig[*oldl_ind] = 0;
}
for(i = 0; i < dirLen; i++)
{
dirName = namelist[i]->d_name;
dirNameStrLen = strlen(dirName);
if(dirName[0] == '.')
{
passedFilterFlag = 0;
}
else if(filterFlag)
{
if(strlen(filterStr) > dirNameStrLen) passedFilterFlag = 0;
else
{
if(!strcmp(filterStr, &(dirName[dirNameStrLen - strlen(filterStr)]))) passedFilterFlag = 1;
else passedFilterFlag = 0;
}
}
else passedFilterFlag = 1;
if(passedFilterFlag)
{
matchCount++;
strcpy(&(new[*newl_ind]), dirName);
if(i != (dirLen -1))
{
*newl_ind = *newl_ind + dirNameStrLen + 1;
new[*newl_ind - 1] = ' ';
}
else *newl_ind = *newl_ind + dirNameStrLen;
}
free(namelist[i]);
}
if(!matchCount)
{
new[*newl_ind] = '*';
(*newl_ind)++;
if(filterFlag)
{
strcpy(&(new[*newl_ind]), filterStr);
*newl_ind = *newl_ind + strlen(filterStr);
}
}
if(filterFlag) orig[*oldl_ind] = tempChar;
free(namelist);
return 0;
}
static int expHomeDir(char *orig, char *new, int *oldl_ind, int *newl_ind)
{
int i = 1;
char temp;
char *name = 0;
char *hdir;
struct passwd *pwResult;
/* SEE IF NAME PRESENT AFTER ~ AND PUT NULL TERMINATOR AT END IF THERE IS
IF NOT USE getlogin */
while(orig[*oldl_ind + i] != ' ' && orig[*oldl_ind + i] != '/' && orig[*oldl_ind + i] != 0) i++;
temp = orig[*oldl_ind +i];
if(i == 1) name = getlogin();
else
{
orig[*oldl_ind + i] = 0;
name = &(orig[*oldl_ind + 1]);
}
/* GET PASSWD RESULTS, REPLACE NULL(OR NOTHING) WITH TEMP */
pwResult = getpwnam(name);
orig[*oldl_ind + i] = temp;
/* UPDATE IND'S. IF THERE ARE NO PASSWD RESULTS, LEAVE LITERAL
TILDA, OTHERWISE COPY HOME FOLDER TO NEW. */
if(!pwResult)
{
new[*newl_ind] = '~';
*oldl_ind = *oldl_ind + 1;
*newl_ind = *newl_ind + 1;
}
else
{
hdir = pwResult->pw_dir;
strcpy(&(new[*newl_ind]), hdir);
*oldl_ind = *oldl_ind + i;
*newl_ind = *newl_ind + strlen(hdir);
}
return 0;
}
static int expCmdOutput(char *orig, char *new, int *oldl_ind, int *newl_ind)
{
char buf[BUF_SIZE];
int bytes_read;
int total_bytes_read = 0;
int fd[2];
int parenthCount = 1;
int i = *oldl_ind + 1;
/* ENSURE MATCHING PARENS - REPLACE LAST PAREN WITH 0 */
while(parenthCount > 0)
{
if(orig[i] == '(') parenthCount++;
else if(orig[i] == ')') parenthCount--;
else if(orig[i] == 0)
{
fprintf(stderr, "./msh: missing )\n");
return 1;
}
i++;
}
orig[i-1] = 0;
/* PIPE, RECURSIVELY CALL PROCESSLINE(should pass 0 for 3rd arg), AND CLOSE WRITE END */
if(pipe (fd) < 0) perror("pipe");
processline(&(orig[*oldl_ind + 1]), fd[1], 0);
close(fd[1]);
/* READ OUTPUT OF COMMAND FROM READ END OF PIPE, THEN CLOSE READ END */
while((bytes_read = read(fd[0],buf,BUF_SIZE-1)))
{
if(bytes_read < 0)
{
if(errno == EWOULDBLOCK || errno == EAGAIN) continue;
else if(errno == EINTR) fprintf(stderr, "WE GOT AN EINTR SIGNAL\n");
else
{
perror("read");
break; // Or should this be exit?
}
}
else if(bytes_read > 0) total_bytes_read += bytes_read;
}
buf[total_bytes_read] = 0;
close(fd[0]);
/* REPLACE ORIGINAL MATCHING PAREN, UPDATE oldl_ind */
orig[i-1] = ')';
*oldl_ind = i;
/* COPY OUTPUT OF COMMAND TO EXPANDED LINE, UPDATE newl_ind */
i = 0;
while(buf[i] != 0)// && buf[i] != '\n')
{
new[*newl_ind + i] = buf[i];
i++;
}
*newl_ind = *newl_ind + i;
/* REMOVING EXTRA LINES */
i = 0;
while(new[i])
{
if(new[i] == '\n') new[i] = ' ';// && new[i+1] != 0) new[i] = ' ';
i++;
}
return 0;
}
int expand(char *orig, char *new, int newsize) //, int mainargc, char **mainargv, char **shiftedMArgV)
{
int newl_ind = 0;
int oldl_ind = 0;
int insideQuoteFlag = 0;
while(orig[oldl_ind] && newl_ind < newsize)
{
if(orig[oldl_ind] == '$')
{
if(orig[++oldl_ind] == '{') { if(expEnvVars(orig, new, &oldl_ind, &newl_ind)) return 1; }
else if(orig[oldl_ind] == '(') { if(expCmdOutput(orig, new, &oldl_ind, &newl_ind)) return 1; }
else if(orig[oldl_ind] == '$') { if(expShPid(orig, new, &oldl_ind, &newl_ind)) return 1; }
else if(isdigit(orig[oldl_ind])) { if(expMainArgs(orig, new, &oldl_ind, &newl_ind)) return 1; } //, mainargc, mainargv, shiftedMArgV)) return 1; }
else if(orig[oldl_ind] == '#') {
if(expMainCount(new, &newl_ind)) return 1;
oldl_ind++;
}
else if(orig[oldl_ind] == '?') {
if(expLastExitS(new, &newl_ind)) return 1;
oldl_ind++;
}
else
{
new[newl_ind] = orig[oldl_ind - 1];
newl_ind++;
}
}
else if(orig[oldl_ind] == '*')
{
if(orig[oldl_ind-1] == ' ' || orig[oldl_ind-1] == '"' || oldl_ind == 0)
{
if(orig[oldl_ind+1] == ' ' || orig[oldl_ind+1] == '"' || orig[oldl_ind+1] == 0)
{
if(expWildCard(orig, new, &oldl_ind, &newl_ind, 0)) return 1;
}
else
{
if(expWildCard(orig, new, &oldl_ind, &newl_ind, 1)) return 1;
}
}
else if(orig[oldl_ind-1] == '\\')
{
new[newl_ind-1] = '*';
oldl_ind++;
}
else
{
/*new[newl_ind] = '*';
newl_ind++;
oldl_ind++;*/
if(expLiteralChars(orig, new, &oldl_ind, &newl_ind, &insideQuoteFlag)) return 1;
}
}
else if(orig[oldl_ind] == '#' && !insideQuoteFlag) break;
else if(orig[oldl_ind] == '~' && orig[oldl_ind-1] == ' ')
{
if(expHomeDir(orig, new, &oldl_ind, &newl_ind)) return 1;
}
else
{
/*if(orig[oldl_ind] == '"') insideQuoteFlag = !insideQuoteFlag;
new[newl_ind] = orig[oldl_ind];
newl_ind++;
oldl_ind++;*/
if(expLiteralChars(orig, new, &oldl_ind, &newl_ind, &insideQuoteFlag)) return 1;
}
}
new[newl_ind] = 0;
return 0;
}