History

the only constant is change.

Ge Wang committed 9 years ago

Commit 009ac191 parent b1e2669181 files · +0 −3911Browse files

Showing the changes to src/core/util_string.cpp (1 of 181 files). Show all

Unified · Split

src/core/util_string.cpp+569−0
@@ -0,0 +1,569 @@
1/*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
4
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.stanford.edu/
7 http://chuck.cs.princeton.edu/
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23-----------------------------------------------------------------------------*/
24
25//-----------------------------------------------------------------------------
26// name: util_string.cpp
27// desc: string functions utility
28//
29// author: Ge Wang (ge@ccrma.stanford.edu | gewang@cs.princeton.edu)
30// Spencer Salazar (spencer@ccrma.stanford.edu)
31// date: Summer 2005
32//-----------------------------------------------------------------------------
33#include "util_string.h"
34#include "chuck_errmsg.h"
35
36#ifdef __PLATFORM_WIN32__
37#include <Windows.h>
38#endif // __PLATFORM_WIN32__
39
40#ifdef __PLATFORM_LINUX__
41#include <linux/limits.h>
42#endif // __PLATFORM_LINUX__
43
44#include <stdio.h>
45using namespace std;
46
47
48
49//-----------------------------------------------------------------------------
50// name: itoa()
51// desc: ...
52//-----------------------------------------------------------------------------
53string itoa( t_CKINT val )
54{
55 char buffer[128];
56 sprintf( buffer, "%li", val );
57 return string(buffer);
58}
59
60
61
62//-----------------------------------------------------------------------------
63// name: ftoa()
64// desc: ...
65//-----------------------------------------------------------------------------
66string ftoa( t_CKFLOAT val, t_CKUINT precision )
67{
68 char str[32];
69 char buffer[128];
70 if( precision > 32 ) precision = 32;
71 sprintf( str, "%%.%lif", precision );
72 sprintf( buffer, str, val );
73 return string(buffer);
74}
75
76
77
78
79//-----------------------------------------------------------------------------
80// name: tolower()
81// desc: ...
82//-----------------------------------------------------------------------------
83string tolower( const string & str )
84{
85 string s = str;
86 t_CKUINT len = s.length();
87
88 // loop
89 for( t_CKUINT i = 0; i < len; i++ )
90 if( s[i] >= 'A' && s[i] <= 'Z' )
91 s[i] += 32;
92
93 return s;
94}
95
96
97
98
99//-----------------------------------------------------------------------------
100// name: toupper()
101// desc: ...
102//-----------------------------------------------------------------------------
103string toupper( const string & str )
104{
105 string s = str;
106 t_CKUINT len = s.length();
107
108 // loop
109 for( t_CKUINT i = 0; i < len; i++ )
110 if( s[i] >= 'a' && s[i] <= 'z' )
111 s[i] -= 32;
112
113 return s;
114}
115
116
117
118
119//-----------------------------------------------------------------------------
120// name: trim()
121// desc: ...
122//-----------------------------------------------------------------------------
123string trim( const string & val )
124{
125 // two ends
126 t_CKINT start = 0;
127 t_CKINT end = val.length() - 1;
128
129 // left trim
130 for( start = 0; start < end; start++ )
131 {
132 // non-white space
133 if( val[start] != ' ' && val[start] != '\t' )
134 break;
135 }
136
137 // if start > end, then all white space
138 if( start > end ) return "";
139
140 // right trim
141 for( ; end >= start; end-- )
142 {
143 // non-white space
144 if( val[end] != ' ' && val[end] != '\t' )
145 break;
146 }
147
148 // cannot be
149 assert( end >= start );
150
151 // return
152 return val.substr( start, end - start + 1 );
153}
154
155
156
157//-----------------------------------------------------------------------------
158// name: ltrim()
159// desc: ...
160//-----------------------------------------------------------------------------
161string ltrim( const string & val )
162{
163 // two ends
164 t_CKINT start = 0;
165 t_CKINT end = val.length() - 1;
166
167 // left trim
168 for( start = 0; start < end; start++ )
169 {
170 // non-white space
171 if( val[start] != ' ' && val[start] != '\t' )
172 break;
173 }
174
175 // if start > end, then all white space
176 if( start > end ) return "";
177
178 // return
179 return val.substr( start, end - start + 1 );
180}
181
182
183
184
185//-----------------------------------------------------------------------------
186// name: rtrim()
187// desc: ...
188//-----------------------------------------------------------------------------
189string rtrim( const string & val )
190{
191 // two ends
192 t_CKINT start = 0;
193 t_CKINT end = val.length() - 1;
194
195 // right trim
196 for( ; end >= start; end-- )
197 {
198 // non-white space
199 if( val[end] != ' ' && val[end] != '\t' )
200 break;
201 }
202
203 // if end < start, then all white space
204 if( end < start ) return "";
205
206 // return
207 return val.substr( start, end - start + 1 );
208}
209
210
211
212
213//-----------------------------------------------------------------------------
214// name: extract_args()
215// desc: extract argument from format filename:arg1:arg2:etc
216//-----------------------------------------------------------------------------
217t_CKBOOL extract_args( const string & token,
218 string & filename, vector<string> & args )
219{
220 // clear vector
221 args.clear();
222 // clear filename
223 filename = "";
224
225 // last : found pos
226 t_CKINT prev_pos = 0;
227 // curr : pos
228 t_CKINT i = 0;
229
230 string tmp;
231
232 // copy and trim
233 string s = trim( token );
234
235 // ignore second character as arg separator if its : on Windows
236 t_CKBOOL ignoreSecond = FALSE;
237#ifdef __PLATFORM_WIN32__
238 ignoreSecond = TRUE;
239#endif // __PLATFORM_WIN32__
240
241 // detect
242 t_CKBOOL scan = FALSE;
243 t_CKBOOL ret = TRUE;
244 t_CKBOOL ignoreNext = FALSE;
245 char * mask = NULL;
246 for( i = 0; i < s.length(); i++ )
247 if( s[i] == '\\' )
248 {
249 scan = TRUE;
250 break;
251 }
252
253 // mad...
254 if( scan )
255 {
256 mask = new char[s.length()];
257 // zero
258 memset(mask, 0, s.length()*sizeof(char));
259
260 // loop through
261 for( i = 0; i < s.length(); i++ )
262 {
263 // escape (tom and ge fixed this, which used to look for \\ then : and randomly incremented i)
264 // added '/' 1.3.1.1
265 // if( s[i] == ':' && (i+1) < s.length() && ( s[i+1] == '\\' || s[i+1] == '/' ) )
266 // {
267 // mask[i] = 1;
268 // break; // added 1.3.1.1
269 // }
270
271 // 1.3.2.0: spencer and ge fixed this, requiring \ to escape :
272 if( s[i] == '\\' && (i+1) < s.length() )
273 {
274 // check next char
275 if( s[i+1] == ':' || s[i+1] == '\\' )
276 {
277 // add
278 mask[i] = 1;
279 // skip next character
280 i++;
281 }
282 else
283 {
284 // error: recognized escape target
285 CK_FPRINTF_STDERR( "[chuck]: unrecognized escape sequence: \\%c", s[i+1] );
286 // return false
287 ret = FALSE;
288 // go clean
289 goto done;
290 }
291 }
292 }
293 }
294
295 // loop through
296 for( i = 0; i < s.length(); i++ )
297 {
298 // check mask
299 if( mask && mask[i] )
300 {
301 //CK_FPRINTF_STDERR( "skipping %c\n", s[i] );
302 // mark the next as false
303 ignoreNext = TRUE;
304 // skip this one
305 continue;
306 }
307
308 // look for :
309 if( !ignoreNext && s[i] == ':' && !(ignoreSecond && i == 1))
310 {
311 // sanity
312 if( i == 0 )
313 {
314 ret = FALSE;
315 goto done;
316 }
317
318 // copy
319 if( filename == "" )
320 filename = tmp;
321 else
322 args.push_back( tmp );
323
324 tmp = "";
325
326 // update
327 prev_pos = i + 1;
328 }
329 else
330 {
331 tmp.append(1, s[i]);
332 }
333
334 // reset
335 ignoreNext = FALSE;
336 }
337
338 // get the remainder, if any
339 if( tmp.length() )
340 {
341 // copy
342 if( filename == "" )
343 filename = tmp;
344 else
345 args.push_back( tmp );
346 }
347
348 // testing code - spencer 1.3.2.0
349// CK_FPRINTF_STDERR( "INPUT: %s\n", token.c_str() );
350// CK_FPRINTF_STDERR( "FILENAME: %s\n", filename.c_str() );
351// for(i = 0; i < args.size(); i++)
352// CK_FPRINTF_STDERR( "ARG: %s\n", args[i].c_str() );
353
354done:
355 // reclaim
356 SAFE_DELETE_ARRAY( mask );
357
358 return ret;
359}
360
361
362/* from http://developer.apple.com/library/mac/#qa/qa1549/_index.html */
363
364#ifndef __PLATFORM_WIN32__
365
366#include <glob.h>
367
368char* CreatePathByExpandingTildePath(const char* path)
369{
370 glob_t globbuf;
371 char **v;
372 char *expandedPath = NULL, *result = NULL;
373
374 assert(path != NULL);
375
376 if (glob(path, GLOB_TILDE, NULL, &globbuf) == 0) //success
377 {
378 v = globbuf.gl_pathv; //list of matched pathnames
379 expandedPath = v[0]; //number of matched pathnames, gl_pathc == 1
380
381 result = (char*)calloc(1, strlen(expandedPath) + 1); //the extra char is for the null-termination
382 if(result)
383 strncpy(result, expandedPath, strlen(expandedPath) + 1); //copy the null-termination as well
384
385 globfree(&globbuf);
386 }
387
388 return result;
389}
390
391#endif // __PLATFORM_WIN32__
392
393
394// get full path to file
395std::string get_full_path( const std::string & fp )
396{
397#ifndef __PLATFORM_WIN32__
398
399 char buf[PATH_MAX];
400
401 char * result = realpath(fp.c_str(), buf);
402
403 // try with .ck extension
404 if(result == NULL && !str_endsin(fp.c_str(), ".ck"))
405 result = realpath((fp + ".ck").c_str(), buf);
406
407 if(result == NULL)
408 return fp;
409 else
410 return buf;
411
412#else //
413
414 char buf[MAX_PATH];
415
416 DWORD result = GetFullPathName(fp.c_str(), MAX_PATH, buf, NULL);
417
418 // try with .ck extension
419 if(result == 0 && !str_endsin(fp.c_str(), ".ck"))
420 result = GetFullPathName((fp + ".ck").c_str(), MAX_PATH, buf, NULL);
421
422 if(result == 0)
423 return fp;
424 else
425 return normalize_directory_separator(buf);
426
427#endif // __PLATFORM_WIN32__
428}
429
430
431std::string expand_filepath( std::string & fp )
432{
433#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
434 // no expansion in Windows systems
435 return fp;
436#else
437
438 char * expanded_cstr = CreatePathByExpandingTildePath( fp.c_str() );
439
440 if(expanded_cstr == NULL)
441 return fp;
442
443 std::string expanded_stdstr = expanded_cstr;
444
445 free(expanded_cstr);
446
447 return expanded_stdstr;
448
449#endif
450}
451
452
453std::string extract_filepath_dir(std::string &filepath)
454{
455 char path_separator = '/';
456
457//#ifdef __WINDOWS_DS__
458// path_separator = '\\';
459//#else
460// path_separator = '/';
461//#endif
462
463 // if the last character is a slash, skip it
464 int i = filepath.rfind(path_separator);
465
466 if(i == std::string::npos)
467 return std::string();
468
469 // skip any/all extra trailing slashes
470 while( i > 0 && filepath[i-1] == path_separator )
471 i--;
472
473 // change spencer 2014-7-17: include trailing slash
474 return std::string(filepath, 0, i+1);
475}
476
477// added: ge 1.3.2.0
478string dir_go_up( const string & dir, t_CKINT numUp )
479{
480 // separator
481 char path_separator = '/';
482
483 // sanity check
484 if( numUp < 0 ) numUp = -numUp;
485
486 // pos
487 size_t pos = dir.length();
488
489 // skip any trailing slashes
490 while( pos > 0 && dir[pos-1] == path_separator )
491 pos--;
492
493 // loop
494 while( numUp > 0 )
495 {
496 // find the last slash
497 pos = dir.rfind( path_separator, pos-1 );
498 // skip any extra slashes
499 while( pos > 0 && dir[pos-1] == path_separator )
500 pos--;
501
502 // not there
503 if( pos == string::npos )
504 return "";
505 else if( pos == 0 )
506 return "/";
507
508 // TODO: what about windows?
509 // TODO: what about windows network: with two backslashes? "\\\\"
510
511 // decrement
512 numUp--;
513 }
514
515
516 // otherwise
517 // change spencer 2014-7-17: include trailing slash
518 string str = string( dir, 0, pos );
519 if( str[str.length()-1] != '/' ) str = str + "/";
520 return str;
521}
522
523//-----------------------------------------------------------------------------
524// name: parse_path_list()
525// desc: split "x:y:z"-style path list into {"x","y","z"}
526//-----------------------------------------------------------------------------
527void parse_path_list( std::string & str, std::list<std::string> & lst )
528{
529#if defined(__PLATFORM_WIN32__)
530 const char separator = ';';
531#else
532 const char separator = ':';
533#endif
534 std::string::size_type i = 0, last = 0;
535 while( last < str.size() &&
536 ( i = str.find( separator, last ) ) != std::string::npos )
537 {
538 lst.push_back( str.substr( last, i - last ) );
539 last = i + 1;
540 }
541
542 lst.push_back( str.substr( last, str.size() - last ) );
543}
544
545
546
547std::string normalize_directory_separator(const std::string &filepath)
548{
549#ifdef __PLATFORM_WIN32__
550 std::string new_filepath = filepath;
551 int len = new_filepath.size();
552 for(int i = 0; i < len; i++)
553 {
554 if(new_filepath[i] == '\\') new_filepath[i] = '/';
555 }
556
557 return new_filepath;
558#else
559 return std::string(filepath);
560#endif // __PLATFORM_WIN32__
561}
562
563int str_endsin(const char *str, const char *end)
564{
565 size_t len = strlen(str);
566 size_t endlen = strlen(end);
567
568 return strncmp(str+(len-endlen), end, endlen) == 0;
569}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t