1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
package Torello.Java;

class Abbrev
{
    static String print1(
            final String    s,
            final int       abbrevPos,
            final boolean   escapeNewLines,
            final String    abbrevStrInput,
            final int       maxLength
        )
    {
        if (maxLength < 0) throw new IllegalArgumentException
            ("The value passed to 'maxLength' " + maxLength + ", may not be zero or negative.");

        if (abbrevPos < 0) throw new IllegalArgumentException
            ("You have passed a negative value to parameter 'abbrevPos': " + abbrevPos);

        // if (abbrevStr == null) abbrevStr = "...";
        String abbrevStr = (abbrevStrInput == null) ? "..." : abbrevStrInput;

        int SLEN = s.length();
        int ALEN = abbrevStr.length();

        if ((abbrevPos + ALEN) >= maxLength) throw new IllegalArgumentException(
            "The value passed to parameter 'abbrevPos', " + abbrevPos + ", added to the length " +
            "of the abbreviation-ellipsis String, \"" + abbrevStr + "\", is longer than the " +
            "value provided to parameter 'maxLength' " + maxLength
        );

        if (! escapeNewLines) if (SLEN <= maxLength) return s;

        char[] cArr = new char[maxLength];

        // NOTE: Two lines ago, if the input string 's' actually fit, it would already have been
        //       returned (in the case that escaping new-lines was NOT requested)
        if (! escapeNewLines)
        {
            s.getChars(0, abbrevPos, cArr, 0);
            abbrevStr.getChars(0, ALEN, cArr, abbrevPos);
            s.getChars(SLEN - (maxLength - (abbrevPos + ALEN)), SLEN, cArr, abbrevPos + ALEN);
            return new String(cArr);
        }

        // Beginning Here: It has been determined that new-lines are to be escaped....
        int     targetPos=0, srcPos=0, oldSrcPos=0;
        char    c;

        while ((targetPos < abbrevPos) && (srcPos < SLEN))

            // When / If a new-line character is encountered, just insert the "\\n" 
            // substring.  Otherwise, normally copy the next character in the source-string

            if ((c = s.charAt(srcPos++)) == '\n')
            {
                cArr[targetPos++] = '\\';

                if ((targetPos < cArr.length) && (targetPos < abbrevPos))
                    cArr[targetPos++] = 'n';
            }

            else
                cArr[targetPos++] = c;

        // This is the case where the String was short enough to fit before the
        // abbrev-pos.

        if (srcPos == SLEN) return new String(cArr, 0, targetPos);

        // In this loop, the iteration is done in reverse.  It starts at the end of the
        // source-String, and at the end of the out char-array, and works backward.
        // LOOP CONTINUES: Continues until the 'abbrevPos' has been reached.

        oldSrcPos   = srcPos;
        srcPos      = SLEN - 1;
        targetPos   = cArr.length - 1;

        while ((targetPos >= abbrevPos) && (srcPos >= oldSrcPos))

            // Here, we need to make sure not to over-write the 
            if ((c = s.charAt(srcPos--)) == '\n')
            {
                cArr[targetPos--] = 'n';

                if (targetPos >= abbrevPos) cArr[targetPos--] = '\\';
            }

            else
                cArr[targetPos--] = c;


        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        // CASE 1: The String didn't fit into the 'maxLength' specified array
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        //
        // so it *DOES* need to be abbreviated.
        // Copy the abbreviation-string into cArr, and return it.

        if (srcPos >= oldSrcPos)
        {
            abbrevStr.getChars(0, ALEN, cArr, abbrevPos);
            return new String(cArr);
        }


        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        // CASE 2: The String did fit (even with escaped '\n' ==> "\\n")
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        //
        // **AND** It fit PRECISELY-EXACTLY into the output char-array

        if ((targetPos == (abbrevPos-1)) && (srcPos == (oldSrcPos-1)))
            return new String(cArr);


        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        // CASE 3: There is extra-room in the output-String
        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
        //
        // This means that the copy which just occurred in the previous loop was wrong
        // There isn't an easy way to avoid this (other than counting new-lines first)
        // Instead, shift the char-array, and then return it

        srcPos = targetPos + 1;
        targetPos = abbrevPos;
        while (srcPos < cArr.length) cArr[targetPos++] = cArr[srcPos++];

        return new String(cArr, 0, targetPos);
    }

    static String print2(
            final String    s,
            final boolean   spaceBeforeAbbrev,
            final boolean   escapeNewLines,
            final String    abbrevStrInput,
            final int       maxLength
        )
    {
        if (maxLength < 0) throw new IllegalArgumentException
            ("The value passed to 'maxLength' " + maxLength + ", may not be zero or negative.");

        // If the original String is shorter than the 'maxLength' parameter, return the original
        // String immediately - **UNLESS** the user has requested to replace new-line characters
        // with the "Escaped New-Line Sequence "\\n"

        if (! escapeNewLines) if (s.length() <= maxLength) return s;

        // The default abbreviation is just the ellipsis.
        // if (abbrevStr == null) abbrevStr = "...";

        final String abbrevStr = (abbrevStrInput == null) ? "..." : abbrevStrInput;

        char[]  cArr        = new char[maxLength];
        int     srcPos      = 0;
        int     targetPos   = 0;
        char    c           = 0;
        int     LEN         = s.length();
        int     END         = maxLength - abbrevStr.length() - (spaceBeforeAbbrev ? 1 : 0);

        if (END < 0) throw new IllegalArgumentException(
            "The value provided to 'maxLength' was : " + maxLength + ", but this isn't long " +
            "enough to even contain the abbreviation-string: \"" + (spaceBeforeAbbrev ? " " : "") +
            abbrevStr + "\""
        );

        if (! escapeNewLines)

            // NOTE: Here, the abbreviation will be necessary, so use 'END' instead of 'LEN'
            //       This is because at the top, if the whole-String fit, this method would have
            //       already returned ... if (! escapeNewLines) *above*
            // ALSO: More efficient at copying String-arrays than a 'for-loop' is 'getChars'

            s.getChars(0, targetPos = END, cArr, 0);

        else
        {
            while ((targetPos < maxLength) && (srcPos < LEN))

                // When / If a new-line character is encountered, just insert the "\\n" 
                // substring.  Otherwise, normally copy the next character in the source-string

                if ((c = s.charAt(srcPos++)) == '\n')
                {
                    cArr[targetPos++] = '\\';
                    if (targetPos < cArr.length) cArr[targetPos++] = 'n';
                }
                else
                    cArr[targetPos++] = c;

            // If every single character from the input String has been appended to the output,
            // then there is no need to add the abbreviation String (usually, the ellipsis '...').
            // In this case, just return original-String immediately (with the escaped newlines).

            if (srcPos == LEN)
                return new String(cArr, 0, targetPos);

            targetPos -= (abbrevStr.length() + (spaceBeforeAbbrev ? 1 : 0));
        }

        // NOTE: There is a (false) special-case, where there *ALREADY* IS a space before the
        //       addition of the "ellipsis" - so it *MIGHT SEEM* you wouldn't want to add another
        //       a second-space, unfortunately, if they have asked for a space before the
        //       abbreviation-ellipsis, it is also inappropriate to add another character from the
        //       original String.
        // 
        // LONG-STORY-SHORT: There is a (small) chance that there will be two spaces in a row here,
        //                   but in order to comply with the 'maxLength' parameter, there is no
        //                   alternative.

        if (spaceBeforeAbbrev) cArr[targetPos++] = ' ';

        abbrevStr.getChars(0, abbrevStr.length(), cArr, targetPos);
        return new String(cArr, 0, targetPos + abbrevStr.length());
    }
}