backup
This commit is contained in:
parent
1fe9f668b6
commit
44d62db74c
10 changed files with 208 additions and 82 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@
|
||||||
*.class
|
*.class
|
||||||
*.log
|
*.log
|
||||||
*.core
|
*.core
|
||||||
|
minimake
|
||||||
|
|
|
||||||
5
AUTHORS
Normal file
5
AUTHORS
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
guillem.george
|
||||||
|
|
||||||
|
Special thanks to
|
||||||
|
|
||||||
|
- Timothée Battefort for the parser
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla
|
CFLAGS = -std=c99 -pedantic -Werror -Wall -Wextra -Wvla
|
||||||
|
LDFLAGS=
|
||||||
|
|
||||||
DBG_CFLAGS = -fsanitize=address -g
|
DBG_CFLAGS = -fsanitize=address -g
|
||||||
|
DBG_LDFLAGS= -fsanitize=address
|
||||||
|
|
||||||
|
|
||||||
SRC_DIR = src
|
SRC_DIR = src
|
||||||
LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c
|
LIB_SRCS = lines/lines.c hash_maps/hash_maps.c lists/lists.c
|
||||||
|
|
@ -18,6 +22,7 @@ $(TARGET): $(OBJS)
|
||||||
@echo $(OBJS)
|
@echo $(OBJS)
|
||||||
|
|
||||||
debug: CFLAGS += $(DBG_CFLAGS)
|
debug: CFLAGS += $(DBG_CFLAGS)
|
||||||
|
debug: LDFLAGS += $(DBG_LDFLAGS)
|
||||||
debug: $(OBJS)
|
debug: $(OBJS)
|
||||||
$(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS)
|
$(CC) -o $(TARGET) $^ $(LDFLAGS) $(LDLIBS)
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -9,13 +9,14 @@
|
||||||
// Helps to match a string (excludes blanks and special characters)
|
// Helps to match a string (excludes blanks and special characters)
|
||||||
int isChar(char c)
|
int isChar(char c)
|
||||||
{
|
{
|
||||||
return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#';
|
return c != '\0' && !isblank(c) && c != ':' && c != '=' && c != '#'
|
||||||
|
&& c != '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
int skipBlanks(char *buf, size_t buf_len)
|
int skipBlanks(char *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < buf_len && isblank(buf[i]))
|
while (i < buf_len && (isblank(buf[i]) || buf[i] == '\n'))
|
||||||
i++;
|
i++;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +30,7 @@ int isBlankLine(struct line *l)
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < line_size)
|
while (i < line_size)
|
||||||
{
|
{
|
||||||
if (!isblank(buf[i]))
|
if (!isblank(buf[i]) && buf[i] != '\n')
|
||||||
return 0;
|
return 0;
|
||||||
if (buf[i] == '#') // Comments
|
if (buf[i] == '#') // Comments
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -41,28 +42,34 @@ int isBlankLine(struct line *l)
|
||||||
// Returns the next word from buf until buf_len,
|
// Returns the next word from buf until buf_len,
|
||||||
// and the numbers of read characters in *read_chars
|
// and the numbers of read characters in *read_chars
|
||||||
// WARNING allocates the result on the heap
|
// WARNING allocates the result on the heap
|
||||||
char *readWord(char *buf, size_t buf_len, size_t *read_chars)
|
size_t readWord(char *buf, size_t buf_len, char **word)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t str_buf_size = STRING_BUFFER_SIZE;
|
size_t res_size = STRING_BUFFER_SIZE;
|
||||||
char *str_buf = malloc(sizeof(char) * str_buf_size);
|
char *res = malloc(sizeof(char) * res_size);
|
||||||
while (i < buf_len && isChar(buf[i]))
|
while (i < buf_len && isChar(buf[i]))
|
||||||
{
|
{
|
||||||
// Reallocate more space if necessary
|
// Reallocate more space if necessary
|
||||||
if (i >= str_buf_size - 1)
|
if (i >= res_size - 1)
|
||||||
{
|
{
|
||||||
str_buf_size += STRING_BUFFER_SIZE;
|
res_size += STRING_BUFFER_SIZE;
|
||||||
str_buf = realloc(str_buf, str_buf_size);
|
res = realloc(res, res_size);
|
||||||
if (str_buf == NULL)
|
if (res == NULL)
|
||||||
errx(2, "Could not realloc");
|
errx(2, "Could not realloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
str_buf[i] = buf[i];
|
res[i] = buf[i];
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
res[i] = '\0';
|
||||||
|
|
||||||
str_buf[i] = '\0';
|
if (i == 0)
|
||||||
*read_chars = i;
|
{
|
||||||
|
free(res);
|
||||||
|
*word = NULL;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
return str_buf;
|
*word = res;
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
struct line
|
struct line
|
||||||
{
|
{
|
||||||
char* buffer; // Line content
|
char* buffer; // Line content
|
||||||
size_t length; // Line length
|
ssize_t length; // Line length
|
||||||
size_t number; // Line number in file
|
size_t number; // Line number in file
|
||||||
FILE* file_stream; // Full file stream
|
FILE* file_stream; // Full file stream
|
||||||
};
|
};
|
||||||
|
|
@ -20,6 +20,6 @@ struct line
|
||||||
int isChar(char c);
|
int isChar(char c);
|
||||||
int isBlankLine(struct line *l);
|
int isBlankLine(struct line *l);
|
||||||
int skipBlanks(char *buf, size_t buf_len);
|
int skipBlanks(char *buf, size_t buf_len);
|
||||||
char *readWord(char *buf, size_t buf_len, size_t *read_chars);
|
size_t readWord(char *buf, size_t buf_len, char **word);
|
||||||
|
|
||||||
#endif // LINES_H
|
#endif // LINES_H
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,127 @@
|
||||||
// Error Codes
|
|
||||||
#define INVALID_ARG 2
|
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <stdlib.h>
|
||||||
|
// #include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lists/lists.h"
|
||||||
|
#include "minimake.h"
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Look at perror for stdlib functions
|
// Look at perror for stdlib functions
|
||||||
// Create an enum for error handling
|
// Create an enum for error handling
|
||||||
|
|
||||||
static int handle_args(int argc, char **argv)
|
static void print_help(char *program_name)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [options] [target]... ", program_name);
|
||||||
|
puts("Options:");
|
||||||
|
puts(" -f FILE Reads FILE as a makefile");
|
||||||
|
puts(" -h Prints this message and exit");
|
||||||
|
puts(" -p Prints minimake's internal database");
|
||||||
|
puts("");
|
||||||
|
puts("Pas mal non ? C'est français");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_args(int argc, char **argv, struct list **minimake_files,
|
||||||
|
struct list **minimake_rules)
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
struct list *files = NULL;
|
||||||
|
struct list *rules = NULL;
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
if (strcmp(argv[i], "-h"))
|
// Options
|
||||||
errx(INVALID_ARG, "-h: not implemented");
|
if (argv[i][0] == '-')
|
||||||
else if (strcmp(argv[i], "-f"))
|
{
|
||||||
errx(INVALID_ARG, "-f: not implemented");
|
// No opt
|
||||||
else if (strcmp(argv[i], "-p"))
|
if (strcmp(argv[i], "--") == 0)
|
||||||
errx(INVALID_ARG, "-p: not implemented");
|
{
|
||||||
else
|
// Treat as rules
|
||||||
errx(INVALID_ARG, ": Pleaase give an argument");
|
for (int j = i; j < argc; j++)
|
||||||
|
{
|
||||||
|
files = list_append(rules, argv[i]);
|
||||||
|
}
|
||||||
|
*minimake_files = files;
|
||||||
|
*minimake_rules = rules;
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
// Help
|
||||||
|
else if (strcmp(argv[i], "-h") == 0)
|
||||||
|
{
|
||||||
|
print_help(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
// Custom file
|
||||||
|
else if (strcmp(argv[i], "-f") == 0)
|
||||||
|
{
|
||||||
|
flags |= FLAGS_CUSTOM_FILE;
|
||||||
|
if (i + 1 == argc || argv[i + 1][0] == '-')
|
||||||
|
errx(INVALID_ARG, "No file specified after '-f'");
|
||||||
|
|
||||||
|
files = list_prepend(files, argv[i]);
|
||||||
|
}
|
||||||
|
// Print
|
||||||
|
else if (strcmp(argv[i], "-p") == 0)
|
||||||
|
{
|
||||||
|
flags |= FLAGS_PRINT;
|
||||||
|
}
|
||||||
|
// Unknown option
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Unknown option '%s'", argv[i]);
|
||||||
|
print_help(argv[0]);
|
||||||
|
exit(INVALID_ARG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Rules
|
||||||
|
{
|
||||||
|
files = list_append(rules, argv[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("%s: done", argv[0]);
|
|
||||||
|
files = list_append(files, DEFAULT_MAKEFILE);
|
||||||
|
files = list_append(files, DEFAULT_MAKEFILE_2);
|
||||||
|
|
||||||
|
*minimake_files = files;
|
||||||
|
*minimake_rules = rules;
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *getMakefile(struct list *files)
|
||||||
|
{
|
||||||
|
struct list *file = files;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
// Test file presence
|
||||||
|
while (file != NULL && !found)
|
||||||
|
{
|
||||||
|
FILE *test = fopen(file->data, "r");
|
||||||
|
if (test != NULL)
|
||||||
|
found = 1;
|
||||||
|
|
||||||
|
fclose(test);
|
||||||
|
if (!found)
|
||||||
|
file = file->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *res = NULL;
|
||||||
|
if (found)
|
||||||
|
res = file->data;
|
||||||
|
|
||||||
|
list_destroy(files);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
return handle_args(argc, argv);
|
struct list *files;
|
||||||
|
struct list *rules;
|
||||||
|
int flags = handle_args(argc, argv, &files, &rules);
|
||||||
|
|
||||||
|
char *filename = getMakefile(files);
|
||||||
|
if (filename == NULL)
|
||||||
|
errx(GENERIC_ERR, "No Makefile found");
|
||||||
|
|
||||||
|
make(filename, flags);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,12 @@ static struct variable *createVariable(char *name)
|
||||||
|
|
||||||
int err = hashMapInsert(variables, name, NULL, NULL);
|
int err = hashMapInsert(variables, name, NULL, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
errx(1, "Internal Error: Couln't add entry for '%s' in the hashmap",
|
{
|
||||||
|
// free(name);
|
||||||
|
free(res);
|
||||||
|
errx(2, "Internal Error: Couln't add entry for '%s' in the hashmap",
|
||||||
name);
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -54,29 +58,37 @@ static struct rule *createRule(char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse dependencies from buf and returns them inside a chained list
|
// Parse dependencies from buf and returns them inside a chained list
|
||||||
static struct list *readDependencies(char *buf, size_t buf_size)
|
static struct list *readDependencies(struct line *l, size_t offset)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = offset;
|
||||||
|
size_t buf_size = l->length;
|
||||||
|
char *buf = l->buffer;
|
||||||
struct list *res = NULL;
|
struct list *res = NULL;
|
||||||
|
|
||||||
while (i < buf_size)
|
while (i < buf_size)
|
||||||
{
|
{
|
||||||
i += skipBlanks(buf + i, buf_size - i);
|
i += skipBlanks(buf + i, buf_size - i);
|
||||||
|
|
||||||
// Read word
|
// Read word
|
||||||
size_t skipped_chars = 0;
|
char *dep_name;
|
||||||
char *dep_name = readWord(buf + i, buf_size - i, &skipped_chars);
|
i += readWord(buf + i, buf_size - i, &dep_name);
|
||||||
if (skipped_chars != 0)
|
if (dep_name != NULL)
|
||||||
// Add to list
|
// Add to list
|
||||||
res = list_append(res, dep_name);
|
res = list_append(res, dep_name);
|
||||||
i += skipped_chars;
|
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
if (buf[i] == '#')
|
if (buf[i] == '#')
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
// Unknown chars
|
// Unknown chars
|
||||||
if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0')
|
if (!isChar(buf[i]) && !isblank(buf[i]) && buf[i] != '\0'
|
||||||
errx(2, "Unexpected character '%c'", buf[i]);
|
&& buf[i] != '\n')
|
||||||
|
{
|
||||||
|
printf("DEBUG: line: %s", l->buffer);
|
||||||
|
errx(2,
|
||||||
|
"Unexpected character '%c' after rule declaration at %lu:%lu",
|
||||||
|
buf[i], l->number, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
@ -94,7 +106,7 @@ static struct list *readRecipe(struct line *l)
|
||||||
struct list *res = NULL;
|
struct list *res = NULL;
|
||||||
|
|
||||||
// Getline
|
// Getline
|
||||||
while ((l->length = getline(&buf, &buf_size, stream)))
|
while ((l->length = getline(&buf, &buf_size, stream)) != -1)
|
||||||
{
|
{
|
||||||
l->number++;
|
l->number++;
|
||||||
|
|
||||||
|
|
@ -148,6 +160,8 @@ static char *readValue(char *buf, size_t buf_size)
|
||||||
return str_buf;
|
return str_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static char *expand_variable();
|
||||||
|
|
||||||
// Takes a buffer containing the line to parse and it length
|
// Takes a buffer containing the line to parse and it length
|
||||||
// As well as the line number in the file for error handling
|
// As well as the line number in the file for error handling
|
||||||
static void parseLine(struct line *current_line)
|
static void parseLine(struct line *current_line)
|
||||||
|
|
@ -160,9 +174,11 @@ static void parseLine(struct line *current_line)
|
||||||
i += skipBlanks(buf + i, line_size - i);
|
i += skipBlanks(buf + i, line_size - i);
|
||||||
|
|
||||||
// Read name
|
// Read name
|
||||||
size_t skipped_chars = 0;
|
char *name;
|
||||||
char *name = readWord(buf + i, line_size - i, &skipped_chars);
|
i += readWord(buf + i, line_size - i, &name);
|
||||||
i += skipped_chars;
|
// if (name == NULL)
|
||||||
|
// errx(1, "Il s'est passé quoi là ? \nUnexpected character at %lu:%lu",
|
||||||
|
// current_line->number, i);
|
||||||
|
|
||||||
i += skipBlanks(buf + i, line_size - i);
|
i += skipBlanks(buf + i, line_size - i);
|
||||||
|
|
||||||
|
|
@ -182,10 +198,16 @@ static void parseLine(struct line *current_line)
|
||||||
// Rule
|
// Rule
|
||||||
case ':':
|
case ':':
|
||||||
new_rule = createRule(name);
|
new_rule = createRule(name);
|
||||||
new_rule->dependencies = readDependencies(buf + i, line_size);
|
new_rule->dependencies = readDependencies(current_line, i + 1);
|
||||||
new_rule->recipe = readRecipe(current_line);
|
new_rule->recipe = readRecipe(current_line);
|
||||||
|
|
||||||
|
// Check for EOF
|
||||||
|
if (current_line->length == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
parseLine(current_line);
|
parseLine(current_line);
|
||||||
// TODO: check for loooooops
|
// TODO: check for loooooops
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Blank line
|
// Blank line
|
||||||
|
|
@ -203,7 +225,7 @@ static void parseLine(struct line *current_line)
|
||||||
buf[i], name, current_line->number);
|
buf[i], name, current_line->number);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(name);
|
// free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeParse(char *path)
|
void makeParse(char *path)
|
||||||
|
|
@ -249,3 +271,21 @@ void makeParse(char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==== Runtime ====
|
// ==== Runtime ====
|
||||||
|
|
||||||
|
// ==== MAKE ====
|
||||||
|
|
||||||
|
void make(char *path, int flags)
|
||||||
|
{
|
||||||
|
if (flags & FLAGS_PRINT)
|
||||||
|
errx(GENERIC_ERR, "Not Implemented");
|
||||||
|
|
||||||
|
makeParse(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==== Misc ====
|
||||||
|
|
||||||
|
// static void free_all()
|
||||||
|
// {
|
||||||
|
// hashMapFree(rules);
|
||||||
|
// hashMapFree(variables);
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
#ifndef MINIMAKE_H
|
#ifndef MINIMAKE_H
|
||||||
#define MINIMAKE_H
|
#define MINIMAKE_H
|
||||||
|
|
||||||
|
// Error Codes
|
||||||
|
#define INVALID_ARG 2
|
||||||
|
#define GENERIC_ERR 2
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
#define FLAGS_CUSTOM_FILE 1
|
||||||
|
#define FLAGS_PRINT 2
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
#define DEFAULT_MAKEFILE "Makefile"
|
||||||
|
#define DEFAULT_MAKEFILE_2 "makefile"
|
||||||
#define BUFFER_SIZE 1024
|
#define BUFFER_SIZE 1024
|
||||||
#define HASHMAP_SIZE 32
|
#define HASHMAP_SIZE 32
|
||||||
|
|
||||||
|
|
@ -25,6 +36,6 @@ struct rule
|
||||||
struct list *recipe;
|
struct list *recipe;
|
||||||
};
|
};
|
||||||
|
|
||||||
int make(char *path, int flags);
|
void make(char *path, int flags);
|
||||||
|
|
||||||
#endif // ! MINIMAKE_H
|
#endif // ! MINIMAKE_H
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
SIMPLE_VAR = coucou
|
|
||||||
SIMPLE_VAR_COMMENT = the comment is gone # comment
|
|
||||||
|
|
||||||
# the following line starts with a space then a tab
|
|
||||||
SPACES_BEFORE_TAB = var_beginning var_end
|
|
||||||
|
|
||||||
sparse_rule: depa depb
|
|
||||||
|
|
||||||
command 1
|
|
||||||
|
|
||||||
command 2
|
|
||||||
|
|
||||||
B = B_var_beginning B_var_end
|
|
||||||
|
|
||||||
packed_rule: depa depb
|
|
||||||
command 1
|
|
||||||
command 2
|
|
||||||
|
|
||||||
silent_rule: depa depb
|
|
||||||
@ command 1
|
|
||||||
@command 2
|
|
||||||
|
|
||||||
rule_comment: depa depb # comment
|
|
||||||
|
|
||||||
command_space_rule: depa depb
|
|
||||||
echo spaces before
|
|
||||||
echo spaces after
|
|
||||||
echo this is a # comment
|
|
||||||
|
|
||||||
simple_rule: simple_dep
|
|
||||||
|
|
||||||
no_dep_rule:
|
|
||||||
|
|
||||||
variable_rule: beginning $(SIMPLE_VAR) end
|
|
||||||
echo "shouldn't be expanded: $(SIMPLE_VAR)"
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue