summaryrefslogtreecommitdiff
path: root/expand.c
blob: e88ec6c86c718b0d261878b3033f09817acb312c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "expand.h"
#include "preproc.h"
#include "utils.h"
#include <string.h>


typedef struct {
    QuotationMode qmode;  
    char* content;
} ExpandedChunk;


ExpandedChunk expand_chunk(Chunk chunk, ShellState* shstate) {
    char* content;
    if (chunk.qmode == SINGLE_Q || chunk.kind == LITERAL) {
        if (chunk.qmode == SINGLE_Q && chunk.kind != LITERAL) exit(69);
        content = chunk.as.literal_str;
    } else if (chunk.kind == VAR_EXP) {
        content = get_var(chunk.as.varname, shstate);
    } else if (chunk.kind == REGION_EXP) {
        exit(7); // Not supported yet; arithm
    }
    return (ExpandedChunk){.qmode = chunk.qmode, .content = content};
}


typedef struct {
    StrVec complete_strs;
    String active_str;
} WordSplittingGerm;

void add_expchunk(char* next_str, WordSplittingGerm* curr_res) {
     for (int pos = 0; pos < strlen(next_str); pos++) {
        if (next_str[pos] == ' ') {
            push_to_StrVec(&curr_res->complete_strs, inner(&curr_res->active_str));
            curr_res->active_str = make_String(256);
        } else {
            push_to_String(&curr_res->active_str, next_str[pos]);
        }
    }
}


void expand_word(Word word, SlotVec* target, ShellState* shstate) {
    WordSplittingGerm curr_res = {
        .complete_strs = make_StrVec(256),
        .active_str = make_String(256)
    };    
    for (int i = 0; i < word.count; i++) {
        Chunk chunk = **get_from_Word(&word, i);
        ExpandedChunk expchunk = expand_chunk(chunk, shstate);
        switch (expchunk.qmode) {
            case UN_Q:
                add_expchunk(expchunk.content, &curr_res);
                break;
            case SINGLE_Q:
                append_str_to_String(&curr_res.active_str, expchunk.content);
                break;
            case DOUBLE_Q:
                // TODO: further expansions here
                append_str_to_String(&curr_res.active_str, expchunk.content);
                break;
        }
    }
    for (int j = 0; j < curr_res.complete_strs.count; j++) {
        char* str = *get_from_StrVec(&curr_res.complete_strs, j);
        push_to_SlotVec(target, (Slot){.kind = SLOT_STR, .as.str = str});
    }
}

ExpandedPipelineElement expand_pipeline_element(PipelineElement elem, ShellState* shstate) {
    ExpandedPipelineElement result = {.cmd_slots = make_SlotVec(256), .conn = elem.conn};
    for (int i = 0; i < elem.cmd_toks.count; i++) {
        Token curr_tok = *get_from_TokenVec(&elem.cmd_toks, i);
        switch (curr_tok.kind) {
            case TOK_WORD:
                expand_word(curr_tok.as.word, &result.cmd_slots, shstate);
                break;
            case TOK_SPECIAL:
                push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_SPEC, .as.spec = curr_tok.as.spec});
                break;
            case TOK_PROCSUB_IN:
                push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_IN, .as.proc_reg= curr_tok.as.procsub_region});
                break;
            case TOK_PROCSUB_OUT:
                push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_OUT, .as.proc_reg= curr_tok.as.procsub_region});
                break;
        }
    }
    return result;
}

ExpandedPipeline expand_pipeline(Pipeline* pl, ShellState *shstate) {
    ExpandedPipeline exp_pl = make_ExpandedPipeline(256);
    for (int i = 0; i < pl->count; i++) {
        PipelineElement elem = *get_from_Pipeline(pl, i);
        ExpandedPipelineElement exp_elem = expand_pipeline_element(elem, shstate);
        push_to_ExpandedPipeline(&exp_pl, exp_elem);
    }
    return exp_pl;
}