00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "cvsSourceTree.h"
00020 #include "cvsSourceDirectory.h"
00021
00022 #include "filename.h"
00023 #include "executionEnvironment.h"
00024 #include "notify.h"
00025
00026 #include <algorithm>
00027 #include <ctype.h>
00028 #include <stdio.h>
00029 #include <errno.h>
00030
00031 #ifdef WIN32_VC
00032 #include <direct.h>
00033 #endif
00034
00035 bool CVSSourceTree::_got_start_fullpath = false;
00036 Filename CVSSourceTree::_start_fullpath;
00037
00038
00039
00040
00041
00042
00043 CVSSourceTree::
00044 CVSSourceTree() {
00045 _root = (CVSSourceDirectory *)NULL;
00046 _got_root_fullpath = false;
00047 }
00048
00049
00050
00051
00052
00053
00054 CVSSourceTree::
00055 ~CVSSourceTree() {
00056 if (_root != (CVSSourceDirectory *)NULL) {
00057 delete _root;
00058 }
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068 void CVSSourceTree::
00069 set_root(const Filename &root_path) {
00070 nassertv(_path.empty());
00071 _path = root_path;
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 bool CVSSourceTree::
00083 scan(const Filename &key_filename) {
00084 nassertr(_root == (CVSSourceDirectory *)NULL, false);
00085 Filename root_fullpath = get_root_fullpath();
00086 _root = new CVSSourceDirectory(this, NULL, root_fullpath.get_basename());
00087 return _root->scan(_path, key_filename);
00088 }
00089
00090
00091
00092
00093
00094
00095 CVSSourceDirectory *CVSSourceTree::
00096 get_root() const {
00097 return _root;
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107 CVSSourceDirectory *CVSSourceTree::
00108 find_directory(const Filename &path) {
00109 string root_fullpath = get_root_fullpath();
00110 string fullpath = get_actual_fullpath(path);
00111
00112
00113
00114 if (root_fullpath.length() > fullpath.length() ||
00115 fullpath.substr(0, root_fullpath.length()) != root_fullpath) {
00116
00117 return (CVSSourceDirectory *)NULL;
00118 }
00119
00120
00121 Filename relpath = fullpath.substr(root_fullpath.length());
00122
00123 return _root->find_relpath(relpath);
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 CVSSourceDirectory *CVSSourceTree::
00135 find_relpath(const string &relpath) {
00136 CVSSourceDirectory *result = _root->find_relpath(relpath);
00137 if (result != (CVSSourceDirectory *)NULL) {
00138 return result;
00139 }
00140
00141
00142
00143 size_t slash = relpath.find('/');
00144 Filename first = relpath.substr(0, slash);
00145 Filename rest;
00146 if (slash != string::npos) {
00147 rest = relpath.substr(slash + 1);
00148 }
00149
00150 if (first == _root->get_dirname()) {
00151 return _root->find_relpath(rest);
00152 }
00153
00154 return (CVSSourceDirectory *)NULL;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164 CVSSourceDirectory *CVSSourceTree::
00165 find_dirname(const string &dirname) {
00166 return _root->find_dirname(dirname);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 CVSSourceDirectory *CVSSourceTree::
00180 choose_directory(const Filename &filename, CVSSourceDirectory *suggested_dir,
00181 bool force, bool interactive) {
00182 static Directories empty_dirs;
00183
00184 Filenames::const_iterator fi;
00185 fi = _filenames.find(filename);
00186 if (fi != _filenames.end()) {
00187
00188 const Directories &dirs = (*fi).second;
00189
00190 return prompt_user(filename, suggested_dir, dirs,
00191 force, interactive);
00192 }
00193
00194
00195 return prompt_user(filename, suggested_dir, empty_dirs,
00196 force, interactive);
00197 }
00198
00199
00200
00201
00202
00203
00204
00205 Filename CVSSourceTree::
00206 get_root_fullpath() {
00207 nassertr(!_path.empty(), Filename());
00208 if (!_got_root_fullpath) {
00209 _root_fullpath = get_actual_fullpath(_path);
00210 _got_root_fullpath = true;
00211 }
00212 return _root_fullpath;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221 Filename CVSSourceTree::
00222 get_root_dirname() const {
00223 nassertr(_root != (CVSSourceDirectory *)NULL, Filename());
00224 return _root->get_dirname();
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234 void CVSSourceTree::
00235 add_file(const Filename &filename, CVSSourceDirectory *dir) {
00236 _filenames[filename].push_back(dir);
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247 bool CVSSourceTree::
00248 temp_chdir(const Filename &path) {
00249
00250
00251 get_start_fullpath();
00252
00253 string os_path = path.to_os_specific();
00254 if (chdir(os_path.c_str()) < 0) {
00255 return false;
00256 }
00257 return true;
00258 }
00259
00260
00261
00262
00263
00264
00265
00266 void CVSSourceTree::
00267 restore_cwd() {
00268 Filename start_fullpath = get_start_fullpath();
00269 string os_path = start_fullpath.to_os_specific();
00270
00271 if (chdir(os_path.c_str()) < 0) {
00272
00273 perror(os_path.c_str());
00274 nout << "Can't continue, aborting.\n";
00275 exit(1);
00276 }
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286 CVSSourceDirectory *CVSSourceTree::
00287 prompt_user(const string &filename, CVSSourceDirectory *suggested_dir,
00288 const CVSSourceTree::Directories &dirs,
00289 bool force, bool interactive) {
00290 if (dirs.size() == 1) {
00291
00292 if (!interactive) {
00293 return dirs[0];
00294 }
00295 CVSSourceDirectory *result = ask_existing(filename, dirs[0]);
00296 if (result != (CVSSourceDirectory *)NULL) {
00297 return result;
00298 }
00299
00300 } else if (dirs.size() > 1) {
00301
00302 if (force && !interactive) {
00303 return dirs[0];
00304 }
00305 CVSSourceDirectory *result = ask_existing(filename, dirs, suggested_dir);
00306 if (result != (CVSSourceDirectory *)NULL) {
00307 return result;
00308 }
00309 }
00310
00311
00312
00313 if (force && !interactive) {
00314 return suggested_dir;
00315 }
00316
00317 if (find(dirs.begin(), dirs.end(), suggested_dir) == dirs.end()) {
00318 CVSSourceDirectory *result = ask_new(filename, suggested_dir);
00319 if (result != (CVSSourceDirectory *)NULL) {
00320 return result;
00321 }
00322 }
00323
00324
00325 return ask_any(filename);
00326 }
00327
00328
00329
00330
00331
00332
00333
00334 CVSSourceDirectory *CVSSourceTree::
00335 ask_existing(const string &filename, CVSSourceDirectory *dir) {
00336 while (true) {
00337 nout << filename << " found in tree at "
00338 << dir->get_path() + "/" + filename << ".\n";
00339 string result = prompt("Overwrite this file (y/n)? ");
00340 nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
00341 if (result.size() == 1) {
00342 if (tolower(result[0]) == 'y') {
00343 return dir;
00344 } else if (tolower(result[0]) == 'n') {
00345 return NULL;
00346 }
00347 }
00348
00349 nout << "*** Invalid response: " << result << "\n\n";
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 CVSSourceDirectory *CVSSourceTree::
00360 ask_existing(const string &filename, const CVSSourceTree::Directories &dirs,
00361 CVSSourceDirectory *suggested_dir) {
00362 while (true) {
00363 nout << filename << " found in tree at more than one place:\n";
00364
00365 bool any_suggested = false;
00366 for (int i = 0; i < (int)dirs.size(); i++) {
00367 nout << " " << (i + 1) << ". "
00368 << dirs[i]->get_path() + "/" + filename << "\n";
00369 if (dirs[i] == suggested_dir) {
00370 any_suggested = true;
00371 }
00372 }
00373
00374 int next_option = dirs.size() + 1;
00375 int suggested_option = -1;
00376
00377 if (!any_suggested) {
00378 suggested_option = next_option;
00379 next_option++;
00380 nout << "\n" << suggested_option
00381 << ". create "
00382 << suggested_dir->get_path() + "/" + filename
00383 << "\n";
00384 }
00385
00386 int other_option = next_option;
00387 nout << other_option << ". Other\n";
00388
00389 string result = prompt("Choose an option: ");
00390 nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
00391 const char *nptr = result.c_str();
00392 char *endptr;
00393 int option = strtol(nptr, &endptr, 10);
00394 if (*endptr == '\0') {
00395 if (option >= 1 && option <= (int)dirs.size()) {
00396 return dirs[option - 1];
00397
00398 } else if (option == suggested_option) {
00399 return suggested_dir;
00400
00401 } else if (option == other_option) {
00402 return NULL;
00403 }
00404 }
00405
00406 nout << "*** Invalid response: " << result << "\n\n";
00407 }
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 CVSSourceDirectory *CVSSourceTree::
00417 ask_new(const string &filename, CVSSourceDirectory *dir) {
00418 while (true) {
00419 nout << filename << " will be created in "
00420 << dir->get_path() << ".\n";
00421 string result = prompt("Create this file (y/n)? ");
00422 nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
00423 if (result.size() == 1) {
00424 if (tolower(result[0]) == 'y') {
00425 return dir;
00426 } else if (tolower(result[0]) == 'n') {
00427 return NULL;
00428 }
00429 }
00430
00431 nout << "*** Invalid response: " << result << "\n\n";
00432 }
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 CVSSourceDirectory *CVSSourceTree::
00442 ask_any(const string &filename) {
00443 while (true) {
00444 string result =
00445 prompt("Enter the name of the directory to copy " + filename + " to: ");
00446 nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
00447
00448
00449
00450
00451 CVSSourceDirectory *dir = find_directory(result);
00452 if (dir == (CVSSourceDirectory *)NULL) {
00453 dir = find_relpath(result);
00454 }
00455 if (dir == (CVSSourceDirectory *)NULL) {
00456 dir = find_dirname(result);
00457 }
00458
00459 if (dir != (CVSSourceDirectory *)NULL) {
00460 return dir;
00461 }
00462
00463 nout << "*** Not a valid directory name: " << result << "\n\n";
00464 }
00465 }
00466
00467
00468
00469
00470
00471
00472
00473
00474 string CVSSourceTree::
00475 prompt(const string &message) {
00476 nout << flush;
00477 while (true) {
00478 cerr << message << flush;
00479 string response;
00480 getline(cin, response);
00481
00482
00483 size_t p = 0;
00484 while (p < response.length() && isspace(response[p])) {
00485 p++;
00486 }
00487
00488 size_t q = response.length();
00489 while (q > p && isspace(response[q - 1])) {
00490 q--;
00491 }
00492
00493 if (q > p) {
00494 return response.substr(p, q - p);
00495 }
00496 }
00497 }
00498
00499
00500
00501
00502
00503
00504
00505 Filename CVSSourceTree::
00506 get_actual_fullpath(const Filename &path) {
00507 Filename canon = path;
00508 canon.make_canonical();
00509 return canon;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519 Filename CVSSourceTree::
00520 get_start_fullpath() {
00521 if (!_got_start_fullpath) {
00522 Filename cwd = ExecutionEnvironment::get_cwd();
00523 _start_fullpath = cwd.to_os_specific();
00524 }
00525 return _start_fullpath;
00526 }