<commit_before>/* 
 * philsh.c
 *
 * Copyright (C) 2008 <NAME> <<EMAIL>>
 * See LICENCE file for licence of this piece of software.
 *
 */

/* on inclu les headers */
#include "headers.h"

/* le chemin de l'executable par exemple /bin/echo */
char *chemin;

/* Structure des builtin commandes,
 * char *name;
 * int (*p)(int, char**);
 */
const struct builtin builtin_command[] =
{
   {"pwd", internal_pwd},
   {"which", internal_which},
   {"uname", internal_uname},
   {"env", internal_env},
   {"cd", internal_cd},
   {"whoami", whoami},
   {"alias", alias},
   {NULL, NULL}
};

/* Cette fonction initialise l'environnement
 * Si $HOME et $PATH n'existent pas, il faut
 * les créer... En effet, si on lance le programme
 * comme ceci : env -i philsh, tous les getenv()
 * retournent NULL */
void init_env(void)
{
   /* L'uid sous lequel tourne philsh */
   uid_t uid = getuid();
   struct passwd *user;
   /* On recupère l'entrée correspondante
    * dans /etc/passwd */
   user = getpwuid(uid);
   /* On met tout ça dans l'environnement */
   setenv("HOME", user->pw_dir, 0);
   /* Si le PATH n'est pas fixé, il est impossible de le deviner
    * Dans ce cas on utilise un PATH classique UNIX */
   if (getenv("PATH") == NULL)
      putenv("PATH=/usr/local/bin:/usr/bin:/bin:/opt/bin:/sbin");
   return;
}

/* Cette fonction decoupe la saisie suivant les
 * espaces ou les guillemets, elle alloue le tout dans argv
 * Elle renvoie le dernier entier alloué (on s'en sert pour bien
 * liberer la memoire ensuite) */
int parse_saisie(char *saisie, size_t buf_size, char **argv)
{
   char *p;
   p = saisie;
   char *buffer;
   int gui = 0;
   size_t i = 0, j = 0;
   buffer = malloc(sizeof(char) * buf_size+2);
   assert(buffer != NULL);
   while(*p == ' ')
      p++;
   for(;*p != '\0'; p++)
   {
      assert(i < buf_size+2);
      if(*p == '"')
      {
	 gui = (gui) ? 0 : 1;
	 continue;
      }
      if((*p == ' ')&&(!gui))
      {
	 buffer[i] = '\0';
	 argv[j] = malloc(sizeof(char) * (1+strlen(buffer)));
	 assert(argv[j] != NULL);
	 strcpy(argv[j], buffer);
#ifdef DEBUG
	 printf("argv[%d] = '%s'\n", j, argv[j]);
#endif
	 i = 0;
	 j++;
	 while(*p == ' ')
	    p++;
	 p--;
	 continue;
      }
      buffer[i] = *p;
      i++;
   }
   buffer[i] = '\0';
   argv[j] = malloc(sizeof(char) * (1+strlen(buffer)));
   assert(argv[j] != NULL);
   strcpy(argv[j], buffer);
#ifdef DEBUG
   printf("argv[%d] = '%s'\n", j, argv[j]);
#endif
   free(buffer);
   return j;
}

/* Cette fonction compte les mots dans saisie
 * en prenant en compte les espaces et les guillemets,
 * elle en profite pour rentrer la taille du mot le plus
 * long dans lenght (pour fixer la taille du buffer ensuite...)
 */
int compter_mots(char *saisie, size_t *lenght)
{
   char *p = strchr(saisie, '\0');
   int words = 0;
   size_t lenght_current = 0;
   size_t lenght_max = 0;
   int gui = 0;
   p--;
   while(*p == ' ')
   {
      *p = '\0';
      p--;
   }
   p = saisie;
   while(*p == ' ')
      p++;
   if(*p != '\0')
      words++;
   for(;*p != '\0';p++)
   {
      if(*p == '"')
      {
	 gui = (gui) ? 0 : 1;
	 continue;
      }
      if((*p == ' ')&&(!gui))
      {
	 if (lenght_current > lenght_max)
	    lenght_max = lenght_current;
	 lenght_current = 0;
	 words++;
	 while(*p == ' ')
	    p++;
	 p--;
	 continue;
      }
      lenght_current++;
   }
   if (lenght_current > lenght_max)
      lenght_max = lenght_current;
   *lenght = lenght_max;
   return words;
}


