[29] | 1 | /* |
---|
| 2 | * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. |
---|
| 3 | * |
---|
| 4 | * This file is part of Jam - see jam.c for Copyright information. |
---|
| 5 | */ |
---|
| 6 | |
---|
| 7 | /* This file is ALSO: |
---|
| 8 | * Copyright 2001-2004 David Abrahams. |
---|
| 9 | * Distributed under the Boost Software License, Version 1.0. |
---|
| 10 | * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | # include "jam.h" |
---|
| 14 | # include "pathsys.h" |
---|
| 15 | |
---|
| 16 | # ifdef OS_VMS |
---|
| 17 | |
---|
| 18 | # define DEBUG |
---|
| 19 | |
---|
| 20 | /* |
---|
| 21 | * pathvms.c - manipulate file names on VMS |
---|
| 22 | * |
---|
| 23 | * External routines: |
---|
| 24 | * |
---|
| 25 | * path_parse() - split a file name into dir/base/suffix/member |
---|
| 26 | * path_build() - build a filename given dir/base/suffix/member |
---|
| 27 | * path_parent() - make a PATHNAME point to its parent dir |
---|
| 28 | * |
---|
| 29 | * File_parse() and path_build() just manipuate a string and a structure; |
---|
| 30 | * they do not make system calls. |
---|
| 31 | * |
---|
| 32 | * WARNING! This file contains voodoo logic, as black magic is |
---|
| 33 | * necessary for wrangling with VMS file name. Woe be to people |
---|
| 34 | * who mess with this code. |
---|
| 35 | * |
---|
| 36 | * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length! |
---|
| 37 | * 05/03/96 (seiwald) - split from filevms.c |
---|
| 38 | */ |
---|
| 39 | |
---|
| 40 | /* |
---|
| 41 | * path_parse() - split a file name into dir/base/suffix/member |
---|
| 42 | */ |
---|
| 43 | |
---|
| 44 | void |
---|
| 45 | path_parse( |
---|
| 46 | char *file, |
---|
| 47 | PATHNAME *f ) |
---|
| 48 | { |
---|
| 49 | char *p, *q; |
---|
| 50 | char *end; |
---|
| 51 | |
---|
| 52 | memset( (char *)f, 0, sizeof( *f ) ); |
---|
| 53 | |
---|
| 54 | /* Look for <grist> */ |
---|
| 55 | |
---|
| 56 | if( file[0] == '<' && ( p = strchr( file, '>' ) ) ) |
---|
| 57 | { |
---|
| 58 | f->f_grist.ptr = file; |
---|
| 59 | f->f_grist.len = p - file; |
---|
| 60 | file = p + 1; |
---|
| 61 | } |
---|
| 62 | |
---|
| 63 | /* Look for dev:[dir] or dev: */ |
---|
| 64 | |
---|
| 65 | if( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) ) |
---|
| 66 | { |
---|
| 67 | f->f_dir.ptr = file; |
---|
| 68 | f->f_dir.len = p + 1 - file; |
---|
| 69 | file = p + 1; |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | end = file + strlen( file ); |
---|
| 73 | |
---|
| 74 | /* Look for (member) */ |
---|
| 75 | |
---|
| 76 | if( ( p = strchr( file, '(' ) ) && end[-1] == ')' ) |
---|
| 77 | { |
---|
| 78 | f->f_member.ptr = p + 1; |
---|
| 79 | f->f_member.len = end - p - 2; |
---|
| 80 | end = p; |
---|
| 81 | } |
---|
| 82 | |
---|
| 83 | /* Look for .suffix */ |
---|
| 84 | /* This would be memrchr() */ |
---|
| 85 | |
---|
| 86 | p = 0; |
---|
| 87 | q = file; |
---|
| 88 | |
---|
| 89 | while( q = (char *)memchr( q, '.', end - q ) ) |
---|
| 90 | p = q++; |
---|
| 91 | |
---|
| 92 | if( p ) |
---|
| 93 | { |
---|
| 94 | f->f_suffix.ptr = p; |
---|
| 95 | f->f_suffix.len = end - p; |
---|
| 96 | end = p; |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | /* Leaves base */ |
---|
| 100 | |
---|
| 101 | f->f_base.ptr = file; |
---|
| 102 | f->f_base.len = end - file; |
---|
| 103 | |
---|
| 104 | /* Is this a directory without a file spec? */ |
---|
| 105 | |
---|
| 106 | f->parent = 0; |
---|
| 107 | } |
---|
| 108 | |
---|
| 109 | /* |
---|
| 110 | * dir mods result |
---|
| 111 | * --- --- ------ |
---|
| 112 | * Rerooting: |
---|
| 113 | * |
---|
| 114 | * (none) :R=dev: dev: |
---|
| 115 | * devd: :R=dev: devd: |
---|
| 116 | * devd:[dir] :R=dev: devd:[dir] |
---|
| 117 | * [.dir] :R=dev: dev:[dir] questionable |
---|
| 118 | * [dir] :R=dev: dev:[dir] |
---|
| 119 | * |
---|
| 120 | * (none) :R=[rdir] [rdir] questionable |
---|
| 121 | * devd: :R=[rdir] devd: |
---|
| 122 | * devd:[dir] :R=[rdir] devd:[dir] |
---|
| 123 | * [.dir] :R=[rdir] [rdir.dir] questionable |
---|
| 124 | * [dir] :R=[rdir] [rdir] |
---|
| 125 | * |
---|
| 126 | * (none) :R=dev:[root] dev:[root] |
---|
| 127 | * devd: :R=dev:[root] devd: |
---|
| 128 | * devd:[dir] :R=dev:[root] devd:[dir] |
---|
| 129 | * [.dir] :R=dev:[root] dev:[root.dir] |
---|
| 130 | * [dir] :R=dev:[root] [dir] |
---|
| 131 | * |
---|
| 132 | * Climbing to parent: |
---|
| 133 | * |
---|
| 134 | */ |
---|
| 135 | |
---|
| 136 | # define DIR_EMPTY 0 /* empty string */ |
---|
| 137 | # define DIR_DEV 1 /* dev: */ |
---|
| 138 | # define DIR_DEVDIR 2 /* dev:[dir] */ |
---|
| 139 | # define DIR_DOTDIR 3 /* [.dir] */ |
---|
| 140 | # define DIR_DASHDIR 4 /* [-] or [-.dir] */ |
---|
| 141 | # define DIR_ABSDIR 5 /* [dir] */ |
---|
| 142 | # define DIR_ROOT 6 /* [000000] or dev:[000000] */ |
---|
| 143 | |
---|
| 144 | # define G_DIR 0 /* take just dir */ |
---|
| 145 | # define G_ROOT 1 /* take just root */ |
---|
| 146 | # define G_VAD 2 /* root's dev: + [abs] */ |
---|
| 147 | # define G_DRD 3 /* root's dev:[dir] + [.rel] */ |
---|
| 148 | # define G_VRD 4 /* root's dev: + [.rel] made [abs] */ |
---|
| 149 | # define G_DDD 5 /* root's dev:[dir] + . + [dir] */ |
---|
| 150 | |
---|
| 151 | static int grid[7][7] = { |
---|
| 152 | |
---|
| 153 | /* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */ |
---|
| 154 | /* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, |
---|
| 155 | /* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD, |
---|
| 156 | /* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD, |
---|
| 157 | /* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, |
---|
| 158 | /* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR, |
---|
| 159 | /* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR, |
---|
| 160 | /* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR, |
---|
| 161 | |
---|
| 162 | } ; |
---|
| 163 | |
---|
| 164 | struct dirinf { |
---|
| 165 | int flags; |
---|
| 166 | |
---|
| 167 | struct { |
---|
| 168 | char *ptr; |
---|
| 169 | int len; |
---|
| 170 | } dev, dir; |
---|
| 171 | } ; |
---|
| 172 | |
---|
| 173 | static char * |
---|
| 174 | strnchr( |
---|
| 175 | char *buf, |
---|
| 176 | int c, |
---|
| 177 | int len ) |
---|
| 178 | { |
---|
| 179 | while( len-- ) |
---|
| 180 | if( *buf && *buf++ == c ) |
---|
| 181 | return buf - 1; |
---|
| 182 | |
---|
| 183 | return 0; |
---|
| 184 | } |
---|
| 185 | |
---|
| 186 | static void |
---|
| 187 | dir_flags( |
---|
| 188 | char *buf, |
---|
| 189 | int len, |
---|
| 190 | struct dirinf *i ) |
---|
| 191 | { |
---|
| 192 | char *p; |
---|
| 193 | |
---|
| 194 | if( !buf || !len ) |
---|
| 195 | { |
---|
| 196 | i->flags = DIR_EMPTY; |
---|
| 197 | i->dev.ptr = |
---|
| 198 | i->dir.ptr = 0; |
---|
| 199 | i->dev.len = |
---|
| 200 | i->dir.len = 0; |
---|
| 201 | } |
---|
| 202 | else if( p = strnchr( buf, ':', len ) ) |
---|
| 203 | { |
---|
| 204 | i->dev.ptr = buf; |
---|
| 205 | i->dev.len = p + 1 - buf; |
---|
| 206 | i->dir.ptr = buf + i->dev.len; |
---|
| 207 | i->dir.len = len - i->dev.len; |
---|
| 208 | i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV; |
---|
| 209 | } |
---|
| 210 | else |
---|
| 211 | { |
---|
| 212 | i->dev.ptr = buf; |
---|
| 213 | i->dev.len = 0; |
---|
| 214 | i->dir.ptr = buf; |
---|
| 215 | i->dir.len = len; |
---|
| 216 | |
---|
| 217 | if( *buf == '[' && buf[1] == ']' ) |
---|
| 218 | i->flags = DIR_EMPTY; |
---|
| 219 | else if( *buf == '[' && buf[1] == '.' ) |
---|
| 220 | i->flags = DIR_DOTDIR; |
---|
| 221 | else if( *buf == '[' && buf[1] == '-' ) |
---|
| 222 | i->flags = DIR_DASHDIR; |
---|
| 223 | else |
---|
| 224 | i->flags = DIR_ABSDIR; |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | /* But if its rooted in any way */ |
---|
| 228 | |
---|
| 229 | if( i->dir.len == 8 && !strncmp( i->dir.ptr, "[000000]", 8 ) ) |
---|
| 230 | i->flags = DIR_ROOT; |
---|
| 231 | } |
---|
| 232 | |
---|
| 233 | /* |
---|
| 234 | * path_build() - build a filename given dir/base/suffix/member |
---|
| 235 | */ |
---|
| 236 | |
---|
| 237 | void |
---|
| 238 | path_build( |
---|
| 239 | PATHNAME *f, |
---|
| 240 | string *file, |
---|
| 241 | int binding ) |
---|
| 242 | { |
---|
| 243 | struct dirinf root, dir; |
---|
| 244 | int g; |
---|
| 245 | |
---|
| 246 | file_build1( f, file ); |
---|
| 247 | |
---|
| 248 | /* Get info on root and dir for combining. */ |
---|
| 249 | |
---|
| 250 | dir_flags( f->f_root.ptr, f->f_root.len, &root ); |
---|
| 251 | dir_flags( f->f_dir.ptr, f->f_dir.len, &dir ); |
---|
| 252 | |
---|
| 253 | /* Combine */ |
---|
| 254 | |
---|
| 255 | switch( g = grid[ root.flags ][ dir.flags ] ) |
---|
| 256 | { |
---|
| 257 | case G_DIR: |
---|
| 258 | /* take dir */ |
---|
| 259 | string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len ); |
---|
| 260 | break; |
---|
| 261 | |
---|
| 262 | case G_ROOT: |
---|
| 263 | /* take root */ |
---|
| 264 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
| 265 | break; |
---|
| 266 | |
---|
| 267 | case G_VAD: |
---|
| 268 | /* root's dev + abs directory */ |
---|
| 269 | string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); |
---|
| 270 | string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len ); |
---|
| 271 | break; |
---|
| 272 | |
---|
| 273 | case G_DRD: |
---|
| 274 | case G_DDD: |
---|
| 275 | /* root's dev:[dir] + rel directory */ |
---|
| 276 | string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len ); |
---|
| 277 | |
---|
| 278 | /* sanity checks: root ends with ] */ |
---|
| 279 | |
---|
| 280 | if( file->value[file->size - 1] == ']' ) |
---|
| 281 | string_pop_back( file ); |
---|
| 282 | |
---|
| 283 | /* Add . if separating two -'s */ |
---|
| 284 | |
---|
| 285 | if( g == G_DDD ) |
---|
| 286 | string_push_back( file, '.' ); |
---|
| 287 | |
---|
| 288 | /* skip [ of dir */ |
---|
| 289 | string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 ); |
---|
| 290 | break; |
---|
| 291 | |
---|
| 292 | case G_VRD: |
---|
| 293 | /* root's dev + rel directory made abs */ |
---|
| 294 | string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len ); |
---|
| 295 | string_push_back( file, '[' ); |
---|
| 296 | /* skip [. of rel dir */ |
---|
| 297 | string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 ); |
---|
| 298 | break; |
---|
| 299 | } |
---|
| 300 | |
---|
| 301 | # ifdef DEBUG |
---|
| 302 | if( DEBUG_SEARCH && ( root.flags || dir.flags ) ) |
---|
| 303 | { |
---|
| 304 | printf( "%d x %d = %d (%s)\n", root.flags, dir.flags, |
---|
| 305 | grid[ root.flags ][ dir.flags ], file->value ); |
---|
| 306 | } |
---|
| 307 | # endif |
---|
| 308 | |
---|
| 309 | /* |
---|
| 310 | * Now do the special :P modifier when no file was present. |
---|
| 311 | * (none) (none) |
---|
| 312 | * [dir1.dir2] [dir1] |
---|
| 313 | * [dir] [000000] |
---|
| 314 | * [.dir] (none) |
---|
| 315 | * [] [] |
---|
| 316 | */ |
---|
| 317 | |
---|
| 318 | if( file->value[file->size - 1] == ']' && f->parent ) |
---|
| 319 | { |
---|
| 320 | char* p = file->value + file->size; |
---|
| 321 | while( p-- > file->value ) |
---|
| 322 | { |
---|
| 323 | if( *p == '.' ) |
---|
| 324 | { |
---|
| 325 | /* If we've truncated everything and left with '[', |
---|
| 326 | return empty string. */ |
---|
| 327 | if (p == file->value + 1) |
---|
| 328 | string_truncate( file, 0 ); |
---|
| 329 | else { |
---|
| 330 | string_truncate( file, p - file->value ); |
---|
| 331 | string_push_back( file, ']' ); |
---|
| 332 | } |
---|
| 333 | break; |
---|
| 334 | } |
---|
| 335 | else if( *p == '-' ) |
---|
| 336 | { |
---|
| 337 | /* handle .- or - */ |
---|
| 338 | if( p > file->value && p[-1] == '.' ) |
---|
| 339 | --p; |
---|
| 340 | |
---|
| 341 | *p++ = ']'; |
---|
| 342 | break; |
---|
| 343 | } |
---|
| 344 | else if( *p == '[' ) |
---|
| 345 | { |
---|
| 346 | if( p[1] == ']' ) |
---|
| 347 | { |
---|
| 348 | /* CONSIDER: I don't see any use of this code. We immediately |
---|
| 349 | break, and 'p' is a local variable. */ |
---|
| 350 | p += 2; |
---|
| 351 | } |
---|
| 352 | else |
---|
| 353 | { |
---|
| 354 | string_truncate( file, p - file->value ); |
---|
| 355 | string_append( file, "[000000]" ); |
---|
| 356 | } |
---|
| 357 | break; |
---|
| 358 | } |
---|
| 359 | } |
---|
| 360 | } |
---|
| 361 | |
---|
| 362 | /* Now copy the file pieces. */ |
---|
| 363 | |
---|
| 364 | if( f->f_base.len ) |
---|
| 365 | { |
---|
| 366 | string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len ); |
---|
| 367 | } |
---|
| 368 | |
---|
| 369 | /* If there is no suffix, we append a "." onto all generated */ |
---|
| 370 | /* names. This keeps VMS from appending its own (wrong) idea */ |
---|
| 371 | /* of what the suffix should be. */ |
---|
| 372 | |
---|
| 373 | if( f->f_suffix.len ) |
---|
| 374 | { |
---|
| 375 | string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len ); |
---|
| 376 | } |
---|
| 377 | else if( binding && f->f_base.len ) |
---|
| 378 | { |
---|
| 379 | string_push_back( file, '.' ); |
---|
| 380 | } |
---|
| 381 | |
---|
| 382 | if( f->f_member.len ) |
---|
| 383 | { |
---|
| 384 | string_push_back( file, '(' ); |
---|
| 385 | string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len ); |
---|
| 386 | string_push_back( file, ')' ); |
---|
| 387 | } |
---|
| 388 | |
---|
| 389 | # ifdef DEBUG |
---|
| 390 | if( DEBUG_SEARCH ) |
---|
| 391 | printf("built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n", |
---|
| 392 | f->f_root.len, f->f_root.ptr, |
---|
| 393 | f->f_dir.len, f->f_dir.ptr, |
---|
| 394 | f->f_base.len, f->f_base.ptr, |
---|
| 395 | f->f_suffix.len, f->f_suffix.ptr, |
---|
| 396 | f->f_member.len, f->f_member.ptr, |
---|
| 397 | file->value ); |
---|
| 398 | # endif |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | /* |
---|
| 402 | * path_parent() - make a PATHNAME point to its parent dir |
---|
| 403 | */ |
---|
| 404 | |
---|
| 405 | void |
---|
| 406 | path_parent( PATHNAME *f ) |
---|
| 407 | { |
---|
| 408 | if( f->f_base.len ) |
---|
| 409 | { |
---|
| 410 | f->f_base.ptr = |
---|
| 411 | f->f_suffix.ptr = |
---|
| 412 | f->f_member.ptr = ""; |
---|
| 413 | |
---|
| 414 | f->f_base.len = |
---|
| 415 | f->f_suffix.len = |
---|
| 416 | f->f_member.len = 0; |
---|
| 417 | } |
---|
| 418 | else |
---|
| 419 | { |
---|
| 420 | f->parent = 1; |
---|
| 421 | } |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | # endif /* VMS */ |
---|