Project setup

This commit is contained in:
Christoffer Lerno
2019-07-13 22:46:39 +02:00
parent 1d02585c7a
commit 88b2dc547e
13 changed files with 416 additions and 5 deletions

1
.gitignore vendored
View File

@@ -50,3 +50,4 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf
cmake-build-debug/

View File

@@ -3,4 +3,4 @@ project(c3c C)
set(CMAKE_C_STANDARD 11)
add_executable(c3c main.c)
add_executable(c3c main.c build/build_options.c build/build_options.h build/project_creation.c build/project_creation.h utils/string_utils.c utils/string_utils.h utils/file_utils.c utils/file_utils.h utils/errors.c utils/errors.h)

7
build/build_options.c Normal file
View File

@@ -0,0 +1,7 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "build_options.h"
BuildOptions build_options;

21
build/build_options.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#define MAX_LIB_DIRS 1024
#define MAX_FILES 2048
typedef struct
{
const char* lib_dir[MAX_LIB_DIRS];
int lib_count;
const char* files[MAX_FILES];
int file_count;
const char* project_name;
const char* path;
const char* original_path;
} BuildOptions;
extern BuildOptions build_options;

129
build/project_creation.c Normal file
View File

@@ -0,0 +1,129 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "project_creation.h"
#include "build_options.h"
#include "string.h"
#include "../utils/string_utils.h"
const char* TOML =
"[[executable]]\n"
"# name of the target\n"
"name = \"%s\"\n"
"# version using semantic versioning\n"
"version = \"0.1.0\"\n"
"# authors, optionally with email\n"
"authors = [\"John Doe <john.doe@example.com>\"]\n"
"# language version of C3\n"
"langrev = \"1\"\n"
"# warnings used\n"
"warnings = [\"no-unused\"]\n"
"# sources compiled\n"
"sources = [\"src/**\"]\n"
"# libraries to use\n"
"libs = [\"lib/**\"]\n";
void create_project(void)
{
for (int i = 0; ; i++)
{
char c = build_options.project_name[i];
if (c == '\0') break;
if (!is_alphanum_(c))
{
fprintf(stderr, "'%s' is not a valid project name.\n", build_options.project_name);
exit(EXIT_FAILURE);
}
}
if (chdir(build_options.path))
{
fprintf(stderr, "Can't open path %s\n", build_options.path);
exit(EXIT_FAILURE);
}
int error = mkdir(build_options.project_name, 0755);
if (error)
{
fprintf(stderr, "Could not create directory %s: %s\n", build_options.project_name, strerror(errno));
exit(EXIT_FAILURE);
}
if (chdir(build_options.project_name)) goto ERROR;
FILE *file = fopen("LICENCE", "a");
if (!file) goto ERROR;
fclose(file);
file = fopen("README.md", "a");
if (!file) goto ERROR;
fclose(file);
file = fopen("project.toml", "a");
if (!file) goto ERROR;
fprintf(file, TOML, build_options.project_name);
fclose(file);
if (mkdir("lib", 0755)) goto ERROR;
if (mkdir("build", 0755)) goto ERROR;
if (mkdir("resources", 0755)) goto ERROR;
if (mkdir("test", 0755)) goto ERROR;
chdir("test");
if (mkdir(build_options.project_name, 0755)) goto ERROR;
chdir("..");
if (mkdir("docs", 0755)) goto ERROR;
chdir("docs");
file = fopen("about.md", "a");
if (!file) goto ERROR;
fclose(file);
if (mkdir("src", 0755)) goto ERROR;
chdir("src");
file = fopen("index.html", "a");
if (!file) goto ERROR;
fclose(file);
chdir("../..");
if (mkdir("src", 0755)) goto ERROR;
chdir("src");
if (mkdir(build_options.project_name, 0755)) goto ERROR;
chdir(build_options.project_name);
file = fopen("main.c3", "a");
if (!file) goto ERROR;
fclose(file);
chdir("../..");
printf("Project '%s' created.\n", build_options.project_name);
exit(EXIT_SUCCESS);
ERROR:
fprintf(stderr, "Err: %s\n", strerror(errno));
printf("Something went wrong creating the project.");
chdir(build_options.path);
rmdir(build_options.project_name);
exit(EXIT_FAILURE);
}

8
build/project_creation.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
void create_project(void);

181
main.c
View File

