save
This commit is contained in:
6
TODO
6
TODO
@@ -1,6 +0,0 @@
|
||||
1 Fix arg parseing
|
||||
2 Fix generated Makefile
|
||||
3 Add Licence
|
||||
|
||||
Ideas
|
||||
1 Add --is-lib
|
||||
3
config.h
3
config.h
@@ -3,7 +3,8 @@
|
||||
|
||||
/* Program information */
|
||||
#define PROGRAM "yait"
|
||||
#define LICENSE_LINE "License BSD-3-Clause: BSD-3-Clause <https://opensource.org/license/bsd-3-clause>"
|
||||
#define LICENSE_LINE \
|
||||
"License BSD-3-Clause: BSD-3-Clause <https://opensource.org/license/bsd-3-clause>"
|
||||
#define AUTHORS "vx_clutch"
|
||||
#define VERSION "alpha"
|
||||
#define YEAR 2025
|
||||
|
||||
346
core/create_project.c
Normal file
346
core/create_project.c
Normal file
@@ -0,0 +1,346 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include "manifest.h"
|
||||
#include "contents.h"
|
||||
#include "yait.h"
|
||||
|
||||
#define DEFAULT_USER_NAME "unknown"
|
||||
#define DEFAULT_PROJECT_NAME "Project"
|
||||
#define DEFAULT_LICENCE BSD3
|
||||
#define DEFAULT_GIT_INIT true
|
||||
#define DEFAULT_CLANG_FORMAT true
|
||||
|
||||
/* This is to keep track of how deep we are within
|
||||
the project tree. This is used in reset_path_ () */
|
||||
int depth;
|
||||
|
||||
/* This macro exist purely because I like how it looks. This should be called
|
||||
in every function that creates file to ensure they are being created in
|
||||
right place. */
|
||||
#define reset_path reset_path_()
|
||||
int reset_path_()
|
||||
{
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int program_exists(const char *prog)
|
||||
{
|
||||
char *path = getenv("PATH");
|
||||
if (!path)
|
||||
return 1;
|
||||
|
||||
char *copy = strdup(path);
|
||||
if (!copy)
|
||||
return 1;
|
||||
|
||||
char *dir = strtok(copy, ":");
|
||||
while (dir) {
|
||||
char buf[4096];
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir, prog);
|
||||
if (access(buf, X_OK) == 0) {
|
||||
free(copy);
|
||||
return 0;
|
||||
}
|
||||
dir = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): sanitize the alpha-numeric range
|
||||
// clang-format off
|
||||
int sanitize(manifest_t *m)
|
||||
{
|
||||
if (!m->project) m->project = DEFAULT_PROJECT_NAME;
|
||||
if (!m->name) m->name = DEFAULT_USER_NAME;
|
||||
if (!(m->licence == UNLICENCE)) m->licence = DEFAULT_LICENCE;
|
||||
|
||||
m->flag.git = m->flag.git ? true : DEFAULT_GIT_INIT;
|
||||
m->flag.clang_format = m->flag.clang_format ? true : DEFAULT_CLANG_FORMAT;
|
||||
m->flag.GNU = m->flag.GNU ? true : DEFAULT_GNU;
|
||||
|
||||
if (!m->name) {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
int create_libraries(manifest_t manifest)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!manifest.libraries) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LIB_COUNT_; ++i) {
|
||||
if (HAS_LIBRARY(manifest.libraries, LIB_RAYLIB)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/raysan5/raylib");
|
||||
} else if (HAS_LIBRARY(manifest.libraries, LIB_NCURSES)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/mirror/ncurses");
|
||||
} else if (HAS_LIBRARY(manifest.libraries, LIB_CURL)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_CURL);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/raysan5/raylib");
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_licence(manifest_t manifest, char **licence_line_buffer)
|
||||
{
|
||||
if (manifest.licence == UNLICENCE)
|
||||
return 0;
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
assert(licence_line_buffer != NULL);
|
||||
|
||||
switch (manifest.licence) {
|
||||
case BSD3:
|
||||
*licence_line_buffer = "Bsd";
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case GPLv3:
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case MIT:
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case UNLICENCE:
|
||||
default:
|
||||
printfn("bad logic in create_licence ()");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int maybe_create_clang_format(manifest_t manifest)
|
||||
{
|
||||
int status;
|
||||
if (!manifest.flag.clang_format)
|
||||
return 0;
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
status = create_file_with_content(".clang-format",
|
||||
clang_format_template);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int setup_git(manifest_t manifest)
|
||||
{
|
||||
if (!manifest.flag.git) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
int status = system("git init --quiet");
|
||||
if (status) {
|
||||
printfn("failed on git initialize: %s", strerror(status));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_makefile(manifest_t manifest)
|
||||
{
|
||||
char *makefile_name = strdup(manifest.project);
|
||||
if (!makefile_name) {
|
||||
printfn("fatal: out of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (char *p = makefile_name; *p; ++p)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p -= 32;
|
||||
|
||||
reset_path;
|
||||
|
||||
create_file_with_content("Makefile", makefile_template, makefile_name,
|
||||
makefile_name, makefile_name, makefile_name,
|
||||
makefile_name, makefile_name, manifest.project,
|
||||
makefile_name, makefile_name);
|
||||
|
||||
free(makefile_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_configure(manifest_t manifest)
|
||||
{
|
||||
int status = 0;
|
||||
reset_path;
|
||||
|
||||
char *cc;
|
||||
if (manifest.flag.use_cpp) {
|
||||
cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
|
||||
} else {
|
||||
cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
|
||||
}
|
||||
|
||||
create_file_with_content("configure", configure_template, cc);
|
||||
status = system("chmod +x configure");
|
||||
if (status)
|
||||
printfn("error: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
int generate_source_code(manifest_t manifest, char *licence_line)
|
||||
{
|
||||
int status, year;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
year = tm.tm_year + 1900;
|
||||
|
||||
// XXX(vx-clutch): this segfaults, but why?
|
||||
// status = create_file_with_content("config.h", manifest.project, licence_line, year);
|
||||
if (status) {
|
||||
printfn("failed to create config.h: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_and_enter_directory(manifest.project);
|
||||
++depth;
|
||||
if (status) {
|
||||
printfn("failed to create or enter directory: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (manifest.flag.GNU) {
|
||||
status = create_file_with_content("main.c", main_c_gnu_template,
|
||||
manifest.project,
|
||||
manifest.name);
|
||||
} else {
|
||||
status = create_file_with_content("main.c", main_c_template,
|
||||
manifest.project,
|
||||
manifest.name);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int create_project(manifest_t manifest)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = sanitize(&manifest);
|
||||
if (status) {
|
||||
printfn("failed to sanitize format: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
depth = 0;
|
||||
if (strcmp(manifest.path, ".") != 0) {
|
||||
status = create_and_enter_directory(manifest.project);
|
||||
if (status) {
|
||||
printfn("failed to create or enter directory: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = create_makefile(manifest);
|
||||
if (status) {
|
||||
printfn("failed to create Makefile: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_configure(manifest);
|
||||
if (status) {
|
||||
printfn("failed to create configure: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = setup_git(manifest);
|
||||
if (status) {
|
||||
printfn("warning: git initialization failed: %s",
|
||||
strerror(status));
|
||||
}
|
||||
|
||||
status = maybe_create_clang_format(manifest);
|
||||
if (status) {
|
||||
printfn("warning: clang-format setup failed: %s",
|
||||
strerror(status));
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): make this smarter--or not ( macro ).
|
||||
char *licence_line = malloc(sizeof(char) * 1024);
|
||||
if (!licence_line) {
|
||||
printfn("failed to create memory for licence line: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
status = create_licence(manifest, &licence_line);
|
||||
if (status) {
|
||||
printfn("failed to get libraries: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): Take in licence line and put it into standard.c
|
||||
status = generate_source_code(manifest, licence_line);
|
||||
if (status) {
|
||||
printfn("failed to generate source code: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
free(licence_line);
|
||||
|
||||
status = create_libraries(manifest);
|
||||
if (status) {
|
||||
printfn("failed to get libraries: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -6,13 +6,14 @@
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
#include "../config.h"
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "yait.h"
|
||||
|
||||
int create_file_with_content(char *path, char *format, ...)
|
||||
{
|
||||
|
||||
24
core/file.h
24
core/file.h
@@ -1,24 +0,0 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/* Constants for file operations */
|
||||
#define DEFAULT_DIR_PERMISSIONS 0755
|
||||
#define MAX_PATH_LENGTH 1024
|
||||
|
||||
int create_and_enter_directory (const char *dirname);
|
||||
|
||||
int create_file_with_content (char *path, char *format, ...);
|
||||
|
||||
int create_directory (char *format, ...);
|
||||
|
||||
#endif
|
||||
78
core/manifest.h
Normal file
78
core/manifest.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/licence/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef FORMAT_H
|
||||
#define FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
BSD3, /* BSD 3-Clause Licence */
|
||||
GPLv3, /* GNU General Public Licence v3 */
|
||||
MIT, /* MIT Licence */
|
||||
UNLICENCE, /* Unlicence */
|
||||
LICENCE_HELP, /* Help case */
|
||||
} licence_t;
|
||||
|
||||
/* A bit field is used so that we can accomplish two things. (a) store lots of
|
||||
libraries without taxing memory; and (b) a dynamic array is not neccescary.
|
||||
*/
|
||||
typedef enum {
|
||||
LIB_NONE = 0, /* No libraries selected */
|
||||
LIB_RAYLIB = 1 << 0, /* Raylib game library */
|
||||
LIB_NCURSES = 1 << 1, /* Windows API */
|
||||
LIB_CURL = 1 << 2, /* cURL library */
|
||||
LIB_COUNT_, /* Number of Libraries */
|
||||
LIB_HELP, /* Help case */
|
||||
} lib_flags_t;
|
||||
|
||||
typedef struct {
|
||||
bool GNU;
|
||||
bool git;
|
||||
bool clang_format;
|
||||
bool use_cpp;
|
||||
} flags_t;
|
||||
|
||||
typedef struct {
|
||||
licence_t licence; /* Licence type for the project */
|
||||
char *project; /* Project name */
|
||||
char *path; /* Path */
|
||||
char *name; /* Author/creator name ( if not provided infered on sanitize ) */
|
||||
lib_flags_t libraries; /* Selected libraries (bit field) */
|
||||
flags_t flag; /* Flags */
|
||||
} manifest_t;
|
||||
|
||||
#define DEFAULT_CLANG_FORMAT true
|
||||
#define DEFAULT_GIT_INIT true
|
||||
#define DEFAULT_GNU false
|
||||
#define DEFAULT_LIBRARIES LIB_NONE
|
||||
#define DEFAULT_LICENCE BSD3
|
||||
|
||||
#define HAS_LIBRARY(libs, lib) ((libs) & (lib))
|
||||
#define ADD_LIBRARY(libs, lib) ((libs) |= (lib))
|
||||
#define REMOVE_LIBRARY(libs, lib) ((libs) &= ~(lib))
|
||||
|
||||
static lib_flags_t TOLibrary(char *src)
|
||||
{
|
||||
if (strcmp(src, "raylib"))
|
||||
return LIB_RAYLIB;
|
||||
if (strcmp(src, "ncurse"))
|
||||
return LIB_NCURSES;
|
||||
if (strcmp(src, "ncurses"))
|
||||
return LIB_NCURSES;
|
||||
if (strcmp(src, "curl"))
|
||||
return LIB_CURL;
|
||||
if (strcmp(src, "help"))
|
||||
return LIB_HELP;
|
||||
fprintf(stderr, "could not find library %s", src);
|
||||
return LIB_COUNT_; /* bad case */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#include "print.h"
|
||||
#include "yait.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
17
core/print.h
17
core/print.h
@@ -1,17 +0,0 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef PRINT_H
|
||||
#define PRINT_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int printfn (char *format, ...);
|
||||
|
||||
#endif
|
||||
@@ -9,7 +9,8 @@
|
||||
#ifndef COMMIT
|
||||
#define COMMIT 0
|
||||
#endif
|
||||
#include "standard.h"
|
||||
|
||||
#include "yait.h"
|
||||
#include "../config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef STANDARD_H
|
||||
#define STANDARD_H
|
||||
|
||||
int parse_standard_options (void (*usage_func) (), int argc, char **argv);
|
||||
|
||||
#endif
|
||||
31
core/yait.h
Normal file
31
core/yait.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/license/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef YAIT_H
|
||||
#define YAIT_H
|
||||
|
||||
/* Constants for file operations */
|
||||
#define DEFAULT_DIR_PERMISSIONS 0755
|
||||
#define MAX_PATH_LENGTH 1024
|
||||
|
||||
int printfn(char *format, ...);
|
||||
|
||||
int create_and_enter_directory(const char *dirname);
|
||||
|
||||
int create_file_with_content(char *path, char *format, ...);
|
||||
|
||||
int create_directory(char *format, ...);
|
||||
|
||||
int parse_standard_options(void (*usage_func)(), int argc, char **argv);
|
||||
|
||||
int program_exists(const char *prog);
|
||||
|
||||
#include "manifest.h"
|
||||
int create_project(manifest_t manifest);
|
||||
|
||||
#endif // YAIT_H
|
||||
@@ -3,3 +3,4 @@
|
||||
# Usage ./format
|
||||
|
||||
find . -name "*.c" -exec clang-format -i {} \;
|
||||
find . -name "*.h" -exec clang-format -i {} \;
|
||||
|
||||
368
yait/main.c
368
yait/main.c
@@ -6,34 +6,18 @@
|
||||
* <https://opensource.org/licence/bsd-3-clause>
|
||||
*/
|
||||
|
||||
// Usage: yait [OPTION]... PROJECT [NAME]
|
||||
// Usage: yait [OPTION]... <PATH>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "../core/file.h"
|
||||
#include "../core/print.h"
|
||||
#include "../core/standard.h"
|
||||
#include "contents.h"
|
||||
#include "manifest.h"
|
||||
|
||||
#define DEFAULT_USER_NAME "unknown"
|
||||
#define DEFAULT_PROJECT_NAME "Project"
|
||||
#define DEFAULT_LICENCE BSD3
|
||||
#define DEFAULT_GIT_INIT true
|
||||
#define DEFAULT_CLANG_FORMAT true
|
||||
|
||||
/* This is to keep track of how deep we are within
|
||||
the project tree. This is used in reset_path_ () */
|
||||
int depth;
|
||||
#include "../core/yait.h"
|
||||
#include "../core/manifest.h"
|
||||
|
||||
#define print_option(option, description) \
|
||||
printf(" %-20s %-20s\n", option, description)
|
||||
@@ -115,325 +99,30 @@ static int parse_arguments(manifest_t *conf, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This macro exist purely because I like how it looks. This should be called
|
||||
in every function that creates file to ensure they are being created in
|
||||
right place. */
|
||||
#define reset_path reset_path_()
|
||||
static int reset_path_()
|
||||
int get_name(char **output)
|
||||
{
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
FILE *pipe;
|
||||
char buffer[128];
|
||||
size_t output_len = 0;
|
||||
|
||||
pipe = popen("ls -l", "r");
|
||||
if (!pipe)
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
|
||||
size_t chunk_len = strlen(buffer);
|
||||
char *new_output = realloc(output, output_len + chunk_len + 1);
|
||||
if (!new_output) {
|
||||
free(output);
|
||||
pclose(pipe);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
*output = new_output;
|
||||
memcpy(output + output_len, buffer, chunk_len);
|
||||
output_len += chunk_len;
|
||||
*output[output_len] = '\0';
|
||||
}
|
||||
|
||||
int program_exists(const char *prog)
|
||||
{
|
||||
char *path = getenv("PATH");
|
||||
if (!path)
|
||||
return 1;
|
||||
|
||||
char *copy = strdup(path);
|
||||
if (!copy)
|
||||
return 1;
|
||||
|
||||
char *dir = strtok(copy, ":");
|
||||
while (dir) {
|
||||
char buf[4096];
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir, prog);
|
||||
if (access(buf, X_OK) == 0) {
|
||||
free(copy);
|
||||
return 0;
|
||||
}
|
||||
dir = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(copy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): sanitize the alpha-numeric range
|
||||
// clang-format off
|
||||
static int sanitize(manifest_t *m)
|
||||
{
|
||||
if (!m->project) m->project = DEFAULT_PROJECT_NAME;
|
||||
if (!m->name) m->name = DEFAULT_USER_NAME;
|
||||
if (!(m->licence == UNLICENCE)) m->licence = DEFAULT_LICENCE;
|
||||
|
||||
m->flag.git = m->flag.git ? true : DEFAULT_GIT_INIT;
|
||||
m->flag.clang_format = m->flag.clang_format ? true : DEFAULT_CLANG_FORMAT;
|
||||
m->flag.GNU = m->flag.GNU ? true : DEFAULT_GNU;
|
||||
|
||||
if (!m->name) {
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
m->name = (pw && pw->pw_name) ? pw->pw_name : DEFAULT_USER_NAME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static int create_libraries(manifest_t manifest)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (!manifest.libraries) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
for (int i = 0; i < LIB_COUNT_; ++i) {
|
||||
if (HAS_LIBRARY(manifest.libraries, LIB_RAYLIB)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_RAYLIB);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/raysan5/raylib");
|
||||
} else if (HAS_LIBRARY(manifest.libraries, LIB_NCURSES)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_NCURSES);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/mirror/ncurses");
|
||||
} else if (HAS_LIBRARY(manifest.libraries, LIB_CURL)) {
|
||||
REMOVE_LIBRARY(manifest.libraries, LIB_CURL);
|
||||
status = system(
|
||||
"git submodule add -q https://github.com/raysan5/raylib");
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int create_licence(manifest_t manifest, char **licence_line_buffer)
|
||||
{
|
||||
if (manifest.licence == UNLICENCE)
|
||||
return 0;
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
assert(licence_line_buffer != NULL);
|
||||
|
||||
switch (manifest.licence) {
|
||||
case BSD3:
|
||||
*licence_line_buffer = "Bsd";
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case GPLv3:
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case MIT:
|
||||
printfn("Not impl");
|
||||
assert(1 == 2);
|
||||
break;
|
||||
case UNLICENCE:
|
||||
default:
|
||||
printfn("bad logic in create_licence ()");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int maybe_create_clang_format(manifest_t manifest)
|
||||
{
|
||||
int status;
|
||||
if (!manifest.flag.clang_format)
|
||||
return 0;
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
status = create_file_with_content(".clang-format",
|
||||
clang_format_template);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int setup_git(manifest_t manifest)
|
||||
{
|
||||
if (!manifest.flag.git) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reset_path; */
|
||||
while (depth != 0) {
|
||||
if (chdir("..") != 0)
|
||||
return errno;
|
||||
else
|
||||
--depth;
|
||||
}
|
||||
|
||||
int status = system("git init --quiet");
|
||||
if (status) {
|
||||
printfn("failed on git initialize: %s", strerror(status));
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int create_makefile(manifest_t manifest)
|
||||
{
|
||||
char *makefile_name = strdup(manifest.project);
|
||||
if (!makefile_name) {
|
||||
printfn("fatal: out of memory");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (char *p = makefile_name; *p; ++p)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p -= 32;
|
||||
|
||||
reset_path;
|
||||
|
||||
create_file_with_content("Makefile", makefile_template, makefile_name,
|
||||
makefile_name, makefile_name, makefile_name,
|
||||
makefile_name, makefile_name, manifest.project,
|
||||
makefile_name, makefile_name);
|
||||
|
||||
free(makefile_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_configure(manifest_t manifest)
|
||||
{
|
||||
int status = 0;
|
||||
reset_path;
|
||||
|
||||
char *cc;
|
||||
if (manifest.flag.use_cpp) {
|
||||
cc = "trycc g++\ntrycc CC\ntrycc clang++\n";
|
||||
} else {
|
||||
cc = "trycc gcc\ntrycc cc\ntrycc clang\n";
|
||||
}
|
||||
|
||||
create_file_with_content("configure", configure_template, cc);
|
||||
status = system("chmod +x configure");
|
||||
if (status)
|
||||
printfn("error: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
static int generate_source_code(manifest_t manifest, char *licence_line)
|
||||
{
|
||||
int status, year;
|
||||
|
||||
time_t t = time(NULL);
|
||||
struct tm tm = *localtime(&t);
|
||||
year = tm.tm_year + 1900;
|
||||
|
||||
// XXX(vx-clutch): this segfaults, but why?
|
||||
// status = create_file_with_content("config.h", manifest.project, licence_line, year);
|
||||
if (status) {
|
||||
printfn("failed to create config.h: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_and_enter_directory(manifest.project);
|
||||
++depth;
|
||||
if (status) {
|
||||
printfn("failed to create or enter directory: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (manifest.flag.GNU) {
|
||||
status = create_file_with_content("main.c", main_c_gnu_template,
|
||||
manifest.project,
|
||||
manifest.name);
|
||||
} else {
|
||||
status = create_file_with_content("main.c", main_c_template,
|
||||
manifest.project,
|
||||
manifest.name);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int create_project(manifest_t manifest)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = sanitize(&manifest);
|
||||
if (status) {
|
||||
printfn("failed to sanitize format: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_and_enter_directory(manifest.project);
|
||||
depth = 0;
|
||||
if (status) {
|
||||
printfn("failed to create or enter directory: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_makefile(manifest);
|
||||
if (status) {
|
||||
printfn("failed to create Makefile: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = create_configure(manifest);
|
||||
if (status) {
|
||||
printfn("failed to create configure: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = setup_git(manifest);
|
||||
if (status) {
|
||||
printfn("warning: git initialization failed: %s",
|
||||
strerror(status));
|
||||
}
|
||||
|
||||
status = maybe_create_clang_format(manifest);
|
||||
if (status) {
|
||||
printfn("warning: clang-format setup failed: %s",
|
||||
strerror(status));
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): make this smarter--or not ( macro ).
|
||||
char *licence_line = malloc(sizeof(char) * 1024);
|
||||
if (!licence_line) {
|
||||
printfn("failed to create memory for licence line: %s",
|
||||
strerror(status));
|
||||
return status;
|
||||
}
|
||||
status = create_licence(manifest, &licence_line);
|
||||
if (status) {
|
||||
printfn("failed to get libraries: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): Take in licence line and put it into standard.c
|
||||
status = generate_source_code(manifest, licence_line);
|
||||
if (status) {
|
||||
printfn("failed to generate source code: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
free(licence_line);
|
||||
|
||||
status = create_libraries(manifest);
|
||||
if (status) {
|
||||
printfn("failed to get libraries: %s", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
pclose(pipe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -454,12 +143,9 @@ int main(int argc, char **argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO(vx-clutch): enable argument parsing
|
||||
// parse_arguments(&manifest, argc, argv);
|
||||
manifest.project = "sample_project";
|
||||
manifest.name = "vx_clutch";
|
||||
manifest.licence = BSD3;
|
||||
manifest.libraries = ADD_LIBRARY(manifest.libraries, LIB_NONE);
|
||||
status = get_name(&manifest.name);
|
||||
manifest.path = ".";
|
||||
|
||||
status = create_project(manifest);
|
||||
|
||||
return status == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/* Copyright (C) vx_clutch
|
||||
*
|
||||
* This file is part of yait
|
||||
*
|
||||
* This project and file is licenced under the BSD-3-Clause licence.
|
||||
* <https://opensource.org/licence/bsd-3-clause>
|
||||
*/
|
||||
|
||||
#ifndef FORMAT_H
|
||||
#define FORMAT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../core/print.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BSD3, /* BSD 3-Clause Licence */
|
||||
GPLv3, /* GNU General Public Licence v3 */
|
||||
MIT, /* MIT Licence */
|
||||
UNLICENCE, /* Unlicence */
|
||||
LICENCE_HELP, /* Help case */
|
||||
} licence_t;
|
||||
|
||||
/* A bit field is used so that we can accomplish two things. (a) store lots of
|
||||
libraries without taxing memory; and (b) a dynamic array is not neccescary.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LIB_NONE = 0, /* No libraries selected */
|
||||
LIB_RAYLIB = 1 << 0, /* Raylib game library */
|
||||
LIB_NCURSES = 1 << 1, /* Windows API */
|
||||
LIB_CURL = 1 << 2, /* cURL library */
|
||||
LIB_COUNT_, /* Number of Libraries */
|
||||
LIB_HELP, /* Help case */
|
||||
} lib_flags_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool GNU;
|
||||
bool git;
|
||||
bool clang_format;
|
||||
bool use_cpp;
|
||||
} flags_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
licence_t licence; /* Licence type for the project */
|
||||
char *project; /* Project name */
|
||||
char *name; /* Author/creator name ( if not provided infered on sanitize ) */
|
||||
lib_flags_t libraries; /* Selected libraries (bit field) */
|
||||
flags_t flag; /* Flags */
|
||||
} manifest_t;
|
||||
|
||||
#define DEFAULT_CLANG_FORMAT true
|
||||
#define DEFAULT_GIT_INIT true
|
||||
#define DEFAULT_GNU false
|
||||
#define DEFAULT_LIBRARIES LIB_NONE
|
||||
#define DEFAULT_LICENCE BSD3
|
||||
|
||||
#define HAS_LIBRARY(libs, lib) ((libs) & (lib))
|
||||
#define ADD_LIBRARY(libs, lib) ((libs) |= (lib))
|
||||
#define REMOVE_LIBRARY(libs, lib) ((libs) &= ~(lib))
|
||||
|
||||
static lib_flags_t
|
||||
TOLibrary (char *src)
|
||||
{
|
||||
if (strcmp (src, "raylib"))
|
||||
return LIB_RAYLIB;
|
||||
if (strcmp (src, "ncurse"))
|
||||
return LIB_NCURSES;
|
||||
if (strcmp (src, "ncurses"))
|
||||
return LIB_NCURSES;
|
||||
if (strcmp (src, "curl"))
|
||||
return LIB_CURL;
|
||||
if (strcmp (src, "help"))
|
||||
return LIB_HELP;
|
||||
printfn("could not find library %s", src);
|
||||
return LIB_COUNT_; /* bad case */
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user