-Subproject commit 2447a14f38be8e2de8f3984dc708800b36f36c98
+Subproject commit 988bd412d9b3d0681457c4c169d398c273d0c6ff
SUBPROJECTS := Libft
-INCDIR := .
+INCDIR := inc
INCDIR += $(addsuffix /inc, $(SUBPROJECTS));
INCLUDE := $(addprefix -I, $(INCDIR))
-SOURCES := main.c
+SRCDIR := src
+
+SOURCES := main.c \
+ \
+ sim_main.c \
+ sim_node.c \
+ sim_state.c \
+ \
+ text.c \
+ colors.c \
+ \
+ build_helper.c \
+ \
+ c_addnode.c \
+ c_addfet.c \
+ c_setnode.c \
+ c_bind.c \
+ c_draw.c \
+ c_next.c \
+ c_help.c \
+
+SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES))
+
OBJECTS := $(SOURCES:.c=.o)
NAME := FET_sim
TODO
+rewrite t_fet and t_node to store indexes insted of pointers to connected parts
+rewrite command parsing (what I've created is just ugly)
+come up with better file structure
create language to write circuits in (circuit language?) (something like MHRD language?)
implement circuit builder that converts circuit language to FET_sim representation in order to simulate
-expand simulator commands
+add even more simulation commands(eg. delete node/fet)
test the project
improve simulator io (maybe add graphics?)
optimize
+pass 42 norminette
DONE
foundations of logic
+expand simulator commands
--- /dev/null
+#ifndef FET_SIM_H
+# define FET_SIM_H
+
+# include "libft.h"
+
+# define MAX_ARGS 3
+
+// zkrat means short circuit in my language. I opted for this because
+// C does not permit short (it is type) and short_circuit was too long
+typedef enum e_state
+{
+ off,
+ on,
+ pull_down,
+ pull_up,
+ floating,
+ zkrat,
+ unknown,
+} t_state;
+
+typedef enum e_terminal
+{
+ source,
+ drain,
+ gate,
+} t_terminal;
+
+typedef struct s_node
+{
+ int checked;
+ t_state state;
+ t_state set_state;
+ t_vec connected;
+} t_node;
+
+typedef enum e_type
+{
+ p = 'p',
+ n = 'n',
+} t_type;
+
+typedef struct s_mosfet
+{
+ int is_opened;
+ t_type type;
+ t_node *gate;
+ t_node *source;
+ t_node *drain;
+} t_mosfet;
+
+typedef enum e_command
+{
+ none,
+ next,
+ draw,
+ setnode,
+ addfet,
+ addnode,
+ bind,
+ help,
+ exitsim,
+} t_command;
+
+typedef enum e_arg_type
+{
+ num,
+ terminal,
+ state,
+ type,
+ command,
+} t_arg_type;
+
+typedef union u_arg_val
+{
+ size_t num;
+ t_terminal terminal;
+ t_state state;
+ t_type type;
+ t_command command;
+} t_arg_val;
+
+typedef struct s_arg
+{
+ t_arg_type type;
+ t_arg_val val;
+} t_arg;
+
+typedef struct s_input
+{
+ t_command command;
+ size_t argc;
+ t_arg argv[MAX_ARGS];
+} t_input;
+
+
+void add_node(t_vec *nodes, t_state set_state);
+void add_mosfet(t_vec *mosfets, t_type type);
+void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal);
+
+void free_node(void *node);
+int process_input(t_vec *nodes, t_vec *mosfets);
+int get_input(t_input *input);
+
+const char *state_color_escape(t_state state);
+void draw_single(t_vec *nodes, t_vec *mosfets, size_t i);
+
+void update_nodes(t_vec *nodes);
+int sim_step(t_vec *nodes, t_vec *mosfets);
+
+void print_start(void);
+void command_not_found(const char *input);
+void print_help(t_command c);
+void print_index_error(size_t index, size_t size);
+
+t_state simple_resolve_state(t_state s1, t_state s2);
+t_state resolve_state(t_vec *connected_nodes);
+void apply_state(t_state state, t_vec *connected_nodes);
+t_state reduce_state(t_state state);
+
+int c_addfet(t_input input, t_vec *mosfets);
+int c_addnode(t_input input, t_vec *nodes);
+int c_bind(t_input input, t_vec *nodes, t_vec *mosfets);
+int c_draw(t_input input, t_vec *nodes, t_vec *mosfets);
+int c_help(t_input input);
+int c_next(t_input input, t_vec *nodes, t_vec *mosfets);
+int c_setnode(t_input input, t_vec *nodes);
+#endif //FET_SIM_H
+++ /dev/null
-
-#include "libft.h"
-#include <stdlib.h>
-
-// zkrat means short circuit in my language. I opted for this because
-// C does not permit short (it is type) and short_circuit was too long
-typedef enum e_state
-{
- off,
- on,
- pull_down,
- pull_up,
- floating,
- zkrat,
- unknown,
-} t_state;
-
-typedef enum e_terminal
-{
- source,
- drain,
- gate,
-} t_terminal;
-
-typedef struct s_node
-{
- int checked;
- t_state state;
- t_state set_state;
- t_vec connected;
-} t_node;
-
-typedef enum e_type
-{
- p = 'p',
- n = 'n',
-} t_type;
-
-typedef struct s_mosfet
-{
- int is_opened;
- t_type type;
- t_node *gate;
- t_node *source;
- t_node *drain;
-} t_mosfet;
-
-/* Monospace table of state resolution
- * s2 \ s1 | short | off | on | pull_d | pull_u | float | unknown
- * --------|-------|-------|-------|--------|--------|--------|---------
- * short | short | short | short | short | short | short | short
- * --------|-------|-------|-------|--------|--------|--------|---------
- * off | short | off | short | off | off | off | off
- * --------|-------|-------|-------|--------|--------|--------|---------
- * on | short | short | on | on | on | on | on
- * --------|-------|-------|-------|--------|--------|--------|---------
- * pull_d | short | off | on | pull_d | pull_d | pull_d | pull_d
- * --------|-------|-------|-------|--------|--------|--------|---------
- * pull_u | short | off | on | pull_d | pull_u | pull_u | pull_u
- * --------|-------|-------|-------|--------|--------|--------|---------
- * float | short | off | on | pull_d | pull_u | float | float
- * --------|-------|-------|-------|--------|--------|--------|---------
- * unknown | short | off | on | pull_d | pull_u | float | unknown
- *
- * It may be possible to construct the enum e_state in such a way that
- * this function is easy arithmetics.
- */
-t_state simple_resolve_state(t_state s1, t_state s2)
-{
- if (s1 == s2)
- return (s1);
- if (s1 == zkrat || s2 == zkrat)
- return (zkrat);
- if ((s1 == off && s2 == on) || (s1 == on && s2 == off))
- return (zkrat);
- if (s1 == on || s2 == on)
- return (on);
- if (s1 == off || s2 == off)
- return (off);
- if (s1 == pull_down || s2 == pull_down)
- return (pull_down);
- if (s1 == pull_up || s2 == pull_up)
- return (pull_up);
- if (s1 == floating || s2 == floating)
- return (floating);
- return (unknown);
-}
-
-t_state resolve_state(t_vec *connected_nodes)
-{
- size_t i;
- t_state state;
- t_node *node;
-
- i = 0;
- state = unknown;
- while (i < connected_nodes->size)
- {
- node = *(t_node **)ft_vec_access(connected_nodes, i);
- state = simple_resolve_state(state, node->set_state);
- ++i;
- }
- return (state);
-}
-
-t_node *get_neighbour_node(const t_mosfet *mosfet, const t_node *start)
-{
- if (mosfet->source == start)
- return (mosfet->drain);
- return (mosfet->source);
-}
-
-void find_connected(t_node *node, t_vec *connected_nodes)
-{
- size_t i;
- t_node *neigh_node;
- t_mosfet *mosfet;
-
- if (node->checked)
- return ;
- node->checked = 1;
- ft_vec_append(connected_nodes, &node);
- i = 0;
- while (i < node->connected.size)
- {
- mosfet = *(t_mosfet **)ft_vec_access(&node->connected, i);
- if (mosfet->is_opened)
- {
- neigh_node = get_neighbour_node(mosfet, node);
- find_connected(neigh_node, connected_nodes);
- }
- ++i;
- }
- return ;
-}
-
-void apply_state(t_state state, t_vec *connected_nodes)
-{
- size_t i;
- t_node *node;
-
- i = 0;
- while (i < connected_nodes->size)
- {
- node = *(t_node **)ft_vec_access(connected_nodes, i);
- node->state = state;
- ++i;
- }
- return ;
-}
-
-t_state reduce_state(t_state state)
-{
- if (state == pull_down)
- return (off);
- if (state == pull_up)
- return (on);
- if (state == unknown)
- return (floating);
- return (state);
-}
-
-void update_nodes(t_vec *nodes)
-{
- size_t i;
- t_state state;
- t_node *cur_node;
- t_vec connected_nodes;
-
- ft_vec_init(&connected_nodes, sizeof(t_node *));
- i = 0;
- while (i < nodes->size)
- {
- cur_node = ft_vec_access(nodes, i);
- if (!cur_node->checked)
- {
- find_connected(cur_node, &connected_nodes);
- state = resolve_state(&connected_nodes);
- apply_state(reduce_state(state), &connected_nodes);
- ft_vec_forget_range(&connected_nodes, connected_nodes.size, 0);
- }
- ++i;
- }
- ft_vec_free(&connected_nodes, NULL);
- return ;
-}
-
-void update_mosfet(t_mosfet *mosfet)
-{
- t_state state;
-
- state = mosfet->gate->state;
- if (mosfet->type == p && state == on)
- mosfet->is_opened = 1;
- else if (mosfet->type == n && state == off)
- mosfet->is_opened = 1;
- else
- mosfet->is_opened = 0;
- return ;
-}
-
-void update_mosfets(t_vec *mosfets)
-{
- size_t i;
- t_mosfet *mosfet;
-
- i = 0;
- while (i < mosfets->size)
- {
- mosfet = ft_vec_access(mosfets, i);
- update_mosfet(mosfet);
- ++i;
- }
- return ;
-}
-
-void reset_nodes(t_vec *nodes)
-{
- size_t i;
- t_node *node;
-
- i = 0;
- while (i < nodes->size)
- {
- node = ft_vec_access(nodes, i);
- node->checked = 0;
- ++i;
- }
- return ;
-}
-
-// memset is used to initialize struct padding
-void add_node(t_vec *nodes, t_state set_state)
-{
- t_node node;
-
- ft_memset(&node, 0, sizeof(node));
- node.checked = 0;
- node.state = set_state;
- node.set_state = set_state;
- ft_vec_init(&node.connected, sizeof(t_mosfet *));
- ft_vec_append(nodes, &node);
- return ;
-}
-
-void add_mosfet(t_vec *mosfets, t_type type)
-{
- t_mosfet mosfet;
-
- mosfet.is_opened = 0;
- mosfet.type = type;
- mosfet.gate = NULL;
- mosfet.drain = NULL;
- mosfet.source = NULL;
- ft_vec_append(mosfets, &mosfet);
- return ;
-}
-
-void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal)
-{
- t_node *old;
- size_t index;
-
- old = NULL;
- if (terminal == source)
- {
- old = mosfet->source;
- mosfet->source = node;
- ft_vec_append(&node->connected, &mosfet);
- }
- else if (terminal == drain)
- {
- old = mosfet->drain;
- mosfet->drain = node;
- ft_vec_append(&node->connected, &mosfet);
- }
- else
- {
- mosfet->gate = node;
- }
- if (old && ft_vec_find_index(&old->connected, &mosfet, &index) == success)
- {
- ft_vec_forget(&old->connected, index);
- }
- return ;
-}
-
-void build_graph(__attribute__((unused)) const char *filename, t_vec *nodes, t_vec *mosfets)
-{
- add_node(nodes, off);
- add_node(nodes, off);
- add_node(nodes, pull_up);
- add_mosfet(mosfets, p);
- bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 0), gate);
- bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 1), drain);
- bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 2), source);
- return ;
-}
-
-void free_node(void *node)
-{
- ft_vec_free(&((t_node *)node)->connected, NULL);
- return ;
-}
-
-const char *state_color_escape(t_state state)
-{
- if (state == on)
- return ("\033[32m");
- if (state == off)
- return ("\033[39m");
- if (state == floating)
- return ("\033[34m");
- return ("\033[31m");
-}
-
-void draw(t_vec *nodes, t_vec *mosfets)
-{
- size_t i;
- size_t index;
- t_mosfet *mosfet;
- const char default_color[] = "\033[39m";
-
- i = 0;
- ft_printf("\n");
- while (i < mosfets->size)
- {
- mosfet = ft_vec_access(mosfets, i);
- ft_vec_find_index(nodes, mosfet->source, &index);
- ft_printf(" %u\n", index);
- ft_printf(" %s|%s\n", state_color_escape(mosfet->source->state), default_color);
- ft_vec_find_index(nodes, mosfet->gate, &index);
- ft_printf("%u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), default_color, mosfet->type);
- ft_printf(" %s|%s\n", state_color_escape(mosfet->drain->state), default_color);
- ft_vec_find_index(nodes, mosfet->drain, &index);
- ft_printf(" %u\n\n", index);
- ++i;
- }
- return ;
-}
-
-int take_input(__attribute__((unused)) t_vec *nodes,__attribute__((unused)) t_vec *mosfets)
-{
- int res;
- char *input;
-
- ft_printf("FET_sim>");
- input = get_next_line(0);
- res = 0;
- if (input && (input[0] == n || (!ft_strncmp(input, "next", 4))))
- res = 1;
- free(input);
- return (res);
-}
-
-int main(__attribute__((unused)) int argc, char **argv)
-{
- int run;
- t_vec nodes;
- t_vec mosfets;
-
- ft_vec_init(&nodes, sizeof(t_node));
- ft_vec_init(&mosfets, sizeof(t_mosfet));
- build_graph(argv[1], &nodes, &mosfets);
- run = 1;
- while (run)
- {
- update_nodes(&nodes);
- draw(&nodes, &mosfets);
- update_mosfets(&mosfets);
- reset_nodes(&nodes);
- ((t_node *)ft_vec_access(&nodes, 0))->set_state = on;
- run = take_input(&nodes, &mosfets);
- }
- ft_vec_free(&nodes, free_node);
- ft_vec_free(&mosfets, NULL);
- return (0);
-}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+void bind_fet_node(t_mosfet *mosfet, t_node *node, t_terminal terminal)
+{
+ t_node *old;
+ size_t index;
+
+ old = NULL;
+ if (terminal == source)
+ {
+ old = mosfet->source;
+ mosfet->source = node;
+ ft_vec_append(&node->connected, &mosfet);
+ }
+ else if (terminal == drain)
+ {
+ old = mosfet->drain;
+ mosfet->drain = node;
+ ft_vec_append(&node->connected, &mosfet);
+ }
+ else
+ {
+ mosfet->gate = node;
+ }
+ if (old && ft_vec_find_index(&old->connected, &mosfet, &index) == success)
+ {
+ ft_vec_forget(&old->connected, index);
+ }
+ return ;
+}
+
+// memset is used to initialize struct padding
+void add_node(t_vec *nodes, t_state set_state)
+{
+ t_node node;
+
+ ft_memset(&node, 0, sizeof(node));
+ node.checked = 0;
+ node.state = set_state;
+ node.set_state = set_state;
+ ft_vec_init(&node.connected, sizeof(t_mosfet *));
+ ft_vec_append(nodes, &node);
+ return ;
+}
+
+void add_mosfet(t_vec *mosfets, t_type type)
+{
+ t_mosfet mosfet;
+
+ mosfet.is_opened = 0;
+ mosfet.type = type;
+ mosfet.gate = NULL;
+ mosfet.drain = NULL;
+ mosfet.source = NULL;
+ ft_vec_append(mosfets, &mosfet);
+ return ;
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+int c_addfet(t_input input, t_vec *mosfets)
+{
+ size_t i;
+
+ if (input.argc == 1 && input.argv[0].type == type)
+ {
+ add_mosfet(mosfets, input.argv[0].val.type);
+ ft_printf("Index of added FET: %u\n", mosfets->size - 1);
+ }
+ else if (input.argc == 2 && input.argv[0].type == type && input.argv[1].type == num)
+ {
+ i = 0;
+ ft_printf("Index of added FETs:\n\t");
+ while (i < input.argv[1].val.num)
+ {
+ ft_printf("%u ", mosfets->size);
+ add_mosfet(mosfets, input.argv[0].val.type);
+ ++i;
+ }
+ }
+ /*else
+ print_wrong_usage(input);*/
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+static int add_nodes(t_vec *nodes, size_t num, t_state state)
+{
+ size_t i;
+
+ i = 0;
+ ft_printf("Indexes of added nodes:\n\t");
+ while (i < num)
+ {
+ ft_printf("%u ", nodes->size);
+ add_node(nodes, state);
+ ++i;
+ }
+ ft_printf("\n");
+ return (1);
+}
+
+int c_addnode(t_input input, t_vec *nodes)
+{
+ size_t new_nodes_num;
+ t_state set_state;
+
+ /*if (input.argc > 2
+ || (input.argc == 1
+ && input.argv[0].type != num && input.argv[0].type != state)
+ || (input.argc == 2
+ && (input.argv[0].type != state || input.argv[1].type != num)))
+ {
+ print_wrong_usage(input);
+ return (1);
+ }*/
+ new_nodes_num = 1;
+ set_state = unknown;
+ if (input.argc == 1 && input.argv[0].type == state)
+ set_state = input.argv[0].val.state;
+ else if (input.argc == 1)
+ new_nodes_num= input.argv[0].val.num;
+ else if (input.argc == 2)
+ {
+ set_state = input.argv[0].val.state;
+ new_nodes_num = input.argv[1].val.num;
+ }
+ return (add_nodes(nodes, new_nodes_num, set_state));
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+int c_bind(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+ t_node *node;
+ t_mosfet *mosfet;
+ t_terminal term;
+
+ /*if (input.argc != 3 || input.argv[0].type != num
+ || input.argv[1].type != num || input.argv[2].type != terminal)
+ {
+ print_wrong_usage(input);
+ return (1);
+ }*/
+ node = ft_vec_access(nodes, input.argv[0].val.num);
+ mosfet = ft_vec_access(mosfets, input.argv[1].val.num);
+ term = input.argv[2].val.terminal;
+ bind_fet_node(mosfet, node, term);
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+int c_draw(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+ size_t i;
+
+ if (input.argc == 0)
+ {
+ i = 0;
+ while (i < mosfets->size)
+ {
+ draw_single(nodes, mosfets, i);
+ ++i;
+ }
+ }
+ else if (input.argc == 1 && input.argv[0].type == num)
+ {
+ draw_single(nodes, mosfets, input.argv[0].val.num);
+ }
+ /*else
+ {
+ print_wrong_usage(input);
+ }*/
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+
+int c_help(t_input input)
+{
+ if (input.argc == 0)
+ print_help(none);
+ else if (input.argc == 1 && input.argv[0].type == command)
+ print_help(input.argv[0].val.command);
+ /*else
+ print_wrong_usage(input);*/
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+int c_next(t_input input, t_vec *nodes, t_vec *mosfets)
+{
+ size_t i;
+
+ if (input.argc == 0)
+ {
+ if (!sim_step(nodes, mosfets))
+ return (0);
+ }
+ else if (input.argc == 1 && input.argv[0].type == num)
+ {
+ i = 0;
+ while (i < input.argv[0].val.num)
+ {
+ if (!sim_step(nodes, mosfets))
+ return (0);
+ ++i;
+ }
+ }
+ /*else
+ {
+ print_wrong_usage(input);
+ }*/
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+int c_setnode(t_input input, t_vec *nodes)
+{
+ t_node *node;
+
+ /*if (input.argc != 2 || input.argv[0].type != num || input.argv[1].type != state)
+ {
+ print_wrong_usage(input);
+ return (1);
+ }*/
+ node = ft_vec_access(nodes, input.argv[0].val.num);
+ if (!node)
+ {
+ print_index_error(input.argv[0].val.num, nodes->size);
+ return (1);
+ }
+ node->set_state = input.argv[1].val.state;
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+// ac stands for ANSI (escape code) color
+const char g_default_ac[] = "\033[39m";
+
+const char g_red_ac[] = "\033[31m";
+const char g_green_ac[] = "\033[32m";
+const char g_blue_ac[] = "\033[34m";
+const char g_white_ac[] = "\033[97m";
+
+const char *state_color_escape(t_state state)
+{
+ if (state == on)
+ return (g_green_ac);
+ if (state == off)
+ return (g_white_ac);
+ if (state == floating)
+ return (g_blue_ac);
+ return (g_red_ac);
+}
+
+void draw_single(t_vec *nodes, t_vec *mosfets, size_t i)
+{
+ t_mosfet *mosfet;
+ size_t index;
+
+ mosfet = ft_vec_access(mosfets, i);
+ if (ft_vec_find_index(nodes, mosfet->source, &index) == success)
+ {
+ ft_printf(" %u\n", index);
+ ft_printf(" %s|%s\n", state_color_escape(mosfet->source->state), g_default_ac);
+ }
+ else
+ {
+ ft_printf(" %sNULL%s\n", g_red_ac, g_default_ac);
+ ft_printf(" %s|%s\n", g_red_ac, g_default_ac);
+ }
+ if (ft_vec_find_index(nodes, mosfet->gate, &index) == success)
+ ft_printf("%4u%s--%s%c\n", index, state_color_escape(mosfet->gate->state), g_default_ac, mosfet->type);
+ else
+ ft_printf("%sNULL--%s%c\n", g_red_ac, g_default_ac, mosfet->type);
+ if (ft_vec_find_index(nodes, mosfet->drain, &index) == success)
+ {
+ ft_printf(" %s|%s\n", state_color_escape(mosfet->drain->state), g_default_ac);
+ ft_printf(" %u\n\n", index);
+ }
+ else
+ {
+ ft_printf(" %s|%s\n", g_red_ac, g_default_ac);
+ ft_printf(" %sNULL%s\n\n", g_red_ac, g_default_ac);
+ }
+ ++i;
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+#include <stdlib.h>
+
+void build_graph(__attribute__((unused)) const char *filename, t_vec *nodes, t_vec *mosfets)
+{
+ add_node(nodes, off);
+ add_node(nodes, off);
+ add_node(nodes, pull_up);
+ add_mosfet(mosfets, p);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 0), gate);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 1), drain);
+ bind_fet_node(ft_vec_access(mosfets, 0), ft_vec_access(nodes, 2), source);
+ return ;
+}
+
+void free_node(void *node)
+{
+ ft_vec_free(&((t_node *)node)->connected, NULL);
+ return ;
+}
+
+void free_split(char **sp)
+{
+ size_t i;
+
+ i = 0;
+ while (sp[i])
+ {
+ free(sp[i]);
+ ++i;
+ }
+ free(sp);
+ return ;
+}
+
+size_t split_length(char **sp)
+{
+ size_t i;
+
+ i = 0;
+ while (sp[i])
+ ++i;
+ return (i);
+}
+
+int parse_command(const char *str, t_command *cmd)
+{
+ if (!ft_strcmp(str, "n") || !ft_strcmp(str, "next"))
+ *cmd = next;
+ else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "draw"))
+ *cmd = draw;
+ else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "set") || !ft_strcmp(str, "setnode"))
+ *cmd = setnode;
+ else if (!ft_strcmp(str, "an") || !ft_strcmp(str, "addn") || !ft_strcmp(str, "addnode"))
+ *cmd = addnode;
+ else if (!ft_strcmp(str, "af") || !ft_strcmp(str, "addf") || !ft_strcmp(str, "addfet"))
+ *cmd = addfet;
+ else if (!ft_strcmp(str, "b") || !ft_strcmp(str, "bind"))
+ *cmd = bind;
+ else if (!ft_strcmp(str, "h") || !ft_strcmp(str, "help"))
+ *cmd = help;
+ else if (!ft_strcmp(str, "e") || !ft_strcmp(str, "exit"))
+ *cmd = exitsim;
+ else
+ return (0);
+ return (1);
+}
+
+int parse_type(const char *str, t_type *type)
+{
+ if (!ft_strcmp(str, "p"))
+ *type = p;
+ else if (!ft_strcmp(str, "n"))
+ *type = n;
+ else
+ return (0);
+ return (1);
+}
+
+int parse_terminal(const char *str, t_terminal *term)
+{
+ if (!ft_strcmp(str, "s") || !ft_strcmp(str, "source"))
+ *term = source;
+ else if (!ft_strcmp(str, "d") || !ft_strcmp(str, "drain"))
+ *term = drain;
+ else if (!ft_strcmp(str, "g") || !ft_strcmp(str, "gate"))
+ *term = gate;
+ else
+ return (0);
+ return (1);
+}
+
+int parse_state(const char *str, t_state *state)
+{
+ if(!ft_strcmp(str, "on"))
+ *state = on;
+ else if (!ft_strcmp(str, "off"))
+ *state = off;
+ else if (!ft_strcmp(str, "pd") || !ft_strcmp(str, "pull_down"))
+ *state = pull_down;
+ else if (!ft_strcmp(str, "pu") || !ft_strcmp(str, "pull_up"))
+ *state = pull_up;
+ else if (!ft_strcmp(str, "f") || !ft_strcmp(str, "float") || !ft_strcmp(str, "floating"))
+ *state = floating;
+ else if (!ft_strcmp(str, "s") || !ft_strcmp(str, "short"))
+ *state = zkrat;
+ else if (!ft_strcmp(str, "u") || !ft_strcmp(str, "unknown"))
+ *state = unknown;
+ else
+ return (0);
+ return (1);
+}
+
+int has_correct_argc(t_input input)
+{
+ t_command c;
+ size_t argc;
+
+ c = input.command;
+ argc = input.argc;
+ if ((c == next || c == draw || c == addfet || c == help) && argc > 1)
+ return (0);
+ if (c == setnode && argc != 2)
+ return (0);
+ if (c == bind && argc != 3)
+ return (0);
+ if (c == addnode && argc > 2)
+ return (0);
+ return (1);
+}
+
+static int str_is_num(const char *str)
+{
+ size_t i;
+
+ i = 0;
+ while (ft_isdigit(str[i]))
+ ++i;
+ return (str[i] == '\0');
+}
+
+// maybe atos (alphanum to size_t) should be implemented
+int parse_arg(t_input *input, const char *str, size_t i)
+{
+ const int is_num = str_is_num(str);
+ const size_t num_i = (size_t)ft_atoll(str);
+ const t_command c = input->command;
+ int res;
+
+ res = 0;
+ if (is_num != 0 && (c == next || c == draw || (c == setnode && i == 0)
+ || (c == addfet && i == 1) || (c == addnode && (input->argc == 1 || i == 1))
+ || (c == bind && i < 2)))
+ {
+ input->argv[i].val.num = num_i;
+ input->argv[i].type = num;
+ res = 1;
+ }
+ else if (!is_num)
+ {
+ if ((c == addnode && i == 0) || (c == setnode && i == 1))
+ {
+ res = parse_state(str, &input->argv[i].val.state);
+ input->argv[i].type = state;
+ }
+ else if (c == addfet && i == 0)
+ {
+ res = parse_type(str, &input->argv[i].val.type);
+ input->argv[i].type = type;
+ }
+ else if (c == help)
+ {
+ res = parse_command(str, &input->argv[i].val.command);
+ input->argv[i].type = command;
+ }
+ else if (c == bind && i == 2)
+ {
+ res = parse_terminal(str, &input->argv[i].val.terminal);
+ input->argv[i].type = terminal;
+ }
+ }
+ return (res);
+}
+
+int construct_input(t_input *input, char **split_inp)
+{
+ size_t i;
+ t_input tmp;
+
+ tmp.argc = split_length(split_inp) - 1;
+ if (!parse_command(split_inp[0], &tmp.command))
+ return (0);
+ if (!has_correct_argc(tmp))
+ return (0);
+ i = 0;
+ while (i < tmp.argc)
+ {
+ if (!parse_arg(&tmp, split_inp[i + 1], i))
+ return (0);
+ ++i;
+ }
+ *input = tmp;
+ return (1);
+}
+
+int get_input(t_input *input)
+{
+ int res;
+ char *str_inp;
+ char **split_inp;
+
+ str_inp = get_next_line(0);
+ if (!str_inp)
+ {
+ input->command = exitsim;
+ input->argc = 0;
+ return (1);
+ }
+ if (str_inp[0] == '\n')
+ return (1);
+ if (str_inp[0] && str_inp[ft_strlen(str_inp) - 1] == '\n')
+ str_inp[ft_strlen(str_inp) - 1] = '\0';
+ split_inp = ft_split(str_inp, ' ');
+ res = construct_input(input, split_inp);
+ if (!res)
+ {
+ command_not_found(str_inp);
+ }
+ free(str_inp);
+ free_split(split_inp);
+ return (res);
+}
+
+int process_input(t_vec *nodes, t_vec *mosfets)
+{
+ int res;
+ static t_input input = {.command = help, .argc = 0};
+
+ ft_printf("FET_sim>");
+ if (!get_input(&input))
+ return (1);
+ res = 1;
+ if (input.command == next)
+ res = c_next(input, nodes, mosfets);
+ else if (input.command == draw)
+ res = c_draw(input, nodes, mosfets);
+ else if (input.command == setnode)
+ res = c_setnode(input, nodes);
+ else if (input.command == addnode)
+ res = c_addnode(input, nodes);
+ else if (input.command == addfet)
+ res = c_addfet(input, mosfets);
+ else if (input.command == bind)
+ res = c_bind(input, nodes, mosfets);
+ else if (input.command == help)
+ res = c_help(input);
+ else if (input.command == exitsim)
+ res = 0;
+ return (res);
+}
+
+int main(__attribute__((unused)) int argc, char **argv)
+{
+ t_vec nodes;
+ t_vec mosfets;
+
+ print_start();
+ ft_vec_init(&nodes, sizeof(t_node));
+ ft_vec_init(&mosfets, sizeof(t_mosfet));
+ build_graph(argv[1], &nodes, &mosfets);
+ while (process_input(&nodes, &mosfets))
+ {
+ continue ;
+ }
+ update_nodes(NULL);
+ ft_vec_free(&nodes, free_node);
+ ft_vec_free(&mosfets, NULL);
+ return (0);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+static void update_mosfet(t_mosfet *mosfet)
+{
+ t_state state;
+
+ state = mosfet->gate->state;
+ if (mosfet->type == p && state == on)
+ mosfet->is_opened = 1;
+ else if (mosfet->type == n && state == off)
+ mosfet->is_opened = 1;
+ else
+ mosfet->is_opened = 0;
+ return ;
+}
+
+static void update_mosfets(t_vec *mosfets)
+{
+ size_t i;
+ t_mosfet *mosfet;
+
+ i = 0;
+ while (i < mosfets->size)
+ {
+ mosfet = ft_vec_access(mosfets, i);
+ update_mosfet(mosfet);
+ ++i;
+ }
+ return ;
+}
+
+int sim_step(t_vec *nodes, t_vec *mosfets)
+{
+ update_nodes(nodes);
+ update_mosfets(mosfets);
+ return (1);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+#include <stdlib.h>
+
+static t_node *get_neighbour_node(const t_mosfet *mosfet, const t_node *start)
+{
+ if (mosfet->source == start)
+ return (mosfet->drain);
+ return (mosfet->source);
+}
+
+static void find_connected(t_node *node, t_vec *connected_nodes)
+{
+ size_t i;
+ t_node *neigh_node;
+ t_mosfet *mosfet;
+
+ if (node->checked)
+ return ;
+ node->checked = 1;
+ ft_vec_append(connected_nodes, &node);
+ i = 0;
+ while (i < node->connected.size)
+ {
+ mosfet = *(t_mosfet **)ft_vec_access(&node->connected, i);
+ if (mosfet->is_opened)
+ {
+ neigh_node = get_neighbour_node(mosfet, node);
+ find_connected(neigh_node, connected_nodes);
+ }
+ ++i;
+ }
+ return ;
+}
+
+static void reset_nodes(t_vec *nodes)
+{
+ size_t i;
+ t_node *node;
+
+ i = 0;
+ while (i < nodes->size)
+ {
+ node = ft_vec_access(nodes, i);
+ node->checked = 0;
+ ++i;
+ }
+ return ;
+}
+
+// passing NULL signals update_nodes should clean connected_nodes
+// and should be called before end
+//
+// I don't know how irresponsible it is to let OS clear those things
+// so I provide this mechanism. It may be removed in the future if
+// it seems to be a reasonable decision.
+
+void update_nodes(t_vec *nodes)
+{
+ size_t i;
+ t_state state;
+ t_node *cur_node;
+ static t_vec connected_nodes = VEC_INIT(sizeof(t_node *));
+
+ if (!nodes)
+ {
+ free(connected_nodes.vec);
+ return ;
+ }
+ reset_nodes(nodes);
+ i = 0;
+ while (i < nodes->size)
+ {
+ cur_node = ft_vec_access(nodes, i);
+ if (!cur_node->checked)
+ {
+ find_connected(cur_node, &connected_nodes);
+ state = resolve_state(&connected_nodes);
+ apply_state(reduce_state(state), &connected_nodes);
+ ft_vec_forget_range(&connected_nodes, connected_nodes.size, 0);
+ }
+ ++i;
+ }
+ ft_vec_free(&connected_nodes, NULL);
+ return ;
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+// Monospace table of state resolution
+// s2 \ s1 | short | off | on | pull_d | pull_u | float | unknown
+// --------|-------|-------|-------|--------|--------|--------|---------
+// short | short | short | short | short | short | short | short
+// --------|-------|-------|-------|--------|--------|--------|---------
+// off | short | off | short | off | off | off | off
+// --------|-------|-------|-------|--------|--------|--------|---------
+// on | short | short | on | on | on | on | on
+// --------|-------|-------|-------|--------|--------|--------|---------
+// pull_d | short | off | on | pull_d | pull_d | pull_d | pull_d
+// --------|-------|-------|-------|--------|--------|--------|---------
+// pull_u | short | off | on | pull_d | pull_u | pull_u | pull_u
+// --------|-------|-------|-------|--------|--------|--------|---------
+// float | short | off | on | pull_d | pull_u | float | float
+// --------|-------|-------|-------|--------|--------|--------|---------
+// unknown | short | off | on | pull_d | pull_u | float | unknown
+//
+// It may be possible to construct the enum e_state in such a way that
+// this function is easy arithmetics.
+
+t_state simple_resolve_state(t_state s1, t_state s2)
+{
+ if (s1 == s2)
+ return (s1);
+ if (s1 == zkrat || s2 == zkrat)
+ return (zkrat);
+ if ((s1 == off && s2 == on) || (s1 == on && s2 == off))
+ return (zkrat);
+ if (s1 == on || s2 == on)
+ return (on);
+ if (s1 == off || s2 == off)
+ return (off);
+ if (s1 == pull_down || s2 == pull_down)
+ return (pull_down);
+ if (s1 == pull_up || s2 == pull_up)
+ return (pull_up);
+ if (s1 == floating || s2 == floating)
+ return (floating);
+ return (unknown);
+}
+
+t_state resolve_state(t_vec *connected_nodes)
+{
+ size_t i;
+ t_state state;
+ t_node *node;
+
+ i = 0;
+ state = unknown;
+ while (i < connected_nodes->size)
+ {
+ node = *(t_node **)ft_vec_access(connected_nodes, i);
+ state = simple_resolve_state(state, node->set_state);
+ ++i;
+ }
+ return (state);
+}
+
+void apply_state(t_state state, t_vec *connected_nodes)
+{
+ size_t i;
+ t_node *node;
+
+ i = 0;
+ while (i < connected_nodes->size)
+ {
+ node = *(t_node **)ft_vec_access(connected_nodes, i);
+ node->state = state;
+ ++i;
+ }
+ return ;
+}
+
+t_state reduce_state(t_state state)
+{
+ if (state == pull_down)
+ return (off);
+ if (state == pull_up)
+ return (on);
+ if (state == unknown)
+ return (floating);
+ return (state);
+}
--- /dev/null
+#include "FET_sim.h"
+#include "libft.h"
+
+static const char g_version_str[] = "0.0";
+
+static const char g_next_help_str[] = ""
+ "next [STEPS]\n"
+ "Advances the simulation\n\n"
+ "STEPS\n"
+ "\tAdvances the simulation by STEPS number of steps.\n"
+ "\tDefaults to 1 when not included.\n\n";
+
+static const char g_draw_help_str[] = ""
+ "draw [IND]\n"
+ "Draws the current state of the simulation.\n"
+ "IND\n"
+ "\tDraws the transistors with the index number IND.\n"
+ "\tDefaults to drawing every transistor.\n\n";
+
+static const char g_setnode_help_str[] = ""
+ "setnode IND STATE\n"
+ "Sets the \"set_state\" of the node with index IND to state STATE.\n\n";
+
+static const char g_addnode_help_str[] = ""
+ "addnode [STATE] [NUM]\n"
+ "Adds new nodes.\n"
+ "NUM\n"
+ "\tAdds NUM new nodes.\n"
+ "\tDefaults to 1.\n\n"
+ "STATE\n"
+ "\tSets \"set_state\" of new nodes to STATE.\n"
+ "\tDefaults to unknown state.\n\n";
+
+static const char g_addfet_help_str[] = ""
+ "addfet TYPE [NUM]\n"
+ "Adds new transistors of type TYPE.\n"
+ "NUM\n"
+ "\tAdds NUM new transistors.\n"
+ "\tDefaults to 1.\n\n";
+
+static const char g_bind_help_str[] = ""
+ "bind NODE FET TERMINAL\n"
+ "Binds node with index NODE to the TERMINAL of transitor indexed by FET.\n"
+ "Possible values for TERMINAL are gate, source and drain.\n\n";
+
+static const char g_help_help_str[] = ""
+ "help [COMMAND]\n"
+ "Prints a simple explanation.\n"
+ "COMMAND\n"
+ "\tPrints explanation of COMMAND.\n"
+ "\tWhen no COMMAND is provided, the general help with list of commands is shown.\n\n";
+
+static const char g_help_exit_str[] = ""
+ "exit [...]\n"
+ "Exits FET_sim. One may also use ctrl-D.\n"
+ "[...]\n"
+ "\tAnything after the command is ignored.\n\n";
+
+static const char g_general_help_str[] = ""
+ "This is a FET_sim - simulator of FET (Field Effect Transistor) logic.\n"
+ "Version number: %s"
+ "You can use the following commands:\n"
+ "next [STEPS] \t\t- advances the simulation\n"
+ "draw [IND] \t\t- draws the state of the simulation\n"
+ "setnode IND STATE \t- sets the \"set_state\" of the node indexed by IND to STATE\n"
+ "addnode [STATE] [NUM] \t- adds new nodes\n"
+ "addfet TYPE [NUM] \t- adds new FETs\n"
+ "bind NODE FET TERMINAL \t- binds node indexed by NODE to TERMINAL\n \
+ \t\t\t of transistor indexed by FET\n"
+ "help [COMMAND] \t\t- shows this help or help for COMMAND\n"
+ "exit [...] \t\t- exits this program\n\n";
+
+void print_help(t_command c)
+{
+ if (c == next)
+ ft_printf(g_next_help_str);
+ else if (c == draw)
+ ft_printf(g_draw_help_str);
+ else if (c == setnode)
+ ft_printf(g_setnode_help_str);
+ else if (c == addnode)
+ ft_printf(g_addnode_help_str);
+ else if (c == addfet)
+ ft_printf(g_addfet_help_str);
+ else if (c == bind)
+ ft_printf(g_bind_help_str);
+ else if (c == help)
+ ft_printf(g_help_help_str);
+ else if (c == exitsim)
+ ft_printf(g_help_exit_str);
+ else
+ ft_printf(g_general_help_str, g_version_str);
+ return ;
+}
+
+void command_not_found(const char *input)
+{
+ ft_printf("The command \"%s\" is not a proper FET_sim command.\n", input);
+ return ;
+}
+
+void print_start(void)
+{
+ ft_printf("FET_sim, version %s\n"
+ "FET_sim is a simulator of FET logic.\n"
+ "If you need some guidence, use the \"help\" command.\n",
+ g_version_str);
+ return ;
+}
+
+void print_index_error(size_t index, size_t size)
+{
+ if (size > 0)
+ {
+ ft_printf("This action is invalid as given index %u "
+ "is larger then the highest index present %u.\n",
+ index, size - 1);
+ }
+ else
+ {
+ ft_printf("This action is invalid as there is no element yet.\n");
+ }
+ return ;
+}