subr.c revision 17721
1186121Skmacy/* 2186121Skmacy * Copyright (c) 1992, Brian Berliner and Jeff Polk 3186121Skmacy * Copyright (c) 1989-1992, Brian Berliner 4186121Skmacy * 5186121Skmacy * You may distribute under the terms of the GNU General Public License as 6186121Skmacy * specified in the README file that comes with the CVS 1.4 kit. 7186121Skmacy * 8186121Skmacy * Various useful functions for the CVS support code. 9186121Skmacy */ 10186121Skmacy 11186121Skmacy#include "cvs.h" 12186121Skmacy 13186121Skmacyextern char *getlogin (); 14186121Skmacy 15186121Skmacy/* 16186121Skmacy * malloc some data and die if it fails 17186121Skmacy */ 18186121Skmacychar * 19186121Skmacyxmalloc (bytes) 20186121Skmacy size_t bytes; 21186121Skmacy{ 22186121Skmacy char *cp; 23186121Skmacy 24186121Skmacy /* Parts of CVS try to xmalloc zero bytes and then free it. Some 25186121Skmacy systems have a malloc which returns NULL for zero byte 26186121Skmacy allocations but a free which can't handle NULL, so compensate. */ 27186121Skmacy if (bytes == 0) 28186121Skmacy bytes = 1; 29186121Skmacy 30186121Skmacy cp = malloc (bytes); 31186121Skmacy if (cp == NULL) 32186121Skmacy error (1, 0, "can not allocate %lu bytes", (unsigned long) bytes); 33186121Skmacy return (cp); 34186121Skmacy} 35186121Skmacy 36186121Skmacy/* 37186121Skmacy * realloc data and die if it fails [I've always wanted to have "realloc" do 38186121Skmacy * a "malloc" if the argument is NULL, but you can't depend on it. Here, I 39186121Skmacy * can *force* it. 40186121Skmacy */ 41186121Skmacyvoid * 42186121Skmacyxrealloc (ptr, bytes) 43186121Skmacy void *ptr; 44186121Skmacy size_t bytes; 45186121Skmacy{ 46186121Skmacy char *cp; 47186121Skmacy 48186121Skmacy if (!ptr) 49186121Skmacy cp = malloc (bytes); 50186121Skmacy else 51186121Skmacy cp = realloc (ptr, bytes); 52186121Skmacy 53186121Skmacy if (cp == NULL) 54186121Skmacy error (1, 0, "can not reallocate %lu bytes", (unsigned long) bytes); 55186121Skmacy return (cp); 56186121Skmacy} 57186121Skmacy 58186121Skmacy/* 59186121Skmacy * Duplicate a string, calling xmalloc to allocate some dynamic space 60186121Skmacy */ 61186121Skmacychar * 62186121Skmacyxstrdup (str) 63186121Skmacy const char *str; 64186121Skmacy{ 65186121Skmacy char *s; 66186121Skmacy 67186121Skmacy if (str == NULL) 68186121Skmacy return ((char *) NULL); 69186121Skmacy s = xmalloc (strlen (str) + 1); 70186121Skmacy (void) strcpy (s, str); 71186121Skmacy return (s); 72186121Skmacy} 73186121Skmacy 74186121Skmacy/* Remove trailing newlines from STRING, destructively. */ 75186121Skmacyvoid 76186121Skmacystrip_trailing_newlines (str) 77186121Skmacy char *str; 78186121Skmacy{ 79186121Skmacy int len; 80186121Skmacy len = strlen (str) - 1; 81186121Skmacy 82186121Skmacy while (str[len] == '\n') 83186121Skmacy str[len--] = '\0'; 84186149Skmacy} 85186121Skmacy 86186121Skmacy/* 87186121Skmacy * Recover the space allocated by Find_Names() and line2argv() 88186121Skmacy */ 89186121Skmacyvoid 90186121Skmacyfree_names (pargc, argv) 91186121Skmacy int *pargc; 92186121Skmacy char **argv; 93186121Skmacy{ 94186121Skmacy register int i; 95186121Skmacy 96186121Skmacy for (i = 0; i < *pargc; i++) 97186121Skmacy { /* only do through *pargc */ 98186121Skmacy free (argv[i]); 99186121Skmacy } 100186121Skmacy *pargc = 0; /* and set it to zero when done */ 101186121Skmacy} 102186121Skmacy 103186121Skmacy/* 104186121Skmacy * Convert a line into argc/argv components and return the result in the 105186121Skmacy * arguments as passed. Use free_names() to return the memory allocated here 106186121Skmacy * back to the free pool. 107186121Skmacy */ 108186121Skmacyvoid 109186121Skmacyline2argv (pargc, argv, line) 110186121Skmacy int *pargc; 111186121Skmacy char **argv; 112186121Skmacy char *line; 113186121Skmacy{ 114186121Skmacy char *cp; 115186121Skmacy 116186121Skmacy *pargc = 0; 117186121Skmacy for (cp = strtok (line, " \t"); cp; cp = strtok ((char *) NULL, " \t")) 118186121Skmacy { 119186121Skmacy argv[*pargc] = xstrdup (cp); 120186121Skmacy (*pargc)++; 121186121Skmacy } 122186121Skmacy} 123186149Skmacy 124186121Skmacy/* 125186121Skmacy * Returns the number of dots ('.') found in an RCS revision number 126186121Skmacy */ 127186121Skmacyint 128186121Skmacynumdots (s) 129186121Skmacy const char *s; 130186121Skmacy{ 131186121Skmacy int dots = 0; 132186121Skmacy 133186121Skmacy for (; *s; s++) 134186121Skmacy { 135186121Skmacy if (*s == '.') 136186121Skmacy dots++; 137186121Skmacy } 138186121Skmacy return (dots); 139186121Skmacy} 140186121Skmacy 141186121Skmacy/* 142186121Skmacy * Get the caller's login from his uid. If the real uid is "root" try LOGNAME 143186121Skmacy * USER or getlogin(). If getlogin() and getpwuid() both fail, return 144186121Skmacy * the uid as a string. 145186121Skmacy */ 146186121Skmacychar * 147186121Skmacygetcaller () 148186121Skmacy{ 149186121Skmacy static char uidname[20]; 150186121Skmacy struct passwd *pw; 151186121Skmacy char *name; 152186121Skmacy uid_t uid; 153186121Skmacy 154186121Skmacy uid = getuid (); 155186121Skmacy if (uid == (uid_t) 0) 156186121Skmacy { 157186121Skmacy /* super-user; try getlogin() to distinguish */ 158186121Skmacy if (((name = getlogin ()) || (name = getenv("LOGNAME")) || 159186121Skmacy (name = getenv("USER"))) && *name) 160186121Skmacy return (name); 161186121Skmacy } 162186121Skmacy if ((pw = (struct passwd *) getpwuid (uid)) == NULL) 163186121Skmacy { 164186121Skmacy (void) sprintf (uidname, "uid%lu", (unsigned long) uid); 165186121Skmacy return (uidname); 166186121Skmacy } 167186121Skmacy return (pw->pw_name); 168186121Skmacy} 169186121Skmacy 170186121Skmacy#ifdef lint 171186121Skmacy#ifndef __GNUC__ 172186121Skmacy/* ARGSUSED */ 173186121Skmacytime_t 174186121Skmacyget_date (date, now) 175186121Skmacy char *date; 176186121Skmacy struct timeb *now; 177186121Skmacy{ 178186121Skmacy time_t foo = 0; 179186121Skmacy 180186121Skmacy return (foo); 181186121Skmacy} 182186121Skmacy#endif 183186121Skmacy#endif 184186121Skmacy 185186121Skmacy/* Given two revisions, find their greatest common ancestor. If the 186186121Skmacy two input revisions exist, then rcs guarantees that the gca will 187186121Skmacy exist. */ 188186121Skmacy 189186121Skmacychar * 190186121Skmacygca (rev1, rev2) 191186121Skmacy char *rev1; 192186121Skmacy char *rev2; 193{ 194 int dots; 195 char gca[PATH_MAX]; 196 char *p[2]; 197 int j[2]; 198 199 if (rev1 == NULL || rev2 == NULL) 200 { 201 error (0, 0, "sanity failure in gca"); 202 abort(); 203 } 204 205 /* walk the strings, reading the common parts. */ 206 gca[0] = '\0'; 207 p[0] = rev1; 208 p[1] = rev2; 209 do 210 { 211 int i; 212 char c[2]; 213 char *s[2]; 214 215 for (i = 0; i < 2; ++i) 216 { 217 /* swap out the dot */ 218 s[i] = strchr (p[i], '.'); 219 if (s[i] != NULL) { 220 c[i] = *s[i]; 221 } 222 223 /* read an int */ 224 j[i] = atoi (p[i]); 225 226 /* swap back the dot... */ 227 if (s[i] != NULL) { 228 *s[i] = c[i]; 229 p[i] = s[i] + 1; 230 } 231 else 232 { 233 /* or mark us at the end */ 234 p[i] = NULL; 235 } 236 237 } 238 239 /* use the lowest. */ 240 (void) sprintf (gca + strlen (gca), "%d.", 241 j[0] < j[1] ? j[0] : j[1]); 242 243 } while (j[0] == j[1] 244 && p[0] != NULL 245 && p[1] != NULL); 246 247 /* back up over that last dot. */ 248 gca[strlen(gca) - 1] = '\0'; 249 250 /* numbers differ, or we ran out of strings. we're done with the 251 common parts. */ 252 253 dots = numdots (gca); 254 if (dots == 0) 255 { 256 /* revisions differ in trunk major number. */ 257 258 char *q; 259 char *s; 260 261 s = (j[0] < j[1]) ? p[0] : p[1]; 262 263 if (s == NULL) 264 { 265 /* we only got one number. this is strange. */ 266 error (0, 0, "bad revisions %s or %s", rev1, rev2); 267 abort(); 268 } 269 else 270 { 271 /* we have a minor number. use it. */ 272 q = gca + strlen (gca); 273 274 *q++ = '.'; 275 for ( ; *s != '.' && *s != '\0'; ) 276 *q++ = *s++; 277 278 *q = '\0'; 279 } 280 } 281 else if ((dots & 1) == 0) 282 { 283 /* if we have an even number of dots, then we have a branch. 284 remove the last number in order to make it a revision. */ 285 286 char *s; 287 288 s = strrchr(gca, '.'); 289 *s = '\0'; 290 } 291 292 return (xstrdup (gca)); 293} 294 295/* 296 * Sanity checks and any required fix-up on message passed to RCS via '-m'. 297 * RCS 5.7 requires that a non-total-whitespace, non-null message be provided 298 * with '-m'. Returns the original argument or a pointer to readonly 299 * static storage. 300 */ 301char * 302make_message_rcslegal (message) 303 char *message; 304{ 305 if ((message == NULL) || (*message == '\0') || isspace (*message)) 306 { 307 char *t; 308 309 if (message) 310 for (t = message; *t; t++) 311 if (!isspace (*t)) 312 return message; 313 314 return "*** empty log message ***\n"; 315 } 316 317 return message; 318} 319