@@ -1,6 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <assert.h>
#include "build/build_options.h"
#include "build/project_creation.h"
#include "utils/errors.h"
static void usage(const char* name) {
fprintf(stderr, "Usage: %s <options> <target>\n", name);
fprintf(stderr, "Options:\n");
fprintf(stderr, " --lib <dir> - use this directory as the c3 library path\n");
fprintf(stderr, " --path <dir> - use this as the base directory for the current command\n");
exit(EXIT_SUCCESS);
}
typedef enum
{
COMMAND_COMPILE,
COMMAND_NEW,
} CompilerCommand;
static CompilerCommand command;
static int arg_index;
static int arg_count;
static const char** args;
static const char* current_arg;
static void select_compiler_command(CompilerCommand new_command)
{
if (command != COMMAND_COMPILE)
{
fprintf(stderr, "Please select only one command\n");
exit(EXIT_FAILURE);
}
command = new_command;
}
static const char* check_dir(const char *path)
{
if (chdir(path) == -1) error_exit("The path \"%s\" does not point to a valid directory.", path);
int err = chdir(build_options.original_path);
assert(!err);
return path;
}
static inline bool at_end()
{
return arg_index == arg_count - 1;
}
static inline const char* next_arg()
{
assert(!at_end());
current_arg = args[++arg_index];
return current_arg;
}
static inline bool next_is_arg()
{
return args[arg_index + 1][0] == '-';
}
static inline bool match_longopt(const char* name)
{
return strcmp(&current_arg[2], name) == 0;
}
static inline bool match_shortopt(const char* name)
{
return strcmp(&current_arg[1], name) == 0;
}
void append_file()
{
if (build_options.file_count == MAX_FILES)
{
fprintf(stderr, "Max %d files may be specified\n", MAX_FILES);
exit(EXIT_FAILURE);
}
build_options.files[build_options.file_count++] = current_arg;
}
static void parse_option()
{
switch (current_arg[1])
{
case 'h':
break;
case 'n':
if (match_shortopt("new"))
{
select_compiler_command(COMMAND_NEW);
if (at_end() || next_is_arg()) error_exit("Expected a project name after -new");
build_options.project_name = next_arg();
return;
}
break;
case '-':
if (match_longopt("about"))
{
fprintf(stderr, "The C3 Compiler\n");
fprintf(stderr, "\nC3 is an evolution of C.\n");
exit(0);
}
if (match_longopt("lib"))
{
if (at_end() || next_is_arg()) error_exit("error: --lib needs a directory.");
if (current_arg[0] == '-') error_exit("Expected a directory after --lib.");
if (build_options.lib_count == MAX_LIB_DIRS) error_exit("Max %d libraries may be specified.", MAX_LIB_DIRS);
build_options.lib_dir[build_options.lib_count++] = check_dir(next_arg());
return;
}
if (match_longopt("path"))
{
if (at_end() || next_is_arg()) error_exit("error: --path needs a directory.");
build_options.path = check_dir(next_arg());
return;
}
if (match_longopt("help"))
{
break;
}
break;
default:
break;
}
usage(args[0]);
}
static void handle_compile_command()
{
printf("TODO\n");
exit(EXIT_SUCCESS);
}
static void parse_arguments()
{
command = COMMAND_COMPILE;
for (arg_index = 1; arg_index < arg_count; arg_index++)
{
current_arg = args[arg_index];
if (current_arg[0] == '-')
{
parse_option();
continue;
}
append_file();
}
switch (command)
{
case COMMAND_NEW:
create_project();
break;
case COMMAND_COMPILE:
handle_compile_command();
break;
default:
exit(EXIT_FAILURE);
}
}
int main(int argc, const char *argv[])
{
build_options.path = ".";
build_options.original_path = getcwd(NULL, 0);
arg_count = argc;
args = argv;
parse_arguments();
return EXIT_SUCCESS;
}
int main() {
printf("Hello, World!\n");
return 0;
}

5
utils/errors.c Normal file
View File

@@ -0,0 +1,5 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "errors.h"

7
utils/errors.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#define error_exit(...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } while(0)

20
utils/file_utils.c Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "file_utils.h"
#include <stdio.h>
#include <stdlib.h>
const char* expand_path(const char* path)
{
if (path[0] == '~' && path[1] == '/')
{
// Ignore leak.
char *ret = NULL;
char *home = getenv("HOME");
if (!home || asprintf(&ret, "%s%s", home, &path[1]) == -1) return &path[2];
return ret;
}
return path;
}

8
utils/file_utils.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
const char* expand_path(const char* path);

6
utils/string_utils.c Normal file
View File

@@ -0,0 +1,6 @@
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "string_utils.h"

26
utils/string_utils.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <stdbool.h>
static inline bool is_lower(char c)
{
return c >= 'a' && c <= 'z';
}
static inline bool is_upper(char c)
{
return c >= 'A' && c <= 'Z';
}
static inline bool is_alphanum_(char c)
{
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_';
}