// // aegis - project change supervisor // Copyright (C) 1997, 1998, 2002-2006, 2008 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #include #include // for assert #include #include #include static string_ty * abbreviate(string_ty *s, size_t max_len, int keep_last_dot) { size_t word_total; size_t punct_total; size_t total; char *cp; int j; // must be signed size_t k; size_t word_max; // // trivial sanity check // assert(max_len > 0); total = s->str_length; if (total <= max_len || max_len == 0) return str_copy(s); // // Break it all up into punctuation and words. // The punctuation *preceeds* the word. // string_list_ty word; string_list_ty punct; punct_total = 0; word_total = 0; cp = s->str_text; while (*cp) { char *start; string_ty *s1; start = cp; while (*cp && !isalnum((unsigned char)*cp)) ++cp; s1 = str_n_from_c(start, cp - start); punct.push_back(s1); punct_total += s1->str_length; str_free(s1); start = cp; if (*cp && isdigit((unsigned char)*cp)) { while (*cp && isdigit((unsigned char)*cp)) ++cp; } else { int was_upper = 1; while (*cp && isalpha((unsigned char)*cp)) { int is_upper = isupper((unsigned char)*cp); if (!was_upper && is_upper) break; was_upper = is_upper; ++cp; } } s1 = str_n_from_c(start, cp - start); word.push_back(s1); word_total += s1->str_length; str_free(s1); } assert(punct.nstrings); // can't be empty string assert(punct.nstrings == word.nstrings); // // kill leading punctuation // if (punct.string[0]->str_length) { total -= punct.string[0]->str_length; punct_total -= punct.string[0]->str_length; str_free(punct.string[0]); punct.string[0] = str_from_c(""); if (total <= max_len) goto reassemble; } // // kill trailing punctuation // if ( punct.string[punct.nstrings - 1]->str_length && !word.string[word.nstrings - 1]->str_length ) { total -= punct.string[punct.nstrings - 1]->str_length; punct_total -= punct.string[punct.nstrings - 1]->str_length; str_free(punct.string[--punct.nstrings]); str_free(word.string[--word.nstrings]); if (total <= max_len) goto reassemble; } assert(punct.nstrings); assert(punct.nstrings == word.nstrings); // // shorten punctuation to one character each // for (j = punct.nstrings - 1; j >= 0; --j) { string_ty *s1; if (punct.string[j]->str_length < 2) continue; total -= punct.string[j]->str_length - 1; punct_total -= punct.string[j]->str_length - 1; s1 = str_n_from_c(punct.string[j]->str_text, (size_t)1); str_free(punct.string[j]); punct.string[j] = s1; if (total <= max_len) goto reassemble; } // // nuke all punctuation if we are very squeezed for space // (except last dot, for file suffixes) // if (punct_total * 5 > max_len) { for (j = punct.nstrings - 1; j >= 0; --j) { if (!punct.string[j]->str_length) continue; assert(punct.string[j]->str_length == 1); if ( keep_last_dot && j == (int)punct.nstrings - 1 && punct.string[j]->str_text[0] == '.' ) continue; --total; --punct_total; str_free(punct.string[j]); punct.string[j] = str_from_c(""); if (total <= max_len) goto reassemble; } } // // shorten all the words // word_max = 1; for (k = 0; k < word.nstrings; ++k) if (word.string[k]->str_length > word_max) word_max = word.string[k]->str_length; --word_max; while (word_max >= 1) { for (j = word.nstrings - 1; j >= 0; --j) { string_ty *s1; if (word.string[j]->str_length <= word_max) continue; total -= (word.string[j]->str_length - word_max); s1 = str_n_from_c(word.string[j]->str_text, word_max); str_free(word.string[j]); word.string[j] = s1; if (total <= max_len) goto reassemble; } --word_max; } reassemble: static stracc_t ac; ac.clear(); for (k = 0; k < punct.nstrings; ++k) { string_ty *p = punct.string[k]; ac.push_back(p->str_text, p->str_length); p = word.string[k]; ac.push_back(p->str_text, p->str_length); } return ac.mkstr(); } static string_ty * nuke_unprintable(string_ty *s) { static char *buffer; static size_t buffer_max; char *ip; char *op; if (s->str_length > buffer_max) { for (;;) { buffer_max = buffer_max * 2 + 16; if (s->str_length <= buffer_max) break; } delete [] buffer; buffer = new char [buffer_max]; } ip = s->str_text; op = buffer; while (*ip) { unsigned char c; c = *ip++; if (isspace((unsigned char)c) || !isprint((unsigned char)c)) c = '_'; *op++ = c; } return str_n_from_c(buffer, op - buffer); } string_ty * abbreviate_dirname(string_ty *s, size_t max_len) { string_ty *s2; string_ty *result; s2 = nuke_unprintable(s); result = abbreviate(s2, max_len, 0); str_free(s2); return result; } string_ty * abbreviate_filename(string_ty *s, size_t max_len) { string_ty *s2; string_ty *result; s2 = nuke_unprintable(s); result = abbreviate(s2, max_len, 1); str_free(s2); return result; } static int contains_moronic_ms_restrictions(string_ty *fn) { static const char *const moronic[] = { "aux", "com1", "com2", "com3", "com4", "con", "nul", }; const char *const *cpp; string_ty *fn2; static string_list_ty wl; int result; if (wl.nstrings == 0) { for (cpp = moronic; cpp < ENDOF(moronic); ++cpp) { fn2 = str_from_c(*cpp); wl.push_back(fn2); str_free(fn2); } } fn2 = str_downcase(fn); result = wl.member(fn2); str_free(fn2); return result; } string_ty * abbreviate_8dos3(string_ty *s) { string_ty *s1; char *cp; string_ty *result; s1 = nuke_unprintable(s); cp = strrchr(s1->str_text, '.'); if (!cp) result = abbreviate(s1, 8, 0); else { string_ty *s2; string_ty *s2a; string_ty *s3; string_ty *s3a; s2 = str_n_from_c(s1->str_text, cp - s1->str_text); ++cp; s2a = abbreviate(s2, 8, 0); if ( s2a->str_length == 0 || !isalpha((unsigned char)s2a->str_text[0]) || contains_moronic_ms_restrictions(s2a) ) { string_ty *s4; str_free(s2a); s4 = str_format("a%s", s2->str_text); s2a = abbreviate(s4, 8, 0); str_free(s4); } str_free(s2); s3 = str_n_from_c(cp, s1->str_text + s1->str_length - cp); s3a = abbreviate(s3, 3, 0); str_free(s3); if (s3a->str_length) result = str_format("%s.%s", s2a->str_text, s3a->str_text); else result = str_copy(s2a); str_free(s2a); str_free(s3a); } str_free(s1); return result; }