int exec_saisie(char *saisie)
{
   int i;
   int argc;
   char **argv;
   size_t buf_size;
   char *p, *buffer = NULL;
   char c;
   extern alias_ll *liste_alias;
   alias_ll *alias;
   alias = liste_alias;
   p = saisie;
   argc = compter_mots(saisie, &buf_size);
   /* Si la saisie est vide de sens */
   if (argc == 0)
      return 0;
   while (*p == ' ')
      p++;
   while(alias != NULL)
   {
      if (!strncmp(alias->name, p, strlen(alias->name)))
      {
	 c = *(p+strlen(alias->name));
	 if ((c != '\0')&&(c != ' '))
	 {
	    alias = alias->next;
	    continue;
	 }
	 buffer = malloc(sizeof(char) * (1+strlen(alias->cmd)+strlen(p+strlen(alias->name))));
	 sprintf(buffer, "%s%s", alias->cmd, p+strlen(alias->name));
	 break;
      }
      alias = alias->next;
   }
   if(buffer == NULL)
      buffer = saisie;
   argc = compter_mots(buffer, &buf_size);
   /* C'est honteux, mais en attendant le support des
    * caractères speciaux, on utilise system()
    * Histoire que le shell donne l'impression
    * de bien marcher
    * NOTE : L'idée honteuse n'est pas de moi,
    * en lisant le code de sash (app-shell/sash sur gentoo)
    * je me suis rendu compte qu'il utilisait system() a tout-vat,
    * du coup je me dis pourquoi pas ? C'est bien sûr temporaire !
    */
   if(strchr(buffer, '|')||strchr(buffer, '*')||strchr(buffer, '>')||strchr(buffer, '<')||strstr(buffer, "&&")||strchr(buffer, '`')||strchr(buffer, '$')||strchr(buffer, '\\'))
   {
      i = system(buffer);
      if (buffer != saisie)
	 free(buffer);
      return i;
   }
   argv = malloc (sizeof(char *) * (argc+1));
   argc = parse_saisie(buffer, buf_size, argv);
   if (buffer != saisie)
      free(buffer);
   argc++;
   argv[argc] = NULL;
   exec_cmd(argc, argv);
   for (i = 0; i < argc; i++)
      free(argv[i]);
   free(argv);
   return 0;
}

/* Ici commence l'aventure */
int main (int argc, char **argv)
{
   /* On teste les options avec lesquelles
    * philsh est appellé */
   options_philsh(argc, argv);
   /* On initialise l'environnement */
   init_env();
   char *config_file;
   char *saisie = NULL;
   char *prompt;
   /* Initialisation de la config */
   uid_t uid = getuid();
   struct passwd *user = getpwuid(uid);
   config_file = malloc(sizeof(char) * (15+strlen(user->pw_dir)));
   sprintf(config_file, "%s/%s", user->pw_dir, ".philshrc");
   init_config(config_file);
   /* La super boucle du phil shell */
   for (;;)
   {
      prompt = set_prompt();
      /* La fonction readline est magique */
      saisie = readline(prompt);
      free(prompt);
      if (saisie && *saisie)
	 add_history(saisie);
      exec_saisie(saisie);
      free(saisie);
   }
   return 0;
}


int options_philsh(int argc, char **argv)
{
   const char *optstring = "hvc";
   static struct option philsh_option[] =
   {
      {"help", 0, NULL, 'h'},
      {"version", 0, NULL, 'v'},
      {"execute", 0, NULL, 'c'},
      {0, 0, 0, 0}
   };
   char opt;
   while (EOF != (opt = getopt_long(argc, argv, optstring, philsh_option, NULL)))
   {
      if (opt == 'v')
      {
	 printf("Philsh %s, Compilé par %s sur une machine %s avec les flags %s\
	       et avec les librairies %s\nPour tout commentaire, pour des bugs, pour me remercier (si si, je suis\
		  serieux ^^) ----> %s\n", PHILSH_VERSION, PHILSH_COMPILE_BY, PHILSH_COMPILE_MACHINE, PHILSH_COMPILE_FLAGS, PHILSH_LINKED_LIBS, PHILSH_MAIL);
	 exit(0);
      }
      else if(opt == 'h')
      {
	 afficher_aide();
	 exit(0);
      }
      else if(opt == 'c')
      {
	 exec_cmd(argc-2, argv+2);
	 exit(0);
      }
   }
   return 0;
}

