DriveHQ Start Menu
Cloud Drive Mapping
Folder Sync
Cloud Backup
True Drop Box
FTP/SFTP Hosting
Group Account
DriveHQ Start Menu
Online File Server
My Storage
|
Manage Shares
|
Publishes
|
Drop Boxes
|
Group Account
WebDAV Drive Mapping
Cloud Drive Home
|
WebDAV Guide
|
Drive Mapping Tool
|
Drive Mapping URL
Complete Data Backup
Backup Guide
|
Online Backup Tool
|
Cloud-to-Cloud Backup
FTP, Email & Web Service
FTP Home
|
FTP Hosting FAQ
|
Email Hosting
|
EmailManager
|
Web Hosting
Help & Resources
About
|
Enterprise Service
|
Partnership
|
Comparisons
|
Support
Quick Links
Security and Privacy
Download Software
Service Manual
Use Cases
Group Account
Online Help
Blog
Contact
Cloud Surveillance
Sign Up
Login
Features
Business Features
Online File Server
FTP Hosting
Cloud Drive Mapping
Cloud File Backup
Email Backup & Hosting
Cloud File Sharing
Folder Synchronization
Group Management
True Drop Box
Full-text Search
AD Integration/SSO
Mobile Access
IP Camera & DVR Solution
More...
Personal Features
Personal Cloud Drive
Backup All Devices
Mobile APPs
Personal Web Hosting
Sub-Account (for Kids)
Home/PC/Kids Monitoring
More...
Software
DriveHQ Drive Mapping Tool
DriveHQ FileManager
DriveHQ Online Backup
DriveHQ Mobile Apps
Pricing
Business Plans & Pricing
Personal Plans & Pricing
Price Comparison with Others
Feature Comparison with Others
Install Mobile App
Sign up
Creating account...
Invalid character in username! Only 0-9, a-z, A-Z, _, -, . allowed.
Username is required!
Invalid email address!
E-mail is required!
Password is required!
Password is invalid!
Password and confirmation do not match.
Confirm password is required!
I accept
Membership Agreement
Please read the Membership Agreement and check "I accept"!
Free Quick Sign-up
Sign-up Page
Log in
Signing in...
Username or e-mail address is required!
Password is required!
Keep me logged in
Quick Login
Forgot Password
Up
Upload
Download
Share
Publish
New Folder
New File
Copy
Cut
Delete
Paste
Rate
Upgrade
Rotate
Effect
Edit
Slide
History
/* * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ /* * expand.c - expand a buffer, given variable values * * External routines: * * var_expand() - variable-expand input string into list of strings * * Internal routines: * * var_edit_parse() - parse : modifiers into PATHNAME structure * var_edit_file() - copy input target name to output, modifying filename * var_edit_shift() - do upshift/downshift mods * * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X) * 04/13/94 (seiwald) - added shorthand L0 for null list pointer * 01/20/00 (seiwald) - Upgraded from K&R to ANSI C * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval * 01/13/01 (seiwald) - :UDJE work on non-filename strings * 02/19/01 (seiwald) - make $($(var):J=x) join multiple values of var * 01/25/02 (seiwald) - fixed broken $(v[1-]), by ian godin * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr() * 11/04/02 (seiwald) - const-ing for string literals * 12/30/02 (armstrong) - fix out-of-bounds access in var_expand() */ # include "jam.h" # include "lists.h" # include "variable.h" # include "expand.h" # include "pathsys.h" # include "newstr.h" typedef struct { PATHNAME f; /* :GDBSMR -- pieces */ char parent; /* :P -- go to parent directory */ char filemods; /* one of the above applied */ char downshift; /* :L -- downshift result */ char upshift; /* :U -- upshift result */ PATHPART empty; /* :E -- default for empties */ PATHPART join; /* :J -- join list with char */ } VAR_EDITS ; static void var_edit_parse( const char *mods, VAR_EDITS *edits ); static void var_edit_file( const char *in, char *out, VAR_EDITS *edits ); static void var_edit_shift( char *out, VAR_EDITS *edits ); # define MAGIC_COLON '\001' # define MAGIC_LEFT '\002' # define MAGIC_RIGHT '\003' /* * var_expand() - variable-expand input string into list of strings * * Would just copy input to output, performing variable expansion, * except that since variables can contain multiple values the result * of variable expansion may contain multiple values (a list). Properly * performs "product" operations that occur in "$(var1)xxx$(var2)" or * even "$($(var2))". * * Returns a newly created list. */ LIST * var_expand( LIST *l, const char *in, const char *end, LOL *lol, int cancopyin ) { char out_buf[ MAXSYM ]; char *out = out_buf; const char *inp = in; char *ov; /* for temp copy of variable in outbuf */ int depth; if( DEBUG_VAREXP ) printf( "expand '%.*s'\n", end - in, in ); /* This gets alot of cases: $(<) and $(>) */ if( end - in == 4 && in[0] == '$' && in[1] == '(' && in[3] == ')' ) { switch( in[2] ) { case '1': case '<': return list_copy( l, lol_get( lol, 0 ) ); case '2': case '>': return list_copy( l, lol_get( lol, 1 ) ); } } /* Just try simple copy of in to out. */ while( in < end ) if( ( *out++ = *in++ ) == '$' && *in == '(' ) goto expand; /* No variables expanded - just add copy of input string to list. */ /* Cancopyin is an optimization: if the input was already a list */ /* item, we can use the copystr() to put it on the new list. */ /* Otherwise, we use the slower newstr(). */ *out = '\0'; if( cancopyin ) return list_new( l, inp, 1 ); else return list_new( l, out_buf, 0 ); expand: /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf $ * ^ ^ * out_buf out * * * We just copied the $ of $(...), so back up one on the output. * We now find the matching close paren, copying the variable and * modifiers between the $( and ) temporarily into out_buf, so that * we can replace :'s with MAGIC_COLON. This is necessary to avoid * being confused by modifier values that are variables containing * :'s. Ugly. */ depth = 1; out--, in++; ov = out; while( in < end && depth ) { switch( *ov++ = *in++ ) { case '(': depth++; break; case ')': depth--; break; case ':': ov[-1] = MAGIC_COLON; break; case '[': ov[-1] = MAGIC_LEFT; break; case ']': ov[-1] = MAGIC_RIGHT; break; } } /* Copied ) - back up. */ ov--; /* * Input so far (ignore blanks): * * stuff-in-outbuf $(variable) remainder * ^ ^ * in end * Output so far: * * stuff-in-outbuf variable * ^ ^ ^ * out_buf out ov * * Later we will overwrite 'variable' in out_buf, but we'll be * done with it by then. 'variable' may be a multi-element list, * so may each value for '$(variable element)', and so may 'remainder'. * Thus we produce a product of three lists. */ { LIST *variables = 0; LIST *remainder = 0; LIST *vars; /* Recursively expand variable name & rest of input */ if( out < ov ) variables = var_expand( L0, out, ov, lol, 0 ); if( in < end ) remainder = var_expand( L0, in, end, lol, 0 ); /* Now produce the result chain */ /* For each variable name */ for( vars = variables; vars; vars = list_next( vars ) ) { LIST *value, *evalue = 0; char *colon; char *bracket; char varname[ MAXSYM ]; int sub1 = 0, sub2 = -1; VAR_EDITS edits; /* Look for a : modifier in the variable name */ /* Must copy into varname so we can modify it */ strcpy( varname, vars->string ); if( colon = strchr( varname, MAGIC_COLON ) ) { *colon = '\0'; var_edit_parse( colon + 1, &edits ); } /* Look for [x-y] subscripting */ /* sub1 is x (0 default) */ /* sub2 is length (-1 means forever) */ if( bracket = strchr( varname, MAGIC_LEFT ) ) { char *dash; if( dash = strchr( bracket + 1, '-' ) ) *dash = '\0'; sub1 = atoi( bracket + 1 ) - 1; if( !dash ) sub2 = 1; else if( !dash[1] || dash[1] == MAGIC_RIGHT ) sub2 = -1; else sub2 = atoi( dash + 1 ) - sub1; *bracket = '\0'; } /* Get variable value, specially handling $(<), $(>), $(n) */ if( varname[0] == '<' && !varname[1] ) value = lol_get( lol, 0 ); else if( varname[0] == '>' && !varname[1] ) value = lol_get( lol, 1 ); else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) value = lol_get( lol, varname[0] - '1' ); else value = var_get( varname ); /* The fast path: $(x) - just copy the variable value. */ /* This is only an optimization */ if( out == out_buf && !bracket && !colon && in == end ) { l = list_copy( l, value ); continue; } /* Handle start subscript */ while( sub1 > 0 && value ) --sub1, value = list_next( value ); /* Empty w/ :E=default? */ if( !value && colon && edits.empty.ptr ) evalue = value = list_new( L0, edits.empty.ptr, 0 ); /* For each variable value */ for( ; value; value = list_next( value ) ) { LIST *rem; char *out1; /* Handle end subscript (length actually) */ if( sub2 >= 0 && --sub2 < 0 ) break; /* Apply : mods, if present */ if( colon && edits.filemods ) var_edit_file( value->string, out, &edits ); else strcpy( out, value->string ); if( colon && ( edits.upshift || edits.downshift ) ) var_edit_shift( out, &edits ); /* Handle :J=joinval */ /* If we have more values for this var, just */ /* keep appending them (with the join value) */ /* rather than creating separate LIST elements. */ if( colon && edits.join.ptr && ( list_next( value ) || list_next( vars ) ) ) { out += strlen( out ); strcpy( out, edits.join.ptr ); out += strlen( out ); continue; } /* If no remainder, append result to output chain. */ if( in == end ) { l = list_new( l, out_buf, 0 ); continue; } /* For each remainder, append the complete string */ /* to the output chain. */ /* Remember the end of the variable expansion so */ /* we can just tack on each instance of 'remainder' */ out1 = out + strlen( out ); for( rem = remainder; rem; rem = list_next( rem ) ) { strcpy( out1, rem->string ); l = list_new( l, out_buf, 0 ); } } /* Toss used empty */ if( evalue ) list_free( evalue ); } /* variables & remainder were gifts from var_expand */ /* and must be freed */ if( variables ) list_free( variables ); if( remainder) list_free( remainder ); if( DEBUG_VAREXP ) { printf( "expanded to " ); list_print( l ); printf( "\n" ); } return l; } } /* * var_edit_parse() - parse : modifiers into PATHNAME structure * * The : modifiers in a $(varname:modifier) currently support replacing * or omitting elements of a filename, and so they are parsed into a * PATHNAME structure (which contains pointers into the original string). * * Modifiers of the form "X=value" replace the component X with * the given value. Modifiers without the "=value" cause everything * but the component X to be omitted. X is one of: * * G
* D directory name * B base name * S .suffix * M (member) * R root directory - prepended to whole path * * This routine sets: * * f->f_xxx.ptr = 0 * f->f_xxx.len = 0 * -> leave the original component xxx * * f->f_xxx.ptr = string * f->f_xxx.len = strlen( string ) * -> replace component xxx with string * * f->f_xxx.ptr = "" * f->f_xxx.len = 0 * -> omit component xxx * * var_edit_file() below and path_build() obligingly follow this convention. */ static void var_edit_parse( const char *mods, VAR_EDITS *edits ) { int havezeroed = 0; memset( (char *)edits, 0, sizeof( *edits ) ); while( *mods ) { char *p; PATHPART *fp; switch( *mods++ ) { case 'L': edits->downshift = 1; continue; case 'U': edits->upshift = 1; continue; case 'P': edits->parent = edits->filemods = 1; continue; case 'E': fp = &edits->empty; goto strval; case 'J': fp = &edits->join; goto strval; case 'G': fp = &edits->f.f_grist; goto fileval; case 'R': fp = &edits->f.f_root; goto fileval; case 'D': fp = &edits->f.f_dir; goto fileval; case 'B': fp = &edits->f.f_base; goto fileval; case 'S': fp = &edits->f.f_suffix; goto fileval; case 'M': fp = &edits->f.f_member; goto fileval; default: return; /* should complain, but so what... */ } fileval: /* Handle :CHARS, where each char (without a following =) */ /* selects a particular file path element. On the first such */ /* char, we deselect all others (by setting ptr = "", len = 0) */ /* and for each char we select that element (by setting ptr = 0) */ edits->filemods = 1; if( *mods != '=' ) { int i; if( !havezeroed++ ) for( i = 0; i < 6; i++ ) { edits->f.part[ i ].len = 0; edits->f.part[ i ].ptr = ""; } fp->ptr = 0; continue; } strval: /* Handle :X=value, or :X */ if( *mods != '=' ) { fp->ptr = ""; fp->len = 0; } else if( p = strchr( mods, MAGIC_COLON ) ) { *p = 0; fp->ptr = ++mods; fp->len = p - mods; mods = p + 1; } else { fp->ptr = ++mods; fp->len = strlen( mods ); mods += fp->len; } } } /* * var_edit_file() - copy input target name to output, modifying filename */ static void var_edit_file( const char *in, char *out, VAR_EDITS *edits ) { PATHNAME pathname; /* Parse apart original filename, putting parts into "pathname" */ path_parse( in, &pathname ); /* Replace any pathname with edits->f */ if( edits->f.f_grist.ptr ) pathname.f_grist = edits->f.f_grist; if( edits->f.f_root.ptr ) pathname.f_root = edits->f.f_root; if( edits->f.f_dir.ptr ) pathname.f_dir = edits->f.f_dir; if( edits->f.f_base.ptr ) pathname.f_base = edits->f.f_base; if( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix; if( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member; /* If requested, modify pathname to point to parent */ if( edits->parent ) path_parent( &pathname ); /* Put filename back together */ path_build( &pathname, out, 0 ); } /* * var_edit_shift() - do upshift/downshift mods */ static void var_edit_shift( char *out, VAR_EDITS *edits ) { /* Handle upshifting, downshifting now */ if( edits->upshift ) { for( ; *out; ++out ) *out = toupper( *out ); } else if( edits->downshift ) { for( ; *out; ++out ) *out = tolower( *out ); } }
expand.c
Page URL
File URL
Prev
13/73
Next
Download
( 12 KB )
Note: The DriveHQ service banners will NOT be displayed if the file owner is a paid member.
Comments
Total ratings:
0
Average rating:
Not Rated
Would you like to comment?
Join DriveHQ
for a free account, or
Logon
if you are already a member.