mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Project setup
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -50,3 +50,4 @@ modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
cmake-build-debug/
|
||||
@@ -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
7
build/build_options.c
Normal 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
21
build/build_options.h
Normal 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
129
build/project_creation.c
Normal 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
8
build/project_creation.h
Normal 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
181
main.c
@@ -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(¤t_arg[2], name) == 0;
|
||||
}
|
||||
|
||||
static inline bool match_shortopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_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
5
utils/errors.c
Normal 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
7
utils/errors.h
Normal 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
20
utils/file_utils.c
Normal 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
8
utils/file_utils.h
Normal 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
6
utils/string_utils.c
Normal 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
26
utils/string_utils.h
Normal 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 == '_';
|
||||
}
|
||||
Reference in New Issue
Block a user