void afficher_aide(void)
{

   printf("PHILSH version %s\n\
	 philsh [OPTION]...\n\<commit_msg>Oo, git <-----> moi<commit_after>/* 
 * philsh.c
 *
 * Copyright (C) 2008 <NAME> <<EMAIL>>
 * See LICENCE file for licence of this piece of software.
 *
 */

/* on inclu les headers */
#include "headers.h"

/* le chemin de l'executable par exemple /bin/echo */
char *chemin;

/* Structure des builtin commandes,
 * char *name;
 * int (*p)(int, char**);
 */
const struct builtin builtin_command[] =
{
   {"pwd", internal_pwd},
   {"which", internal_which},
   {"uname", internal_uname},
   {"env", internal_env},
   {"cd", internal_cd},
   {"whoami", whoami},
   {"alias", alias},
   {NULL, NULL}
};

/* Cette fonction initialise l'environnement
 * Si $HOME et $PATH n'existent pas, il faut
 * les créer... En effet, si on lance le programme
 * comme ceci : env -i philsh, tous les getenv()
 * retournent NULL */
void init_env(void)
{
   /* L'uid sous lequel tourne philsh */
   uid_t uid = getuid();
   struct passwd *user;
   /* On recupère l'entrée correspondante
    * dans /etc/passwd */
   user = getpwuid(uid);
   /* On met tout ça dans l'environnement */
   setenv("HOME", user->pw_dir, 0);
   /* Si le PATH n'est pas fixé, il est impossible de le deviner
    * Dans ce cas on utilise un PATH classique UNIX */
   if (getenv("PATH") == NULL)
      putenv("PATH=/usr/local/bin:/usr/bin:/bin:/opt/bin:/sbin");
   return;
}

/* Cette fonction decoupe la saisie suivant les
 * espaces ou les guillemets, elle alloue le tout dans argv
 * Elle renvoie le dernier entier alloué (on s'en sert pour bien
 * liberer la memoire ensuite) */
int parse_saisie(char *saisie, size_t buf_size, char **argv)
{
   char *p;
   p = saisie;
   char *buffer;
   int gui = 0;
   size_t i = 0, j = 0;
   buffer = malloc(sizeof(char) * buf_size+2);
   assert(buffer != NULL);
   while(*p == ' ')
      p++;
   for(;*p != '\0'; p++)
   {
      assert(i < buf_size+2);
      if(*p == '"')
      {
	 gui = (gui) ? 0 : 1;
	 continue;
      }
      if((*p == ' ')&&(!gui))
      {
	 buffer[i] = '\0';
	 argv[j] = malloc(sizeof(char) * (1+strlen(buffer)));
	 assert(argv[j] != NULL);
	 strcpy(argv[j], buffer);
#ifdef DEBUG
	 printf("argv[%d] = '%s'\n", j, argv[j]);
#endif
	 i = 0;
	 j++;
	 while(*p == ' ')
	    p++;
	 p--;
	 continue;
      }
      buffer[i] = *p;
      i++;
   }
   buffer[i] = '\0';
   argv[j] = malloc(sizeof(char) * (1+strlen(buffer)));
   assert(argv[j] != NULL);
   strcpy(argv[j], buffer);
#ifdef DEBUG
   printf("argv[%d] = '%s'\n", j, argv[j]);
#endif
   free(buffer);
   return j;
}

/* Cette fonction compte les mots dans saisie
 * en prenant en compte les espaces et les guillemets,
 * elle en profite pour rentrer la taille du mot le plus
 * long dans lenght (pour fixer la taille du buffer ensuite...)
 */
int compter_mots(char *saisie, size_t *lenght)
{
   char *p = strchr(saisie, '\0');
   int words = 0;
   size_t lenght_current = 0;
   size_t lenght_max = 0;
   int gui = 0;
   p--;
   while(*p == ' ')
   {
      *p = '\0';
      p--;
   }
   p = saisie;
   while(*p == ' ')
      p++;
   if(*p != '\0')
      words++;
   for(;*p != '\0';p++)
   {
      if(*p == '"')
      {
	 gui = (gui) ? 0 : 1;
	 continue;
      }
      if((*p == ' ')&&(!gui))
      {
	 if (lenght_current > lenght_max)
	    lenght_max = lenght_current;
	 lenght_current = 0;
	 words++;
	 while(*p == ' ')
	    p++;
	 p--;
	 continue;
      }
      lenght_current++;
   }
   if (lenght_current > lenght_max)
      lenght_max = lenght_current;
   *lenght = lenght_max;
   return words;
}


int exec_saisie(char *saisie)
{
   int i;
   int argc;
   char **argv;
   size_t buf_size;
   char *p, *buffer = NULL;
   char c;
   extern alias_ll *liste_alias;
   alias_ll *alias;
   alias = liste_alias;
   p = saisie;
   argc = compter_mots(saisie, &buf_size);
   /* Si la saisie est vide de sens */
   if (argc == 0)
      return 0;
   while (*p == ' ')
      p++;
   while(alias != NULL)
   {
      if (!strncmp(alias->name, p, strlen(alias->name)))
      {
	 c = *(p+strlen(alias->name));
	 if ((c != '\0')&&(c != ' '))
	 {
	    alias = alias->next;
	    continue;
	 }
	 buffer = malloc(sizeof(char) * (1+strlen(alias->cmd)+strlen(p+strlen(alias->name))));
	 sprintf(buffer, "%s%s", alias->cmd, p+strlen(alias->name));
	 break;
      }
      alias = alias->next;
   }
   if(buffer == NULL)
      buffer = saisie;
   argc = compter_mots(buffer, &buf_size);
   /* C'est honteux, mais en attendant le support des
    * caractères speciaux, on utilise system()
    * Histoire que le shell donne l'impression
    * de bien marcher
    * NOTE : L'idée honteuse n'est pas de moi,
    * en lisant le code de sash (app-shell/sash sur gentoo)
    * je me suis rendu compte qu'il utilisait system() a tout-vat,
    * du coup je me dis pourquoi pas ? C'est bien sûr temporaire !
    */
   if(strchr(buffer, '|')||strchr(buffer, '*')||strchr(buffer, '>')||strchr(buffer, '<')||strstr(buffer, "&&")||strchr(buffer, '`')||strchr(buffer, '$')||strchr(buffer, '\\'))
   {
      i = system(buffer);
      if (buffer != saisie)
	 free(buffer);
      return i;
   }
   argv = malloc (sizeof(char *) * (argc+1));
   argc = parse_saisie(buffer, buf_size, argv);
   if (buffer != saisie)
      free(buffer);
   argc++;
   argv[argc] = NULL;
   exec_cmd(argc, argv);
   for (i = 0; i < argc; i++)
      free(argv[i]);
   free(argv);
   return 0;
}

/* Ici commence l'aventure */
int main (int argc, char **argv)
{
   /* On teste les options avec lesquelles
    * philsh est appellé */
   options_philsh(argc, argv);
   /* On initialise l'environnement */
   init_env();
   char *config_file;
   char *saisie = NULL;
   char *prompt;
   /* Initialisation de la config */
   uid_t uid = getuid();
   struct passwd *user = getpwuid(uid);
   config_file = malloc(sizeof(char) * (15+strlen(user->pw_dir)));
   sprintf(config_file, "%s/%s", user->pw_dir, ".philshrc");
   init_config(config_file);
   /* La super boucle du phil shell */
   for (;;)
   {
      prompt = set_prompt();
      /* La fonction readline est magique */
      saisie = readline(prompt);
      free(prompt);
      if (saisie && *saisie)
	 add_history(saisie);
      exec_saisie(saisie);
      free(saisie);
   }
   return 0;
}


int options_philsh(int argc, char **argv)
{
   const char *optstring = "hvc";
   static struct option philsh_option[] =
   {
      {"help", 0, NULL, 'h'},
      {"version", 0, NULL, 'v'},
      {"execute", 0, NULL, 'c'},
      {0, 0, 0, 0}
   };
   char opt;
   while (EOF != (opt = getopt_long(argc, argv, optstring, philsh_option, NULL)))
   {
      if (opt == 'v')
      {
	 printf("Philsh version : "PHILSH_VERSION".\n"
	       " Compilation settings :\n"
	       "  - Flags : "PHILSH_COMPILE_FLAGS"\n"
	       "  - Linked Libs : "PHILSH_LINKED_LIBS"\n"
	       "  - On "PHILSH_COMPILE_MACHINE" by "PHILSH_COMPILE_BY"\n"
	       " Main contact : "PHILSH_MAIL"\n");
	 exit(0);
      }
      else if(opt == 'h')
      {
	 afficher_aide();
	 exit(0);
      }
      else if(opt == 'c')
      {
	 exec_cmd(argc-2, argv+2);
	 exit(0);
      }
   }
   return 0;
}

void afficher_aide(void)
{

   printf("PHILSH version %s\n\
	 philsh [OPTION]...\n\
{'fraction_non_alphanumeric': 0.17305124059886132, 'fraction_numerical': 0.007310044281999016, 'mean_word_length': 2.6575835475578407, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7077157', 'n_tokens_mistral': 5568, 'n_tokens_neox': 5419, 'n_words': 1423}