7d3610a9ca89a47255a284ee523c61eb6ab04d05
7 /* This is the famous DJB hash */
9 djb_hash(const char *name
)
11 unsigned int val
= 5381;
14 for (i
= 0; name
[i
]; i
++)
16 val
= (33 * val
) + name
[i
];
23 chop_filename(const char *target
)
25 char *last_slash
= strrchr(target
, '/');
27 last_slash
= strrchr(target
, '\\');
29 return last_slash
+ 1;
35 chop_dirname(const char *name
, char **dirname
)
37 char *last_slash
= strrchr(name
, '/');
39 last_slash
= strrchr(name
, '\\');
47 char *newdata
= malloc(last_slash
- name
+ 1);
48 memcpy(newdata
, name
, last_slash
- name
);
49 newdata
[last_slash
- name
] = 0;
54 static struct target_dir_entry
*
55 get_entry_by_normname(struct target_dir_hash
*dh
, const char *norm
)
57 unsigned int hashcode
;
58 struct target_dir_entry
*de
;
59 hashcode
= djb_hash(norm
);
60 de
= dh
->buckets
[hashcode
% NUM_DIR_HASH_BUCKETS
];
61 while (de
&& strcmp(de
->normalized_name
, norm
))
62 de
= de
->next_dir_hash_entry
;
67 delete_entry(struct target_dir_hash
*dh
, struct target_dir_entry
*de
)
69 struct target_dir_entry
**ent
;
70 ent
= &dh
->buckets
[de
->hashcode
% NUM_DIR_HASH_BUCKETS
];
71 while (*ent
&& ((*ent
) != de
))
72 ent
= &(*ent
)->next_dir_hash_entry
;
74 *ent
= (*ent
)->next_dir_hash_entry
;
77 void normalize_dirname(char *filename
)
82 for (i
= 0, tgt
= 0; filename
[i
]; i
++)
86 if (filename
[i
] != '/' && filename
[i
] != '\\')
88 filename
[tgt
++] = toupper(filename
[i
]);
94 if (filename
[i
] == '/' || filename
[i
] == '\\')
97 filename
[tgt
++] = DIR_SEPARATOR_CHAR
;
101 filename
[tgt
++] = toupper(filename
[i
]);
107 while (tgt
&& (filename
[--tgt
] == DIR_SEPARATOR_CHAR
))
113 struct target_dir_entry
*
114 dir_hash_create_dir(struct target_dir_hash
*dh
, const char *casename
, const char *targetnorm
)
116 struct target_dir_entry
*de
, *parent_de
;
117 char *parentname
= NULL
;
118 char *parentcase
= NULL
;
119 struct target_dir_entry
**ent
;
121 if (!dh
->root
.normalized_name
)
123 dh
->root
.normalized_name
= strdup("");
124 dh
->root
.case_name
= strdup("");
125 dh
->root
.hashcode
= djb_hash("");
126 dh
->buckets
[dh
->root
.hashcode
% NUM_DIR_HASH_BUCKETS
] = &dh
->root
;
129 de
= get_entry_by_normname(dh
, targetnorm
);
133 chop_dirname(targetnorm
, &parentname
);
134 chop_dirname(casename
, &parentcase
);
135 parent_de
= dir_hash_create_dir(dh
, parentcase
, parentname
);
139 de
= calloc(1, sizeof(*de
));
142 de
->parent
= parent_de
;
143 de
->normalized_name
= strdup(targetnorm
);
144 de
->case_name
= strdup(chop_filename(casename
));
145 de
->hashcode
= djb_hash(targetnorm
);
147 de
->next
= parent_de
->child
;
148 parent_de
->child
= de
;
150 ent
= &dh
->buckets
[de
->hashcode
% NUM_DIR_HASH_BUCKETS
];
153 ent
= &(*ent
)->next_dir_hash_entry
;
160 void dir_hash_add_file(struct target_dir_hash
*dh
, const char *source
, const char *target
)
162 struct target_file
*tf
;
163 struct target_dir_entry
*de
;
164 char *targetdir
= NULL
;
167 chop_dirname(target
, &targetdir
);
168 targetnorm
= strdup(targetdir
);
169 normalize_dirname(targetnorm
);
170 de
= dir_hash_create_dir(dh
, targetdir
, targetnorm
);
174 tf
= calloc(1, sizeof(*tf
));
177 tf
->source_name
= strdup(source
);
178 tf
->target_name
= strdup(chop_filename(target
));
182 dir_hash_destroy_dir(struct target_dir_hash
*dh
, struct target_dir_entry
*de
)
184 struct target_file
*tf
;
185 struct target_dir_entry
*te
;
187 while ((te
= de
->child
))
189 de
->child
= te
->next
;
190 dir_hash_destroy_dir(dh
, te
);
193 while ((tf
= de
->head
))
196 free(tf
->source_name
);
197 free(tf
->target_name
);
201 delete_entry(dh
, de
);
202 free(de
->normalized_name
);
206 void dir_hash_destroy(struct target_dir_hash
*dh
)
208 dir_hash_destroy_dir(dh
, &dh
->root
);