1 // This file is part of Visual D
2 //
3 // Visual D integrates the D programming language into Visual Studio
4 // Copyright (c) 2010 by Rainer Schuetze, All Rights Reserved
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt
8 
9 module c2d.dgutil;
10 
11 import std.string;
12 import std.ascii;
13 import std.utf;
14 import std.path;
15 import std.array;
16 import core.exception;
17 
18 //////////////////////////////////////////////////////////////////////////////
19 
20 class SyntaxException : Exception
21 {
22 	this(string msg)
23 	{
24 		super(msg);
25 		count++;
26 	}
27 
28 	static int count;
29 }
30 
31 void throwException(string msg)
32 {
33 	throw new SyntaxException(msg);
34 }
35 
36 void throwException(int line, string msg)
37 {
38 	throw new SyntaxException(format("(%d): ", line) ~ msg);
39 }
40 
41 void assume(T)(T cond, int line = __LINE__, string file = __FILE__)
42 {
43 	debug if(!cond)
44 		throw new AssertError(file, line);
45 	assert(cond);
46 }
47 
48 void assume(T)(T cond, string msg, int line = __LINE__, string file = __FILE__)
49 {
50 	debug if(!cond)
51 		throw new AssertError(msg, file, line);
52 	assert(cond);
53 }
54 
55 //////////////////////////////////////////////////////////////////////////////
56 
57 string getNameWithoutExt(string fname)
58 {
59 	string bname = baseName(fname);
60 	string name = stripExtension(bname);
61 	if(name.length == 0)
62 		name = bname;
63 	return name;
64 }
65 
66 //////////////////////////////////////////////////////////////////////////////
67 
68 string reindent(string txt, int indent, int tabsize)
69 {
70 	string ntxt;
71 	size_t pos = 0;
72 	for( ; ; )
73 	{
74 		ptrdiff_t p = indexOf(txt[pos .. $], '\n');
75 		if(p < 0)
76 			break;
77 		ntxt ~= txt[pos .. pos + p + 1];
78 		pos += p + 1;
79 		int indentation = 0;
80 		for(p = pos; p < txt.length; p++)
81 		{
82 			if(txt[p] == ' ')
83 				indentation++;
84 			else if(txt[p] == '\t')
85 				indentation = tabsize == 0 ? (indentation + 8) & ~7 : ((indentation + tabsize) / tabsize) * tabsize;
86 			else
87 				break;
88 		}
89 		indentation += indent;
90 		if(indentation < 0)
91 			indentation = 0;
92 
93 		string spaces = replicate("\t", tabsize == 0 ? 0 : indentation / tabsize)
94 			          ~ replicate(" ", tabsize == 0 ? indentation : indentation % tabsize);
95 		ntxt ~= spaces;
96 		pos = p;
97 	}
98 	ntxt ~= txt[pos .. $];
99 	return ntxt;
100 }
101 
102 string cpp_string(string txt)
103 {
104 	string ntxt;
105 	bool escapeNext = false;
106 	foreach(dchar ch; txt)
107 	{
108 		if(escapeNext)
109 		{
110 			switch(ch)
111 			{
112 			case '\\': ch = '\\'; break;
113 			case 'a':  ch = '\a'; break;
114 			case 'r':  ch = '\r'; break;
115 			case 'n':  ch = '\n'; break;
116 			case 't':  ch = '\t'; break;
117 			case '"':  ch = '\"'; break;
118 			case '\'': ch = '\''; break;
119 			default:   break;
120 			}
121 			escapeNext = false;
122 		}
123 		else if(ch == '\\')
124 		{
125 			escapeNext = true;
126 			continue;
127 		}
128 		ntxt ~= toUTF8((&ch)[0..1]);
129 	}
130 	return ntxt;
131 }
132 
133 string removeDuplicateEmptyLines(string txt)
134 {
135 	string ntxt;
136 	size_t npos = 0;
137 	size_t pos = 0;
138 	while(pos < txt.length)
139 	{
140 		dchar ch = decode(txt, pos);
141 		if(ch == '\n')
142 		{
143 			uint nl = 0;
144 			size_t nlpos = pos; // positions after nl
145 			size_t lastnlpos = pos;
146 			while(pos < txt.length)
147 			{
148 				ch = decode(txt, pos);
149 				if(ch == '\n')
150 				{
151 					nl++;
152 					lastnlpos = pos;
153 				}
154 				else if(!isWhite(ch))
155 					break;
156 			}
157 			if(nl > 1)
158 			{
159 				ntxt ~= txt[npos .. nlpos];
160 				ntxt ~= '\n';
161 				npos = lastnlpos;
162 			}
163 		}
164 	}
165 	ntxt ~= txt[npos .. pos];
166 	return ntxt;
167 }
168 
169 unittest
170 {
171 	string txt;
172 	txt = removeDuplicateEmptyLines("abc\n\n\nefg");
173 	assume(txt == "abc\n\nefg");
174 	txt = removeDuplicateEmptyLines("abc\n\nefg");
175 	assume(txt == "abc\n\nefg");
176 }
177 
178 //////////////////////////////////////////////////////////////////////////////
179 
180 unittest
181 {
182 	string txt =
183 		"\nvoid foo()\n"
184 		~ "{\n"
185 		~ "    if(1)\n"
186 		~ "\tx = 0;\n"
187 		~ "}";
188 	string exp =
189 		"\n    void foo()\n"
190 		~ "    {\n"
191 		~ "\tif(1)\n"
192 		~ "\t    x = 0;\n"
193 		~ "    }";
194 
195 	string res = reindent(txt, 4, 8);
196 	assume(res == exp);
197 }
198