Merge pull request #35 from DevManu-de/dev-redirect-handle
[psh.git] / lib / stringbuilder.c
blob1496794458f1c7a572c8b9763c0495d59513db9d
1 /*
2 libpsh/stringbuilder.c - string builder
3 Copyright 2020 Zhang Maiyun
5 This file is part of Psh, P shell.
7 Psh is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Psh is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
25 #include <stddef.h>
26 #include <string.h>
27 #ifdef DEBUG
28 #include <stdio.h>
29 #endif
31 #include "libpsh/stringbuilder.h"
32 #include "libpsh/xmalloc.h"
34 /* Create a new builder */
35 psh_stringbuilder *psh_stringbuilder_create()
37 psh_stringbuilder *builder = xmalloc(sizeof(psh_stringbuilder));
38 builder->total_length = 0;
39 builder->current = builder->first = NULL;
40 return builder;
43 /* Append a string starting at *STRING with a length of LENGTH to the builder.
44 STRING gets free()d if IF_FREE is 1 */
45 const char *psh_stringbuilder_add_length(psh_stringbuilder *builder,
46 const char *string, size_t length,
47 int if_free)
49 struct _psh_sb_item *previous;
50 /* Don't waste memory here */
51 if (length == 0)
52 return string;
53 builder->total_length += length;
54 if (builder->current)
56 /* Not empty */
57 #ifdef DEBUG
58 printf("[psh_stringbuilder_add_length]\n");
59 printf("orig this: %p\n", builder->current->next);
60 #endif
61 builder->current->next = xmalloc(sizeof(struct _psh_sb_item));
62 #ifdef DEBUG
63 printf("this: %p\n", builder->current->next);
64 printf("last: %p\n", builder->current);
65 printf("orig string: %p\n", builder->current->next->string);
66 printf("string: %s\n", string);
67 #endif
68 previous = builder->current;
69 builder->current = builder->current->next;
71 else
73 /* Empty */
74 builder->first = xmalloc(sizeof(struct _psh_sb_item));
75 builder->current = builder->first;
76 previous = NULL;
78 /* Now current is to be filled */
79 builder->current->previous = previous;
80 builder->current->length = length;
81 builder->current->string = string;
82 builder->current->if_free = if_free;
83 builder->current->next = NULL;
84 /* Now current is filled */
85 return string;
88 /* Append STRING to the builder */
89 const char *psh_stringbuilder_add(psh_stringbuilder *builder,
90 const char *string, int if_free)
92 size_t length = strlen(string);
93 return psh_stringbuilder_add_length(builder, string, length, if_free);
96 /* Remove the last member of the builder */
97 void psh_stringbuilder_pop(psh_stringbuilder *builder)
99 builder->total_length -= builder->current->length;
100 if (builder->current->if_free)
101 xfree(builder->current->string);
102 builder->current = builder->current->previous;
103 xfree(builder->current->next);
104 builder->current->next = NULL;
107 /* Generate a string from the builder */
108 char *psh_stringbuilder_yield(psh_stringbuilder *builder)
110 struct _psh_sb_item *cur_from = builder->first;
111 char *result = xmalloc(P_CS * builder->total_length + 1);
112 char *cur_to = result;
113 while (cur_from)
115 /* Copy the string without trailing NUL */
116 memmove(cur_to, cur_from->string, cur_from->length);
117 /* Increase result pointer */
118 cur_to += cur_from->length;
119 /* Get next string */
120 cur_from = cur_from->next;
122 /* NUL-terminate */
123 result[builder->total_length] = 0;
124 return result;
127 /* Free resources used by the builder */
128 void psh_stringbuilder_free(psh_stringbuilder *builder)
130 struct _psh_sb_item *cur = builder->first;
131 while (1)
133 if (cur->if_free)
134 xfree(cur->string);
135 xfree(cur->previous);
136 if (!cur->next)
138 xfree(cur);
139 break;
141 cur = cur->next;
143 xfree(builder);