is there segmentation fault
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "pmake.h"

/******************************************************************************
 * Newly defined helper functions
 *****************************************************************************/

/* Makes a new Rule struct
 */
Rule *make_rule(Rule **head, char *line);

/* Link dependency and make new rules if nessecary
 * note: assume no circular dependency
 */
Dependency *link_dependency(Rule **head, char *token);

/* Add action to rule
 */
void make_action(Rule *rule, char *line);

Rule *make_rule(Rule **head, char *line)
{
    const char delim[3] = "\t ";
    char *token;
    token = strtok(line, delim);
    int len = strlen(token);

    // check if target is in a rule already (due to dependency making the rule beforehand)
    Rule *curr;
    if (*head == NULL)
    {
        *head = calloc(1, sizeof(Rule));
        curr = *head;
    }
    else
    {
        curr = *head;
        while (curr->next_rule != NULL)
        {
            if (strcmp(curr->target, token) == 0)
            {
                break;
            }
            curr = curr->next_rule;
        }
        if (strcmp(curr->target, token) != 0)
        {
            curr->next_rule = calloc(1, sizeof(Rule));
            curr = curr->next_rule;
        }
    }
    
    // assumed correct format, first two tokens are target and ':'
    curr->target = malloc(sizeof(char) * (len + 1));
    strncpy(curr->target, token, len);
    curr->target[len] = '\0';
    token = strtok(NULL, delim);
    if (strcmp(token, ":") != 0)
    {
        fprintf(stderr, "assumption not fulfilled");
        exit(1);
    }
    Dependency *depend_curr = curr->dependencies;
    token = strtok(NULL, delim);
    while (token != NULL)
    {
        if (curr->dependencies == NULL)
        {
            depend_curr = link_dependency(head, token);
            curr->dependencies = depend_curr;
        }
        else
        {
            while (depend_curr->next_dep != NULL)
            {
                depend_curr = depend_curr->next_dep;
            }
            
            depend_curr->next_dep = link_dependency(head, token);
            depend_curr = depend_curr->next_dep;
        }
    }

    return curr;
}

void make_action(Rule *rule, char *line)
{
    Action *new_action = calloc(1, sizeof(Action));
    const char delim[3] = "\t ";
    int count = 0;
    char *token;
    char line_count[MAXLINE];
    strncpy(line_count, line, MAXLINE);
    token = strtok(line_count, delim);

    while (token != NULL)
    {
        count++;
        token = strtok(NULL, delim);
    }
    if (count != 0)
    {
        new_action->args = malloc(sizeof(char *) * (count + 1));
        token = strtok(line, delim);
        int len = strlen(token);
        new_action->args[0] = malloc(sizeof(char) * (len + 1));
        strncpy(new_action->args[0], token, len);
        (new_action->args[0])[len] = '\0';
        for (int i = 1; i < count - 1; i++)
        {
            token = strtok(line, delim);
            len = strlen(token);
            new_action->args[i] = malloc(sizeof(char) * (len + 1));
            strncpy(new_action->args[i], token, len);
            (new_action->args[i])[len] = '\0';
        }
        new_action->args[count] = NULL;
    }
    
    if (rule->actions == NULL)
    {
        rule->actions = new_action;
    }
    else
    {
        Action *curr = rule->actions;
        while (curr->next_act != NULL)
        {
            curr = curr->next_act;
        }
        curr->next_act = new_action;
    }
}

Dependency *link_dependency(Rule **head, char *token)
{
    Rule *curr = *head;
    Dependency *depend = calloc(1, sizeof(Dependency));
    // link_dependency called implies at least one rule is stored/linked in head
    while (curr->next_rule != NULL)
    {
        if (strcmp(curr->target, token) == 0)
        {
            break;
        }
        curr = curr->next_rule;
    }
    if (strcmp(curr->target, token) != 0)
    {
        char sim_line[MAXLINE];
        // assuming correct format, each target has max length MAXLINE-4
        strncat(sim_line, token, (MAXLINE-4));
        strcat(sim_line, " : ");
        sim_line[MAXLINE - 1] = '\0';
        // assume every entry is unique
        curr = make_rule(head, sim_line);
    }
    depend->rule = curr;
    return depend;
}

/* Read from the open file fp, and create the linked data structure
   that represents the Makefile contained in the file.
   See the top of pmake.h for the specification of Makefile contents.
 */
Rule *parse_file(FILE *fp)
{
    char line[MAXLINE];

    Rule *head = NULL;
    Rule *curr = NULL;

    while (fgets(line, MAXLINE, fp) != NULL)
    {
        if (is_comment_or_empty(line))
        {
            continue;
        }
        // assumed at least one rule exists and is at beginnint, 
        // so the if part will at least execute once before the else part meaning curr is well defined
        if (line[0] != '\t')
        {
            curr = make_rule(&head, line);
        }
        else{
            make_action(curr, line);
        }
    }
    return head;
}

/******************************************************************************
 * These helper functions are provided for you. Do not modify them.
 *****************************************************************************/
/* Print the list of actions */
void print_actions(Action *act)
{
    while (act != NULL)
    {
        if (act->args == NULL)
        {
            fprintf(stderr, "ERROR: action with NULL args\n");
            act = act->next_act;
            continue;
        }
        printf("\t");

        int i = 0;
        while (act->args[i] != NULL)
        {
            printf("%s ", act->args[i]);
            i++;
        }
        printf("\n");
        act = act->next_act;
    }
}

/* Print the list of rules to stdout in makefile format. If the output
   of print_rules is saved to a file, it should be possible to use it to
   run make correctly.
 */
void print_rules(Rule *rules)
{
    Rule *cur = rules;

    while (cur != NULL)
    {
        if (cur->dependencies || cur->actions)
        {
            // Print target
            printf("%s : ", cur->target);

            // Print dependencies
            Dependency *dep = cur->dependencies;
            while (dep != NULL)
            {
                if (dep->rule->target == NULL)
                {
                    fprintf(stderr, "ERROR: dependency with NULL rule\n");
                }
                printf("%s ", dep->rule->target);
                dep = dep->next_dep;
            }
            printf("\n");

            // Print actions
            print_actions(cur->actions);
        }
        cur = cur->next_rule;
    }
}

/* Return 1 if the line is a comment line, as defined on the assignment handout.
   Return 0 otherwise.
 */
int is_comment_or_empty(const char *line)
{
    for (int i = 0; i < strlen(line); i++)
    {
        if (line[i] == '#')
        {
            return 1;
        }
        if (line[i] != '\t' && line[i] != ' ')
        {
            return 0;
        }
    }
    return 1;
}

/* Convert an array of args to a single space-separated string in buffer.
   Returns buffer.  Note that memory for args and buffer should be allocted
   by the caller.
 */
char *args_to_string(char **args, char *buffer, int size)
{
    buffer[0] = '\0';
    int i = 0;
    while (args[i] != NULL)
    {
        strncat(buffer, args[i], size - strlen(buffer));
        strncat(buffer, " ", size - strlen(buffer));
        i++;
    }
    return buffer;
}
