Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 327c689adc5dcea3279f4a40475d7cc9e1ac8865 (plain) (blame)
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
/*******************************************************************************
 * Copyright (c) 2005, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IBM Rational Software - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;

import java.io.File;

/**
 * @author jcamelon
 *
 */
public class ScannerUtility {

	static final char DOT    = '.';  
	static final char SLASH  = '/';
	static final char BSLASH = '\\'; 
	static final char QUOTE  = '\"'; 

	/**
	 * This method is quick 1-pass path reconciler.
	 * Functions:
	 *   - replace "/" or "\" by system's separator
	 *   - replace multiple separators by single one
	 *   - skip "/./" 
	 *   - skip quotes
	 *   - process "/../" (skip previous directory level)    
	 * 
	 * @param originalPath - path to process
	 * @return             - reconciled path   
	 */
	public static String reconcilePath(String originalPath ) {
		int len = originalPath.length();
		int len1 = len - 1;         // to avoid multiple calculations
		int j = 0;                  // index for output array
		boolean noSepBefore = true; // to avoid duplicate separators
		
		char[] ein = new char[len];
		char[] aus = new char[len + 1];
		
		originalPath.getChars(0, len, ein, 0);
		
		// allow double backslash at beginning for windows UNC paths, bug 233511
		if(ein.length >= 2 && ein[0] == BSLASH && ein[1] == BSLASH && 
		   File.separatorChar == BSLASH) {
		    aus[j++] = BSLASH;
		}

		
		for (int i=0; i<len; i++) {
			char c = ein[i]; 
			switch (c) {
			case QUOTE:	  // quotes are removed
				noSepBefore = true;
				break;
			case SLASH:     // both separators are processed  
			case BSLASH:    // in the same way
				if (noSepBefore) {
					noSepBefore = false;
					aus[j++] = File.separatorChar;
				}
				break;
			case DOT:
				// no separator before, not a 1st string symbol. 
				if (noSepBefore && j>0) 
					aus[j++] = c;
				else { // separator before "." ! 
					if (i < len1) {
						c = ein[i+1]; // check for next symbol
						// check for "/./" case
						if (c == SLASH || c == BSLASH) {
							// write nothing to output
							// skip the next symbol
							i++;
							noSepBefore = false;
						} 
						// symbol other than "." - write it also 
						else if (c != DOT) {
							i++;
							noSepBefore = true;
							aus[j++] = DOT;
							aus[j++] = c;
						}
						// we found "/.." sequence. Look ahead.
						else {
							// we found "/../" (or "/.." is at the end of string)
							// we should delete previous segment of output path 
							if (i == len1 || ein[i+2] == SLASH || ein[i+2] == BSLASH) {
								i+=2;
								noSepBefore = false;
								if (j > 1) { // there is at least 1 segment before
									int k = j - 2;
									while ( k >= 0 ) {
										if (aus[k] == File.separatorChar) break;
										k--;
									}
									j = k + 1; // set index to previous segment or to 0
								}
							}
							// Case "/..blabla" processed as usual
							else {
								i++;
								noSepBefore = true;
								aus[j++] = DOT;
								aus[j++] = DOT;
							}
						}
					} else 
					{} // do nothing when "." is last symbol
				}
				break;
			default: 
				noSepBefore = true;
				aus[j++] = c;
			}
		}
		return new String(aus, 0, j);
	}

	/**
	 * @param path     - include path
	 * @param fileName - include file name
	 * @return         - reconsiled path
	 */
	public static String createReconciledPath(String path, String fileName) {
		boolean pathEmpty = (path == null || path.length() == 0);
		return (pathEmpty ? fileName : reconcilePath(path + File.separatorChar + fileName));
	}
}

Back to the top