#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdint.h>

typedef struct {
    char *arg;
} DATA; //динамический массив

struct stat statbuf; //информация о файле
struct passwd *pwd; //uid и gid

DATA *the_array = NULL;
int num_elements = 0; // Keeps track of the number of elements used
int num_allocated = 0; // This is essentially how large the array is

//==== Функции
int AddToArray (DATA item);
char const * sperm(__mode_t mode);
void printLine();
//========

int main(int argc, char *argv[])
{
	short int numFiles=0; //количество файлов/папок в аргументах
	short int key_a=0; //ключ -a
	for(int i=1; i<argc; i++) //Сканируем все аргументы
	{
		char ch = argv[i][0]; //берем первый символ
		if(ch == '-')
		{
			int start=1; //начало после '-'
			while(argv[i][start] != NULL) //проверяем ключи
			{
				if(argv[i][start] == 'a')
				     key_a=1;
				start++;
			}
		}
		else
		{
			 numFiles++;
		     DATA temp;
		     temp.arg = malloc((strlen(argv[i]) + 1) * sizeof(char));
		     strncpy(temp.arg, argv[i], strlen(argv[i]) + 1); //копируем значение аргумента в переменную
		     if(AddToArray(temp) == -1) //если возникли проблемы с памятью
		           return 1;
		}
	}
	
	for(int i=0;i<numFiles;i++) //все каталоги из аргументов
	{
		printf("%d ПРОХОД", numFiles);
	    printLine();
    }
    
    if(numFiles==0) //если не заданы папки в параметрах
    {
      DIR *dir = opendir(".");
        
      struct dirent *ent;
      while((ent = readdir(dir)) != NULL)
      {
       
      int ret = stat(ent->d_name, &statbuf);
      if (ret < 0)
      {
          perror(ent->d_name);
      }
        
      printf("%10.10s", sperm (statbuf.st_mode));
      printf("\t%s\n", ent->d_name);
      }
    
    }
    
    return 0;
}

void printLine() //печать файла папки с инфой
{
	DIR *dir = opendir(the_array->arg);
    *the_array++;
  
    struct dirent *next;
    if(dir)
    {
    while( (next=readdir(dir)) != NULL)
    {
        
        int ret = stat(next->d_name, &statbuf);
        if (ret < 0)
        {
            perror(next->d_name);
        }
        
        //printf("%10.10s", sperm (statbuf.st_mode)); //права доступа
        printf("\t%s", next->d_name); //имя папки/файла
        uid_t id = statbuf.st_uid;
        pwd = getpwuid(id); //узнаем имя юзера файла
        if(pwd != NULL)
        printf("    [%-8.15s", pwd->pw_name);
            else
        printf("    [%-8d", statbuf.st_uid); //если имя не найдено в системе
        // то выводим числом
        printf("\n");
    }
    }
    else
    {
    fprintf(stderr, "Error opening directory\n");
    }
    
}

char const * sperm(__mode_t mode) {
    static char local_buff[16] = {0};
    int i = 0;
    // user permissions
    if ((mode & S_IRUSR) == S_IRUSR) local_buff[i] = 'r';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IWUSR) == S_IWUSR) local_buff[i] = 'w';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IXUSR) == S_IXUSR) local_buff[i] = 'x';
    else local_buff[i] = '-';
    i++;
    // group permissions
    if ((mode & S_IRGRP) == S_IRGRP) local_buff[i] = 'r';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IWGRP) == S_IWGRP) local_buff[i] = 'w';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IXGRP) == S_IXGRP) local_buff[i] = 'x';
    else local_buff[i] = '-';
    i++;
    // other permissions
    if ((mode & S_IROTH) == S_IROTH) local_buff[i] = 'r';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IWOTH) == S_IWOTH) local_buff[i] = 'w';
    else local_buff[i] = '-';
    i++;
    if ((mode & S_IXOTH) == S_IXOTH) local_buff[i] = 'x';
    else local_buff[i] = '-';
    return local_buff;
}

int AddToArray (DATA item) //функция добавления в динамический массив
{
        if(num_elements == num_allocated) // Are more refs required?
        { 
                // Feel free to change the initial number of refs
                // and the rate at which refs are allocated.
                if (num_allocated == 0)
                        num_allocated = 3; // Start off with 3 refs
                else
                        num_allocated *= 2; // Double the number 
                                                    // of refs allocated

                // Make the reallocation transactional 
                // by using a temporary variable first
                void *_tmp = realloc(the_array, (num_allocated * sizeof(DATA)));

                // If the reallocation didn't go so well,
                // inform the user and bail out
                if (!_tmp)
                {
                        fprintf(stderr, "ERROR: Couldn't realloc memory!\n");
                        return(-1);
                }

                // Things are looking good so far
                the_array = (DATA*)_tmp;
        }

        the_array[num_elements] = item;
        num_elements++;

        return num_elements;
}