tests: fix non-portable "${var:-"str"}" construct
[git] / resolve-undo.c
1 #include "cache.h"
2 #include "dir.h"
3 #include "resolve-undo.h"
4 #include "string-list.h"
5
6 /* The only error case is to run out of memory in string-list */
7 void record_resolve_undo(struct index_state *istate, struct cache_entry *ce)
8 {
9         struct string_list_item *lost;
10         struct resolve_undo_info *ui;
11         struct string_list *resolve_undo;
12         int stage = ce_stage(ce);
13
14         if (!stage)
15                 return;
16
17         if (!istate->resolve_undo) {
18                 resolve_undo = xcalloc(1, sizeof(*resolve_undo));
19                 resolve_undo->strdup_strings = 1;
20                 istate->resolve_undo = resolve_undo;
21         }
22         resolve_undo = istate->resolve_undo;
23         lost = string_list_insert(resolve_undo, ce->name);
24         if (!lost->util)
25                 lost->util = xcalloc(1, sizeof(*ui));
26         ui = lost->util;
27         oidcpy(&ui->oid[stage - 1], &ce->oid);
28         ui->mode[stage - 1] = ce->ce_mode;
29 }
30
31 void resolve_undo_write(struct strbuf *sb, struct string_list *resolve_undo)
32 {
33         struct string_list_item *item;
34         for_each_string_list_item(item, resolve_undo) {
35                 struct resolve_undo_info *ui = item->util;
36                 int i;
37
38                 if (!ui)
39                         continue;
40                 strbuf_addstr(sb, item->string);
41                 strbuf_addch(sb, 0);
42                 for (i = 0; i < 3; i++)
43                         strbuf_addf(sb, "%o%c", ui->mode[i], 0);
44                 for (i = 0; i < 3; i++) {
45                         if (!ui->mode[i])
46                                 continue;
47                         strbuf_add(sb, ui->oid[i].hash, the_hash_algo->rawsz);
48                 }
49         }
50 }
51
52 struct string_list *resolve_undo_read(const char *data, unsigned long size)
53 {
54         struct string_list *resolve_undo;
55         size_t len;
56         char *endptr;
57         int i;
58         const unsigned rawsz = the_hash_algo->rawsz;
59
60         resolve_undo = xcalloc(1, sizeof(*resolve_undo));
61         resolve_undo->strdup_strings = 1;
62
63         while (size) {
64                 struct string_list_item *lost;
65                 struct resolve_undo_info *ui;
66
67                 len = strlen(data) + 1;
68                 if (size <= len)
69                         goto error;
70                 lost = string_list_insert(resolve_undo, data);
71                 if (!lost->util)
72                         lost->util = xcalloc(1, sizeof(*ui));
73                 ui = lost->util;
74                 size -= len;
75                 data += len;
76
77                 for (i = 0; i < 3; i++) {
78                         ui->mode[i] = strtoul(data, &endptr, 8);
79                         if (!endptr || endptr == data || *endptr)
80                                 goto error;
81                         len = (endptr + 1) - (char*)data;
82                         if (size <= len)
83                                 goto error;
84                         size -= len;
85                         data += len;
86                 }
87
88                 for (i = 0; i < 3; i++) {
89                         if (!ui->mode[i])
90                                 continue;
91                         if (size < rawsz)
92                                 goto error;
93                         oidread(&ui->oid[i], (const unsigned char *)data);
94                         size -= rawsz;
95                         data += rawsz;
96                 }
97         }
98         return resolve_undo;
99
100 error:
101         string_list_clear(resolve_undo, 1);
102         error("Index records invalid resolve-undo information");
103         return NULL;
104 }
105
106 void resolve_undo_clear_index(struct index_state *istate)
107 {
108         struct string_list *resolve_undo = istate->resolve_undo;
109         if (!resolve_undo)
110                 return;
111         string_list_clear(resolve_undo, 1);
112         free(resolve_undo);
113         istate->resolve_undo = NULL;
114         istate->cache_changed |= RESOLVE_UNDO_CHANGED;
115 }
116
117 int unmerge_index_entry_at(struct index_state *istate, int pos)
118 {
119         const struct cache_entry *ce;
120         struct string_list_item *item;
121         struct resolve_undo_info *ru;
122         int i, err = 0, matched;
123         char *name;
124
125         if (!istate->resolve_undo)
126                 return pos;
127
128         ce = istate->cache[pos];
129         if (ce_stage(ce)) {
130                 /* already unmerged */
131                 while ((pos < istate->cache_nr) &&
132                        ! strcmp(istate->cache[pos]->name, ce->name))
133                         pos++;
134                 return pos - 1; /* return the last entry processed */
135         }
136         item = string_list_lookup(istate->resolve_undo, ce->name);
137         if (!item)
138                 return pos;
139         ru = item->util;
140         if (!ru)
141                 return pos;
142         matched = ce->ce_flags & CE_MATCHED;
143         name = xstrdup(ce->name);
144         remove_index_entry_at(istate, pos);
145         for (i = 0; i < 3; i++) {
146                 struct cache_entry *nce;
147                 if (!ru->mode[i])
148                         continue;
149                 nce = make_cache_entry(istate,
150                                        ru->mode[i],
151                                        &ru->oid[i],
152                                        name, i + 1, 0);
153                 if (matched)
154                         nce->ce_flags |= CE_MATCHED;
155                 if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
156                         err = 1;
157                         error("cannot unmerge '%s'", name);
158                 }
159         }
160         free(name);
161         if (err)
162                 return pos;
163         free(ru);
164         item->util = NULL;
165         return unmerge_index_entry_at(istate, pos);
166 }
167
168 void unmerge_marked_index(struct index_state *istate)
169 {
170         int i;
171
172         if (!istate->resolve_undo)
173                 return;
174
175         for (i = 0; i < istate->cache_nr; i++) {
176                 const struct cache_entry *ce = istate->cache[i];
177                 if (ce->ce_flags & CE_MATCHED)
178                         i = unmerge_index_entry_at(istate, i);
179         }
180 }
181
182 void unmerge_index(struct index_state *istate, const struct pathspec *pathspec)
183 {
184         int i;
185
186         if (!istate->resolve_undo)
187                 return;
188
189         for (i = 0; i < istate->cache_nr; i++) {
190                 const struct cache_entry *ce = istate->cache[i];
191                 if (!ce_path_match(istate, ce, pathspec, NULL))
192                         continue;
193                 i = unmerge_index_entry_at(istate, i);
194         }
195 }