source: branches/stable/mondo/mondo/common/libmondo-string.c @ 841

Last change on this file since 841 was 841, checked in by andree, 13 years ago

Fixed display problem in newt mode where old strings weren't fully
overwritten which led to garbled display by improving function
center_string(). (This is also the fix for Debian bug #320152.)

  • Property svn:keywords set to Id
File size: 29.4 KB
Line 
1/* $Id: libmondo-string.c 841 2006-09-26 12:47:02Z andree $ */
2
3
4/**
5 * @file
6 * Functions for handling strings.
7 */
8
9#include "my-stuff.h"
10#include "mondostructures.h"
11#include "libmondo-string.h"
12#include "lib-common-externs.h"
13#include "libmondo-files-EXT.h"
14#include "libmondo-gui-EXT.h"
15#include "libmondo-tools-EXT.h"
16
17/*@unused@*/
18//static char cvsid[] = "$Id: libmondo-string.c 841 2006-09-26 12:47:02Z andree $";
19
20extern int g_current_media_number;
21extern long long g_tape_posK;
22
23
24/**
25 * @addtogroup stringGroup
26 * @{
27 */
28/**
29 * Build a partition name from a drive and a partition number.
30 * @param drive The drive basename of the partition name (e.g. /dev/hda)
31 * @param partno The partition number (e.g. 1)
32 * @param partition Where to put the partition name (e.g. /dev/hda1)
33 * @return @p partition.
34 * @note If @p drive ends in a digit, then 'p' (on Linux) or 's' (on *BSD) is added before @p partno.
35 */
36char *build_partition_name(char *partition, const char *drive, int partno)
37{
38    char *p, *c;
39
40    assert(partition != NULL);
41    assert_string_is_neither_NULL_nor_zerolength(drive);
42    assert(partno >= 0);
43
44    p = strcpy(partition, drive);
45    /* is this a devfs device path? */
46    c = strrchr(partition, '/');
47    if (c && strncmp(c, "/disc", 5) == 0) {
48        /* yup it's devfs, return the "part" path */
49        strcpy(c + 1, "part");
50        p = c + 5;
51    } else {
52        p += strlen(p);
53        if (isdigit(p[-1])) {
54            *p++ =
55#ifdef BSD
56                's';
57#else
58                'p';
59#endif
60        }
61    }
62    sprintf(p, "%d", partno);
63    return (partition);
64}
65
66
67
68
69
70
71
72
73
74
75
76
77
78/**
79 * Pad a string on both sides so it appears centered.
80 * @param in_out The string to be center-padded (modified).
81 * @param width The width of the final result.
82 */
83void center_string(char *in_out, int width)
84{
85    char scratch[MAX_STR_LEN];
86    char *p;
87    int i;                      /* purpose */
88    int len;                    /* purpose */
89    int mid;                    /* purpose */
90    int x;                      /* purpose */
91
92    assert(in_out != NULL);
93    assert(width > 2);
94
95    if (strlen(in_out) == 0) {
96        return;
97    }
98    for (p = in_out; *p == ' '; p++);
99    strcpy(scratch, p);
100    strip_spaces (scratch);
101    len = (int) strlen(scratch);
102    mid = width / 2;
103    x = mid - len / 2;
104    for (i = 0; i < x; i++) {
105        in_out[i] = ' ';
106    }
107    in_out[i] = '\0';
108    strcat(in_out, scratch);
109    for (i = x + len ; i < width - 1; i++) {
110            in_out[i] = ' ';
111        }
112    in_out[i] = '\0';
113}
114
115
116
117
118inline void turn_wildcard_chars_into_literal_chars(char *sout, char *sin)
119{
120    char *p, *q;
121
122    for (p = sin, q = sout; *p != '\0'; *(q++) = *(p++)) {
123        if (strchr("[]*?", *p)) {
124            *(q++) = '\\';
125        }
126    }
127    *q = *p;                    // for the final '\0'
128}
129
130
131
132/**
133 * Add commas every third place in @p input.
134 * @param input The string to commarize.
135 * @return The string with commas.
136 * @note The returned string points to static storage that will be overwritten with each call.
137 */
138char *commarize(char *input)
139{
140    char pos_w_commas[MAX_STR_LEN];
141    static char output[MAX_STR_LEN];
142    char tmp[MAX_STR_LEN];
143    int j;
144
145    assert(input != NULL);
146
147    strcpy(tmp, input);
148    if (strlen(tmp) > 6) {
149        strcpy(pos_w_commas, tmp);
150        j = (int) strlen(pos_w_commas);
151        tmp[j - 6] = ',';
152        strcpy(tmp + j - 5, pos_w_commas + j - 6);
153//      tmp[j-2] = ',';
154//      strcpy(tmp+j-1, pos_w_commas+j-3);
155        strcpy(pos_w_commas, tmp);
156    }
157    if (strlen(tmp) > 3) {
158        j = (int) strlen(tmp);
159        strcpy(pos_w_commas, tmp);
160        pos_w_commas[j - 3] = ',';
161        strcpy(pos_w_commas + j - 2, tmp + j - 3);
162    } else {
163        strcpy(pos_w_commas, tmp);
164    }
165    strcpy(output, pos_w_commas);
166    return (output);
167}
168
169
170
171
172
173
174
175
176
177/**
178 * Turn an entry from the RAID editor's disklist into a GUI-friendly string.
179 * The format is: the device left-aligned and padded to 24 places, followed by a space and the
180 * index, right-aligned and padded to eight places. The total string length
181 * is exactly 33.
182 * @param disklist The disklist to operate on.
183 * @param lino The line number from @p disklist to convert to a string.
184 * @return The string form of the disklist entry.
185 * @note The returned string points to static storage and will be overwritten with each call.
186 */
187char *disklist_entry_to_string(struct list_of_disks *disklist, int lino)
188{
189
190    /*@ buffers ********************************************************** */
191    static char output[MAX_STR_LEN];
192
193    assert(disklist != NULL);
194
195    sprintf(output, "%-24s %8d", disklist->el[lino].device,
196            disklist->el[lino].index);
197    return (output);
198}
199
200
201
202
203
204/**
205 * Turn a "friendly" sizestring into a number of megabytes.
206 * Supports the suffixes 'k'/'K', 'm'/'M', and 'g'/'G'. Calls
207 * fatal_error() if an unknown suffix is encountered.
208 * @param incoming The sizestring to convert (e.g. "40m", "2g").
209 * @return The size in megabytes.
210 */
211long friendly_sizestr_to_sizelong(char *incoming)
212{
213    long outval;
214    int i;
215    char *tmp;
216    char ch;
217
218    assert_string_is_neither_NULL_nor_zerolength(incoming);
219
220    malloc_string(tmp);
221    if (!incoming[0]) {
222        free(tmp);
223        return (0);
224    }
225    if (strchr(incoming, '.')) {
226        fatal_error("Please use integers only. No decimal points.");
227    }
228    strcpy(tmp, incoming);
229    i = (int) strlen(tmp);
230    if (tmp[i - 1] == 'B' || tmp[i - 1] == 'b') {
231        tmp[i - 1] = '\0';
232    }
233    for (i = 0; i < (int) strlen(tmp) && isdigit(tmp[i]); i++);
234    ch = tmp[i];
235    tmp[i] = '\0';
236    outval = atol(tmp);
237    if (ch == 'g' || ch == 'G') {
238        outval = outval * 1024;
239    } else if (ch == 'k' || ch == 'K') {
240        outval = outval / 1024;
241    } else if (ch == 't' || ch == 'T')  // terabyte
242    {
243        outval *= 1048576;
244    } else if (ch == 'Y' || ch == 'y')  // yottabyte - the biggest measure in the info file
245    {
246        log_it
247            ("Oh my gosh. You actually think a YOTTABYTE will get you anywhere? What're you going to do with 1,208,925,819,614,629,174,706,176 bytes of data?!?!");
248        popup_and_OK
249            ("That sizespec is more than 1,208,925,819,614,629,174,706,176 bytes. You have a shocking amount of data. Please send a screenshot to the list :-)");
250        fatal_error("Integer overflow.");
251    } else if (ch != 'm' && ch != 'M') {
252        sprintf(tmp, "Re: parameter '%s' - bad multiplier ('%c')",
253                incoming, ch);
254        fatal_error(tmp);
255    }
256    paranoid_free(tmp);
257    return (outval);
258}
259
260
261
262/**
263 * Add spaces to the right of @p incoming to make it @p width characters wide.
264 * @param incoming The string to left-pad.
265 * @param width The width to pad it to.
266 * @return The left-padded string.
267 * @note The returned string points to static storage that will be overwritten with each call.
268 * @bug Why does center_string() modify its argument but leftpad_string() returns a modified copy?
269 */
270char *leftpad_string(char *incoming, int width)
271{
272    /*@ buffers ***************************************************** */
273    static char output[MAX_STR_LEN];
274
275    /*@ ints ******************************************************** */
276    int i;
277
278    /*@ end vars **************************************************** */
279    assert(incoming != NULL);
280    assert(width > 2);
281
282    strcpy(output, incoming);
283    for (i = (int) strlen(output); i < width; i++) {
284        output[i] = ' ';
285    }
286    output[i] = '\0';
287    return (output);
288}
289
290
291
292/**
293 * Turn a marker byte (e.g. BLK_START_OF_BACKUP) into a string (e.g. "BLK_START_OF_BACKUP").
294 * Unknown markers are identified as "BLK_UNKNOWN (%d)" where %d is the decimal value.
295 * @param marker The marker byte to stringify.
296 * @return @p marker as a string.
297 * @note The returned string points to static storage that will be overwritten with each call.
298 */
299char *marker_to_string(int marker)
300{
301    /*@ buffer ****************************************************** */
302    static char outstr[MAX_STR_LEN];
303
304
305    /*@ end vars *************************************************** */
306
307    switch (marker) {
308    case BLK_START_OF_BACKUP:
309        strcpy(outstr, "BLK_START_OF_BACKUP");
310        break;
311    case BLK_START_OF_TAPE:
312        strcpy(outstr, "BLK_START_OF_TAPE");
313        break;
314    case BLK_START_AN_AFIO_OR_SLICE:
315        strcpy(outstr, "BLK_START_AN_AFIO_OR_SLICE");
316        break;
317    case BLK_STOP_AN_AFIO_OR_SLICE:
318        strcpy(outstr, "BLK_STOP_AN_AFIO_OR_SLICE");
319        break;
320    case BLK_START_AFIOBALLS:
321        strcpy(outstr, "BLK_START_AFIOBALLS");
322        break;
323    case BLK_STOP_AFIOBALLS:
324        strcpy(outstr, "BLK_STOP_AFIOBALLS");
325        break;
326    case BLK_STOP_BIGGIEFILES:
327        strcpy(outstr, "BLK_STOP_BIGGIEFILES");
328        break;
329    case BLK_START_A_NORMBIGGIE:
330        strcpy(outstr, "BLK_START_A_NORMBIGGIE");
331        break;
332    case BLK_START_A_PIHBIGGIE:
333        strcpy(outstr, "BLK_START_A_PIHBIGGIE");
334        break;
335    case BLK_START_EXTENDED_ATTRIBUTES:
336        strcpy(outstr, "BLK_START_EXTENDED_ATTRIBUTES");
337        break;
338    case BLK_STOP_EXTENDED_ATTRIBUTES:
339        strcpy(outstr, "BLK_STOP_EXTENDED_ATTRIBUTES");
340        break;
341    case BLK_START_EXAT_FILE:
342        strcpy(outstr, "BLK_START_EXAT_FILE");
343        break;
344    case BLK_STOP_EXAT_FILE:
345        strcpy(outstr, "BLK_STOP_EXAT_FILE");
346        break;
347    case BLK_START_BIGGIEFILES:
348        strcpy(outstr, "BLK_START_BIGGIEFILES");
349        break;
350    case BLK_STOP_A_BIGGIE:
351        strcpy(outstr, "BLK_STOP_A_BIGGIE");
352        break;
353    case BLK_END_OF_TAPE:
354        strcpy(outstr, "BLK_END_OF_TAPE");
355        break;
356    case BLK_END_OF_BACKUP:
357        strcpy(outstr, "BLK_END_OF_BACKUP");
358        break;
359    case BLK_ABORTED_BACKUP:
360        strcpy(outstr, "BLK_ABORTED_BACKUP");
361        break;
362    case BLK_START_FILE:
363        strcpy(outstr, "BLK_START_FILE");
364        break;
365    case BLK_STOP_FILE:
366        strcpy(outstr, "BLK_STOP_FILE");
367        break;
368    default:
369        sprintf(outstr, "BLK_UNKNOWN (%d)", marker);
370        break;
371    }
372    return (outstr);
373}
374
375
376
377
378/**
379 * Turn a line from the mountlist into a GUI-friendly string.
380 * The format is as follows: the left-aligned @p device field padded to 24 places,
381 * a space, the left-aligned @p mountpoint field again padded to 24 places, a space,
382 * the left-aligned @p format field padded to 10 places, a space, and the right-aligned
383 * @p size field (in MB) padded to 8 places. The total string length is exactly 69.
384 * @param mountlist The mountlist to operate on.
385 * @param lino The line number in @p mountlist to stringify.
386 * @return The string form of <tt>mountlist</tt>-\>el[<tt>lino</tt>].
387 * @note The returned string points to static storage and will be overwritten with each call.
388 */
389char *mountlist_entry_to_string(struct mountlist_itself *mountlist,
390                                int lino)
391{
392
393    /*@ buffer *********************************************************** */
394    static char output[MAX_STR_LEN];
395
396    assert(mountlist != NULL);
397
398    sprintf(output, "%-24s %-24s %-10s %8lld", mountlist->el[lino].device,
399            mountlist->el[lino].mountpoint, mountlist->el[lino].format,
400            mountlist->el[lino].size / 1024);
401    return (output);
402}
403
404
405
406
407
408
409/**
410 * Generate a friendly string containing "X blah blah disk(s)"
411 * @param noof_disks The number of disks (the X).
412 * @param label The "blah blah" part in the middle. If you leave this blank
413 * there will be a weird double space in the middle, so pass *something*.
414 * @return The string containing "X blah blah disk(s)".
415 * @note The returned string points to static storage and will be overwritten with each call.
416 */
417char *number_of_disks_as_string(int noof_disks, char *label)
418{
419
420    /*@ buffers ********************************************************* */
421    static char output[MAX_STR_LEN];
422
423    /*@ char     ******************************************************** */
424    char p;
425
426    assert(label != NULL);
427
428    if (noof_disks > 1) {
429        p = 's';
430    } else {
431        p = ' ';
432    }
433    sprintf(output, "%d %s disk%c", noof_disks, label, p);
434    while (strlen(output) < 14) {
435        strcat(output, " ");
436    }
437    return (output);
438}
439
440
441
442/**
443 * Change @p i into a friendly string. If @p i is \<= 10 then write out the
444 * number (e.g. "one", "two", ..., "nine", "ten", "11", ...).
445 * @param i The number to stringify.
446 * @return The string form of @p i.
447 * @note The returned value points to static strorage that will be overwritten with each call.
448 */
449char *number_to_text(int i)
450{
451
452    /*@ buffers ***************************************************** */
453    static char output[MAX_STR_LEN];
454
455
456    /*@ end vars *************************************************** */
457
458    switch (i) {
459    case 0:
460        strcpy(output, "zero");
461        break;
462    case 1:
463        strcpy(output, "one");
464        break;
465    case 2:
466        strcpy(output, "two");
467        break;
468    case 3:
469        strcpy(output, "three");
470        break;
471    case 4:
472        strcpy(output, "four");
473        break;
474    case 5:
475        strcpy(output, "five");
476        break;
477    case 6:
478        strcpy(output, "six");
479        break;
480    case 7:
481        strcpy(output, "seven");
482        break;
483    case 8:
484        strcpy(output, "eight");
485        break;
486    case 9:
487        strcpy(output, "nine");
488    case 10:
489        strcpy(output, "ten");
490    default:
491        sprintf(output, "%d", i);
492    }
493    return (output);
494}
495
496
497
498
499/**
500 * Replace all occurences of @p token with @p value while copying @p ip to @p output.
501 * @param ip The input string containing zero or more <tt>token</tt>s.
502 * @param output The output string written with the <tt>token</tt>s replaced by @p value.
503 * @param token The token to be relaced with @p value.
504 * @param value The value to replace @p token.
505 */
506void resolve_naff_tokens(char *output, char *ip, char *value, char *token)
507{
508    /*@ buffers *** */
509    char *input;
510
511    /*@ pointers * */
512    char *p;
513
514    input = malloc(2000);
515    assert_string_is_neither_NULL_nor_zerolength(ip);
516    assert_string_is_neither_NULL_nor_zerolength(token);
517    assert(value != NULL);
518
519    strcpy(output, ip);         /* just in case the token doesn't appear in string at all */
520    for (strcpy(input, ip); strstr(input, token); strcpy(input, output)) {
521        strcpy(output, input);
522        p = strstr(output, token);
523        *p = '\0';
524        strcat(output, value);
525        p = strstr(input, token) + strlen(token);
526        strcat(output, p);
527    }
528    paranoid_free(input);
529}
530
531
532
533
534
535/**
536 * Generate the filename of slice @p sliceno of biggiefile @p bigfileno
537 * in @p path with suffix @p s. The format is as follows: @p path, followed
538 * by "/slice-" and @p bigfileno zero-padded to 7 places, followed by
539 * a dot and @p sliceno zero-padded to 5 places, followed by ".dat" and the
540 * suffix. The string is a minimum of 24 characters long.
541 * @param bigfileno The biggiefile number. Starts from 0.
542 * @param sliceno The slice number of biggiefile @p bigfileno. 0 is a "header"
543 * slice (no suffix) containing the biggiestruct, then are the compressed
544 * slices, then an empty uncompressed "trailer" slice.
545 * @param path The path to append (with a / in the middle) to the slice filename.
546 * @param s If not "" then add a "." and this to the end.
547 * @return The slice filename.
548 * @note The returned value points to static storage and will be overwritten with each call.
549 */
550char *slice_fname(long bigfileno, long sliceno, char *path, char *s)
551{
552
553    /*@ buffers **************************************************** */
554    static char output[MAX_STR_LEN];
555    static char suffix[MAX_STR_LEN];
556
557    /*@ end vars *************************************************** */
558
559    assert_string_is_neither_NULL_nor_zerolength(path);
560    if (s[0] != '\0') {
561        sprintf(suffix, ".%s", s);
562    } else {
563        suffix[0] = '\0';
564    }
565    sprintf(output, "%s/slice-%07ld.%05ld.dat%s", path, bigfileno, sliceno,
566            suffix);
567    return (output);
568}
569
570
571/**
572 * Generate a spinning symbol based on integer @p i.
573 * The symbol rotates through the characters / - \ | to form an ASCII "spinner"
574 * if successively written to the same location on screen.
575 * @param i The amount of progress or whatever else to use to determine the character
576 * for this iteration of the spinner.
577 * @return The character for this iteration.
578 */
579int special_dot_char(int i)
580{
581    switch (i % 4) {
582    case 0:
583        return ('/');
584    case 1:
585        return ('-');
586    case 2:
587        return ('\\');
588    case 3:
589        return ('|');
590    default:
591        return ('.');
592    }
593    return ('.');
594}
595
596
597
598
599/**
600 * Wrap @p flaws_str across three lines. The first two are no more than 74 characters wide.
601 * @param flaws_str The original string to split.
602 * @param flaws_str_A Where to put the first 74-or-less characters.
603 * @param flaws_str_B Where to put the second 74-or-less characters.
604 * @param flaws_str_C Where to put the rest.
605 * @param res The result of the original evaluate_mountlist() operation.
606 * @return TRUE if res == 0, FALSE otherwise.
607 */
608bool
609spread_flaws_across_three_lines(char *flaws_str, char *flaws_str_A,
610                                char *flaws_str_B, char *flaws_str_C,
611                                int res)
612{
613
614    /*@ int ************************************************************* */
615    int i = 0;
616
617    /*@ initialize ****************************************************** */
618    assert(flaws_str_A != NULL);
619    assert(flaws_str_B != NULL);
620    assert(flaws_str_C != NULL);
621    assert(flaws_str != NULL);
622
623    flaws_str_A[0] = flaws_str_B[0] = flaws_str_C[0] = '\0';
624
625
626    if (!res && !strlen(flaws_str)) {
627        return (TRUE);
628    }
629    if (strlen(flaws_str) > 0) {
630        sprintf(flaws_str_A, "%s", flaws_str + 1);
631    }
632    if (strlen(flaws_str_A) >= 74) {
633        for (i = 74; flaws_str_A[i] != ' '; i--);
634        strcpy(flaws_str_B, flaws_str_A + i + 1);
635        flaws_str_A[i] = '\0';
636    }
637    if (strlen(flaws_str_B) >= 74) {
638        for (i = 74; flaws_str_B[i] != ' '; i--);
639        strcpy(flaws_str_C, flaws_str_B + i + 1);
640        flaws_str_B[i] = '\0';
641    }
642    if (res) {
643        return (FALSE);
644    } else {
645        return (TRUE);
646    }
647}
648
649
650
651/**
652 * Compare @p stringA and @p stringB. This uses an ASCII sort for everything
653 * up to the digits on the end but a numerical sort for the digits on the end.
654 * @param stringA The first string to compare.
655 * @param stringB The second string to compare.
656 * @return The same as strcmp() - <0 if A<B, 0 if A=B, >0 if A>B.
657 * @note This function only does a numerical sort on the @e last set of numbers. If
658 * there are any in the middle those will be sorted ASCIIbetically.
659 */
660int strcmp_inc_numbers(char *stringA, char *stringB)
661{
662    /*@ int ********************************************************* */
663    int i;
664    int start_of_numbers_in_A;
665    int start_of_numbers_in_B;
666    int res;
667
668    /*@ long ******************************************************* */
669    long numA;
670    long numB;
671
672    /*@ end vars *************************************************** */
673    assert(stringA != NULL);
674    assert(stringB != NULL);
675
676    if (strlen(stringA) == strlen(stringB)) {
677        return (strcmp(stringA, stringB));
678    }
679    for (i = (int) strlen(stringA); i > 0 && isdigit(stringA[i - 1]); i--);
680    if (i == (int) strlen(stringA)) {
681        return (strcmp(stringA, stringB));
682    }
683    start_of_numbers_in_A = i;
684    for (i = (int) strlen(stringB); i > 0 && isdigit(stringB[i - 1]); i--);
685    if (i == (int) strlen(stringB)) {
686        return (strcmp(stringA, stringB));
687    }
688    start_of_numbers_in_B = i;
689    if (start_of_numbers_in_A != start_of_numbers_in_B) {
690        return (strcmp(stringA, stringB));
691    }
692    res = strncmp(stringA, stringB, (size_t) i);
693    if (res) {
694        return (res);
695    }
696    numA = atol(stringA + start_of_numbers_in_A);
697    numB = atol(stringB + start_of_numbers_in_B);
698    /*
699       sprintf(tmp,"Comparing %s and %s --> %ld,%ld\n",stringA,stringB,numA,numB);
700       log_to_screen(tmp);
701     */
702    return ((int) (numA - numB));
703}
704
705
706
707/**
708 * Strip excess baggage from @p input, which should be a line from afio.
709 * For now this copies the whole line unless it finds a set of quotes, in which case
710 * it copies their contents only.
711 * @param input The input line (presumably from afio).
712 * @return The stripped line.
713 * @note The returned string points to static storage that will be overwritten with each call.
714 */
715char *strip_afio_output_line(char *input)
716{
717    /*@ buffer ****************************************************** */
718    static char output[MAX_STR_LEN];
719
720    /*@ pointers **************************************************** */
721    char *p;
722    char *q;
723    /*@ end vars *************************************************** */
724
725    assert(input != NULL);
726    strcpy(output, input);
727    p = strchr(input, '\"');
728    if (p) {
729        q = strchr(++p, '\"');
730        if (q) {
731            strcpy(output, p);
732            *(strchr(output, '\"')) = '\0';
733        }
734    }
735    return (output);
736}
737
738
739
740/**
741 * Remove all characters whose ASCII value is less than or equal to 32
742 * (spaces and control characters) from both sides of @p in_out.
743 * @param in_out The string to strip spaces/control characters from (modified).
744 */
745void strip_spaces(char *in_out)
746{
747    /*@ buffers ***************************************************** */
748    char *tmp;
749
750    /*@ pointers **************************************************** */
751    char *p;
752
753    /*@ int ******************************************************** */
754    int i;
755    int original_incoming_length;
756
757    /*@ end vars *************************************************** */
758
759    assert(in_out != NULL);
760    malloc_string(tmp);
761    original_incoming_length = (int) strlen(in_out);
762    for (i = 0; in_out[i] <= ' ' && i < (int) strlen(in_out); i++);
763    strcpy(tmp, in_out + i);
764    for (i = (int) strlen(tmp); i > 0 && tmp[i - 1] <= 32; i--);
765    tmp[i] = '\0';
766    for (i = 0; i < original_incoming_length && MAX_STR_LEN; i++) {
767        in_out[i] = ' ';
768    }
769    in_out[i] = '\0';
770    i = 0;
771    p = tmp;
772    while (*p != '\0') {
773        in_out[i] = *(p++);
774        in_out[i + 1] = '\0';
775        if (in_out[i] < 32 && i > 0) {
776            if (in_out[i] == 8) {
777                i--;
778            } else if (in_out[i] == 9) {
779                in_out[i++] = ' ';
780            } else if (in_out[i] == '\r')   // added 1st October 2003 -- FIXME
781            {
782                strcpy(tmp, in_out + i);
783                strcpy(in_out, tmp);
784                i = -1;
785                continue;
786            } else if (in_out[i] == '\t') {
787                for (i++; i % 5; i++);
788            } else if (in_out[i] >= 10 && in_out[i] <= 13) {
789                break;
790            } else {
791                i--;
792            }
793        } else {
794            i++;
795        }
796    }
797    in_out[i] = '\0';
798    paranoid_free(tmp);
799/*  for(i=strlen(in_out); i>0 && in_out[i-1]<=32; i--) {in_out[i-1]='\0';} */
800}
801
802
803/**
804 * If there are double quotes "" around @p incoming then remove them.
805 * This does not affect other quotes that may be embedded within the string.
806 * @param incoming The string to trim quotes from (modified).
807 * @return @p incoming.
808 */
809char *trim_empty_quotes(char *incoming)
810{
811    /*@ buffer ****************************************************** */
812    static char outgoing[MAX_STR_LEN];
813
814    /*@ end vars *************************************************** */
815    assert(incoming != NULL);
816
817    if (incoming[0] == '\"' && incoming[strlen(incoming) - 1] == '\"') {
818        strcpy(outgoing, incoming + 1);
819        outgoing[strlen(outgoing) - 1] = '\0';
820    } else {
821        strcpy(outgoing, incoming);
822    }
823    return (outgoing);
824}
825
826
827
828
829/**
830 * Remove any partition info from @p partition, leaving just the drive name.
831 * @param partition The partition name soon-to-become drive name. (modified)
832 * @return @p partition.
833 */
834char *truncate_to_drive_name(char *partition)
835{
836    int i = strlen(partition) - 1;
837    char *c;
838
839#ifdef __FreeBSD__
840
841    if (islower(partition[i]))  // BSD subpartition
842        i--;
843    if (partition[i - 1] == 's') {
844        while (isdigit(partition[i]))
845            i--;
846        i--;
847    }
848    partition[i + 1] = '\0';
849
850#else
851
852    assert_string_is_neither_NULL_nor_zerolength(partition);
853    /* first see if it's a devfs style device */
854    c = strrchr(partition, '/');
855    if (c && strncmp(c, "/part", 5) == 0) {
856        /* yup it's devfs, return the "disc" path */
857        strcpy(c + 1, "disc");
858        return partition;
859    }
860
861    for (i = strlen(partition); isdigit(partition[i - 1]); i--)
862        continue;
863    if (partition[i - 1] == 'p' && isdigit(partition[i - 2])) {
864        i--;
865    }
866    partition[i] = '\0';
867
868#endif
869
870    return partition;
871}
872
873
874
875
876
877/**
878 * Turn a RAID level number (-1 to 5) into a friendly string. The string
879 * is either "Linear RAID" for -1, or " RAID %-2d " (%d = @p raid_level)
880 * for anything else.
881 * @param raid_level The RAID level to stringify.
882 * @return The string form of @p raid_level.
883 * @note The returned value points to static storage that will be overwritten with each call.
884 */
885char *turn_raid_level_number_to_string(int raid_level)
886{
887
888    /*@ buffer ********************************************************** */
889    static char output[MAX_STR_LEN];
890
891
892
893    if (raid_level >= 0) {
894        sprintf(output, " RAID %-2d ", raid_level);
895    } else {
896        sprintf(output, "Linear RAID");
897    }
898    return (output);
899}
900
901
902
903
904
905
906
907
908
909/**
910 * Determine the severity (1-3, 1 being low) of the fact that
911 * @p fn changed in the live filesystem (verify/compare).
912 * @param fn The filename that changed.
913 * @param out_reason If non-NULL, a descriptive reason for the difference will be copied here.
914 * @return The severity (1-3).
915 */
916int severity_of_difference(char *fn, char *out_reason)
917{
918    int sev;
919    char *reason;
920    char *filename;
921
922    malloc_string(reason);
923    malloc_string(filename);
924// out_reason might be null on purpose, so don't bomb if it is :) OK?
925    assert_string_is_neither_NULL_nor_zerolength(fn);
926    if (!strncmp(fn, MNT_RESTORING, strlen(MNT_RESTORING))) {
927        strcpy(filename, fn + strlen(MNT_RESTORING));
928    } else if (fn[0] != '/') {
929        sprintf(filename, "/%s", fn);
930    } else {
931        strcpy(filename, fn);
932    }
933
934    sev = 3;
935    sprintf(reason,
936            "Changed since backup. Consider running a differential backup in a day or two.");
937    if (!strncmp(filename, "/var/", 5)) {
938        sev = 2;
939        sprintf(reason,
940                "/var's contents will change regularly, inevitably.");
941    }
942    if (!strncmp(filename, "/home", 5)) {
943        sev = 2;
944        sprintf(reason,
945                "It's in your /home partiton. Therefore, it is important.");
946    }
947    if (!strncmp(filename, "/usr/", 5)) {
948        sev = 3;
949        sprintf(reason,
950                "You may have installed/removed software during the backup.");
951    }
952    if (!strncmp(filename, "/etc/", 5)) {
953        sev = 3;
954        sprintf(reason,
955                "Do not edit config files while backing up your PC.");
956    }
957    if (!strcmp(filename, "/etc/adjtime")
958        || !strcmp(filename, "/etc/mtab")) {
959        sev = 1;
960        sprintf(reason, "This file changes all the time. It's OK.");
961    }
962    if (!strncmp(filename, "/root/", 6)) {
963        sev = 3;
964        sprintf(reason, "Were you compiling/editing something in /root?");
965    }
966    if (!strncmp(filename, "/root/.", 7)) {
967        sev = 2;
968        sprintf(reason, "Temp or 'dot' files changed in /root.");
969    }
970    if (!strncmp(filename, "/var/lib/", 9)) {
971        sev = 2;
972        sprintf(reason, "Did you add/remove software during backing?");
973    }
974    if (!strncmp(filename, "/var/lib/rpm", 12)) {
975        sev = 3;
976        sprintf(reason, "Did you add/remove software during backing?");
977    }
978    if (!strncmp(filename, "/var/lib/slocate", 16)) {
979        sev = 1;
980        sprintf(reason,
981                "The 'update' daemon ran during backup. This does not affect the integrity of your backup.");
982    }
983    if (!strncmp(filename, "/var/log/", 9)
984        || strstr(filename, "/.xsession")
985        || !strcmp(filename + strlen(filename) - 4, ".log")) {
986        sev = 1;
987        sprintf(reason,
988                "Log files change frequently as the computer runs. Fret not.");
989    }
990    if (!strncmp(filename, "/var/spool", 10)) {
991        sev = 1;
992        sprintf(reason,
993                "Background processes or printers were active. This does not affect the integrity of your backup.");
994    }
995    if (!strncmp(filename, "/var/spool/mail", 10)) {
996        sev = 2;
997        sprintf(reason, "Mail was sent/received during backup.");
998    }
999    if (filename[strlen(filename) - 1] == '~') {
1000        sev = 1;
1001        sprintf(reason,
1002                "Backup copy of another file which was modified recently.");
1003    }
1004    if (strstr(filename, "cache")) {
1005        sev = 1;
1006        sprintf(reason,
1007                "Part of a cache of data. Caches change from time to time. Don't worry.");
1008    }
1009    if (!strncmp(filename, "/var/run/", 9)
1010        || !strncmp(filename, "/var/lock", 8)
1011        || strstr(filename, "/.DCOPserver") || strstr(filename, "/.MCOP")
1012        || strstr(filename, "/.Xauthority")) {
1013        sev = 1;
1014        sprintf(reason,
1015                "Temporary file (a lockfile, perhaps) used by software such as X or KDE to register its presence.");
1016    }
1017    if (out_reason) {
1018        strcpy(out_reason, reason);
1019    }
1020    paranoid_free(filename);
1021    paranoid_free(reason);
1022    return (sev);
1023}
1024
1025
1026
1027/**
1028 * Compare the filenames in two filelist entries (s_filelist_entry*) casted
1029 * to void*.
1030 * @param va The first filelist entry, cast as a @c void pointer.
1031 * @param vb The second filelist entry, cast as a @c void pointer.
1032 * @return The return value of strcmp().
1033 */
1034int compare_two_filelist_entries(void *va, void *vb)
1035{
1036    static int res;
1037    struct s_filelist_entry *fa, *fb;
1038
1039    assert(va != NULL);
1040    assert(vb != NULL);
1041    fa = (struct s_filelist_entry *) va;
1042    fb = (struct s_filelist_entry *) vb;
1043    res = strcmp(fa->filename, fb->filename);
1044    return (res);
1045}
1046
1047
1048
1049
1050
1051
1052
1053/**
1054 * Generate a line intended to be passed to update_evalcall_form(), indicating
1055 * the current media fill percentage (or number of kilobytes if size is not known).
1056 * @param bkpinfo The backup media structure. Fields used:
1057 * - @c bkpinfo->backup_media_type
1058 * - @c bkpinfo->media_size
1059 * - @c bkpinfo->scratchdir
1060 * @return The string indicating media fill.
1061 * @note The returned string points to static storage that will be overwritten with each call.
1062 */
1063char *percent_media_full_comment(struct s_bkpinfo *bkpinfo)
1064{
1065    /*@ int *********************************************** */
1066    int percentage;
1067    int j;
1068
1069    /*@ buffers ******************************************* */
1070    static char outstr[MAX_STR_LEN];
1071    char *pos_w_commas, *tmp;
1072
1073    assert(bkpinfo != NULL);
1074    malloc_string(pos_w_commas);
1075    malloc_string(tmp);
1076    sprintf(tmp, "%lld", g_tape_posK);
1077    strcpy(pos_w_commas, commarize(tmp));
1078
1079
1080
1081    if (bkpinfo->media_size[g_current_media_number] <= 0)
1082//    { fatal_error( "percentage_media_full_comment() - unknown media size"); }
1083    {
1084        sprintf(outstr, "Volume %d: %s kilobytes archived so far",
1085                g_current_media_number, pos_w_commas);
1086        return (outstr);
1087    }
1088
1089/* update screen */
1090    if (IS_THIS_A_STREAMING_BACKUP(bkpinfo->backup_media_type)) {
1091        percentage =
1092            (int) (g_tape_posK / 10 /
1093                   bkpinfo->media_size[g_current_media_number]);
1094        if (percentage > 100) {
1095            percentage = 100;
1096        }
1097        sprintf(outstr, "Volume %d: [", g_current_media_number);
1098    } else {
1099        percentage =
1100            (int) (space_occupied_by_cd(bkpinfo->scratchdir) * 100 / 1024 /
1101                   bkpinfo->media_size[g_current_media_number]);
1102        sprintf(outstr, "%s %d: [",
1103                media_descriptor_string(bkpinfo->backup_media_type),
1104                g_current_media_number);
1105    }
1106    for (j = 0; j < percentage; j += 5) {
1107        strcat(outstr, "*");
1108    }
1109    for (; j < 100; j += 5) {
1110        strcat(outstr, ".");
1111    }
1112    j = (int) strlen(outstr);
1113    sprintf(outstr + j, "] %d%% used", percentage);
1114    paranoid_free(pos_w_commas);
1115    paranoid_free(tmp);
1116    return (outstr);
1117}
1118
1119/**
1120 * Get a string form of @p type_of_bkp.
1121 * @param type_of_bkp The backup type to stringify.
1122 * @return The stringification of @p type_of_bkp.
1123 * @note The returned string points to static storage that will be overwritten with each call.
1124 */
1125char *media_descriptor_string(t_bkptype type_of_bkp)
1126{
1127    static char *type_of_backup = NULL;
1128
1129    if (!type_of_backup) {
1130        malloc_string(type_of_backup);
1131    }
1132
1133    switch (type_of_bkp) {
1134    case dvd:
1135        strcpy(type_of_backup, "DVD");
1136        break;
1137    case cdr:
1138        strcpy(type_of_backup, "CDR");
1139        break;
1140    case cdrw:
1141        strcpy(type_of_backup, "CDRW");
1142        break;
1143    case tape:
1144        strcpy(type_of_backup, "tape");
1145        break;
1146    case cdstream:
1147        strcpy(type_of_backup, "CDR");
1148        break;
1149    case udev:
1150        strcpy(type_of_backup, "udev");
1151        break;
1152    case iso:
1153        strcpy(type_of_backup, "ISO");
1154        break;
1155    case nfs:
1156        strcpy(type_of_backup, "nfs");
1157        break;
1158    default:
1159        strcpy(type_of_backup, "ISO");
1160    }
1161    return (type_of_backup);
1162}
Note: See TracBrowser for help on using the repository browser.