1 1.1 cgd /* 2 1.4 perry * Copyright (c) 1983, 1993 3 1.4 perry * The Regents of the University of California. All rights reserved. 4 1.1 cgd * 5 1.1 cgd * This code is derived from software contributed to Berkeley by 6 1.1 cgd * Asa Romberger and Jerry Berkman. 7 1.1 cgd * 8 1.1 cgd * Redistribution and use in source and binary forms, with or without 9 1.1 cgd * modification, are permitted provided that the following conditions 10 1.1 cgd * are met: 11 1.1 cgd * 1. Redistributions of source code must retain the above copyright 12 1.1 cgd * notice, this list of conditions and the following disclaimer. 13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer in the 15 1.1 cgd * documentation and/or other materials provided with the distribution. 16 1.10 agc * 3. Neither the name of the University nor the names of its contributors 17 1.1 cgd * may be used to endorse or promote products derived from this software 18 1.1 cgd * without specific prior written permission. 19 1.1 cgd * 20 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 cgd * SUCH DAMAGE. 31 1.1 cgd */ 32 1.1 cgd 33 1.5 lukem #include <sys/cdefs.h> 34 1.1 cgd #ifndef lint 35 1.13 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 36 1.13 lukem The Regents of the University of California. All rights reserved."); 37 1.1 cgd #endif /* not lint */ 38 1.1 cgd 39 1.1 cgd #ifndef lint 40 1.5 lukem #if 0 41 1.5 lukem static char sccsid[] = "from: @(#)fsplit.c 8.1 (Berkeley) 6/6/93"; 42 1.6 wsanchez #else 43 1.30 christos __RCSID("$NetBSD: fsplit.c,v 1.30 2015/06/16 22:54:10 christos Exp $"); 44 1.5 lukem #endif 45 1.1 cgd #endif /* not lint */ 46 1.1 cgd 47 1.5 lukem #include <sys/types.h> 48 1.5 lukem #include <sys/stat.h> 49 1.5 lukem 50 1.24 dholland #include <assert.h> 51 1.1 cgd #include <ctype.h> 52 1.15 dholland #include <err.h> 53 1.15 dholland #include <stdbool.h> 54 1.1 cgd #include <stdio.h> 55 1.8 matt #include <stdlib.h> 56 1.3 cgd #include <string.h> 57 1.5 lukem #include <unistd.h> 58 1.1 cgd 59 1.1 cgd /* 60 1.1 cgd * usage: fsplit [-e efile] ... [file] 61 1.1 cgd * 62 1.1 cgd * split single file containing source for several fortran programs 63 1.1 cgd * and/or subprograms into files each containing one 64 1.1 cgd * subprogram unit. 65 1.1 cgd * each separate file will be named using the corresponding subroutine, 66 1.1 cgd * function, block data or program name if one is found; otherwise 67 1.1 cgd * the name will be of the form mainNNN.f or blkdtaNNN.f . 68 1.1 cgd * If a file of that name exists, it is saved in a name of the 69 1.1 cgd * form zzz000.f . 70 1.1 cgd * If -e option is used, then only those subprograms named in the -e 71 1.1 cgd * option are split off; e.g.: 72 1.1 cgd * fsplit -esub1 -e sub2 prog.f 73 1.17 dholland * isolates sub1 and sub2 in sub1.f and sub2.f. The space 74 1.1 cgd * after -e is optional. 75 1.1 cgd * 76 1.1 cgd * Modified Feb., 1983 by Jerry Berkman, Computing Services, U.C. Berkeley. 77 1.1 cgd * - added comments 78 1.1 cgd * - more function types: double complex, character*(*), etc. 79 1.1 cgd * - fixed minor bugs 80 1.1 cgd * - instead of all unnamed going into zNNN.f, put mains in 81 1.1 cgd * mainNNN.f, block datas in blkdtaNNN.f, dups in zzzNNN.f . 82 1.1 cgd */ 83 1.1 cgd 84 1.1 cgd #define BSZ 512 85 1.16 dholland static char buf[BSZ]; 86 1.16 dholland static FILE *ifp; 87 1.16 dholland 88 1.17 dholland static char x[] = "zzz000.f"; 89 1.17 dholland static char mainp[] = "main000.f"; 90 1.17 dholland static char blkp[] = "blkdta000.f"; 91 1.16 dholland 92 1.28 joerg __dead static void badparms(void); 93 1.16 dholland static const char *functs(const char *); 94 1.27 roy static int get_line(void); 95 1.16 dholland static void get_name(char *, int); 96 1.16 dholland static int lend(void); 97 1.16 dholland static int lname(char *, size_t); 98 1.16 dholland static const char *look(const char *, const char *); 99 1.16 dholland static int saveit(const char *); 100 1.23 dholland static int scan_name(char *, size_t, const char *); 101 1.16 dholland static const char *skiplab(const char *); 102 1.19 dholland static const char *skipws(const char *); 103 1.16 dholland 104 1.21 dholland struct extract { 105 1.21 dholland bool found; 106 1.21 dholland char *name; 107 1.21 dholland }; 108 1.21 dholland 109 1.22 dholland #define MAXEXTONLY 100 110 1.22 dholland static struct extract extonly[MAXEXTONLY]; 111 1.22 dholland static int numextonly = 0; 112 1.1 cgd 113 1.5 lukem int 114 1.14 dholland main(int argc, char **argv) 115 1.1 cgd { 116 1.5 lukem FILE *ofp; /* output file */ 117 1.5 lukem int rv; /* 1 if got card in output file, 0 otherwise */ 118 1.5 lukem int nflag; /* 1 if got name of subprog., 0 otherwise */ 119 1.22 dholland int retval, i, ch; 120 1.26 dholland char name[80]; 121 1.1 cgd 122 1.22 dholland while ((ch = getopt(argc, argv, "e:")) != -1) { 123 1.22 dholland switch (ch) { 124 1.22 dholland case 'e': 125 1.22 dholland if (numextonly >= MAXEXTONLY) { 126 1.22 dholland errx(1, "Too many -e options"); 127 1.17 dholland } 128 1.22 dholland extonly[numextonly].name = optarg; 129 1.22 dholland extonly[numextonly].found = false; 130 1.22 dholland numextonly++; 131 1.22 dholland break; 132 1.22 dholland default: 133 1.22 dholland badparms(); 134 1.22 dholland break; 135 1.1 cgd } 136 1.1 cgd } 137 1.1 cgd 138 1.17 dholland if (argc > 2) { 139 1.1 cgd badparms(); 140 1.17 dholland } else if (argc == 2) { 141 1.1 cgd if ((ifp = fopen(argv[1], "r")) == NULL) { 142 1.15 dholland err(1, "%s", argv[1]); 143 1.1 cgd } 144 1.17 dholland } else { 145 1.1 cgd ifp = stdin; 146 1.1 cgd } 147 1.17 dholland 148 1.17 dholland for (;;) { 149 1.17 dholland /* 150 1.17 dholland * Look for a temp file that doesn't correspond to an 151 1.17 dholland * existing file. 152 1.17 dholland */ 153 1.17 dholland 154 1.17 dholland get_name(x, 3); 155 1.17 dholland ofp = fopen(x, "w"); 156 1.17 dholland if (ofp == NULL) { 157 1.17 dholland err(1, "%s", x); 158 1.17 dholland } 159 1.17 dholland nflag = 0; 160 1.17 dholland rv = 0; 161 1.27 roy while (get_line() > 0) { 162 1.17 dholland rv = 1; 163 1.17 dholland fprintf(ofp, "%s", buf); 164 1.17 dholland /* look for an 'end' statement */ 165 1.17 dholland if (lend()) { 166 1.17 dholland break; 167 1.1 cgd } 168 1.17 dholland /* if no name yet, try and find one */ 169 1.17 dholland if (nflag == 0) { 170 1.17 dholland nflag = lname(name, sizeof(name)); 171 1.17 dholland } 172 1.17 dholland } 173 1.17 dholland fclose(ofp); 174 1.17 dholland if (rv == 0) { 175 1.17 dholland /* no lines in file, forget the file */ 176 1.17 dholland unlink(x); 177 1.17 dholland retval = 0; 178 1.20 dholland for (i = 0; i < numextonly; i++) { 179 1.21 dholland if (!extonly[i].found) { 180 1.17 dholland retval = 1; 181 1.21 dholland warnx("%s not found", extonly[i].name); 182 1.17 dholland } 183 1.17 dholland } 184 1.17 dholland exit(retval); 185 1.17 dholland } 186 1.17 dholland if (nflag) { 187 1.17 dholland /* rename the file */ 188 1.17 dholland if (saveit(name)) { 189 1.18 dholland struct stat sbuf; 190 1.18 dholland 191 1.17 dholland if (stat(name, &sbuf) < 0) { 192 1.24 dholland if (rename(x, name) < 0) { 193 1.24 dholland warn("%s: rename", x); 194 1.24 dholland printf("%s left in %s\n", 195 1.24 dholland name, x); 196 1.24 dholland } else { 197 1.24 dholland printf("%s\n", name); 198 1.24 dholland } 199 1.17 dholland continue; 200 1.17 dholland } else if (strcmp(name, x) == 0) { 201 1.17 dholland printf("%s\n", x); 202 1.17 dholland continue; 203 1.17 dholland } 204 1.17 dholland printf("%s already exists, put in %s\n", 205 1.17 dholland name, x); 206 1.17 dholland continue; 207 1.17 dholland } else { 208 1.1 cgd unlink(x); 209 1.1 cgd continue; 210 1.1 cgd } 211 1.17 dholland } 212 1.20 dholland if (numextonly == 0) { 213 1.17 dholland printf("%s\n", x); 214 1.17 dholland } else { 215 1.1 cgd unlink(x); 216 1.17 dholland } 217 1.1 cgd } 218 1.1 cgd } 219 1.1 cgd 220 1.16 dholland static void 221 1.14 dholland badparms(void) 222 1.1 cgd { 223 1.15 dholland err(1, "Usage: fsplit [-e efile] ... [file]"); 224 1.1 cgd } 225 1.1 cgd 226 1.16 dholland static int 227 1.16 dholland saveit(const char *name) 228 1.1 cgd { 229 1.1 cgd int i; 230 1.17 dholland char fname[50]; 231 1.24 dholland size_t fnamelen; 232 1.1 cgd 233 1.20 dholland if (numextonly == 0) { 234 1.17 dholland return 1; 235 1.17 dholland } 236 1.24 dholland strlcpy(fname, name, sizeof(fname)); 237 1.24 dholland fnamelen = strlen(fname); 238 1.29 riastrad /* Guaranteed by scan_name. */ 239 1.24 dholland assert(fnamelen > 2); 240 1.29 riastrad assert(fname[fnamelen-2] == '.'); 241 1.29 riastrad assert(fname[fnamelen-1] == 'f'); 242 1.24 dholland fname[fnamelen-2] = '\0'; 243 1.24 dholland 244 1.25 dholland for (i = 0; i < numextonly; i++) { 245 1.21 dholland if (strcmp(fname, extonly[i].name) == 0) { 246 1.21 dholland extonly[i].found = true; 247 1.17 dholland return 1; 248 1.1 cgd } 249 1.17 dholland } 250 1.17 dholland return 0; 251 1.1 cgd } 252 1.1 cgd 253 1.16 dholland static void 254 1.14 dholland get_name(char *name, int letters) 255 1.1 cgd { 256 1.18 dholland struct stat sbuf; 257 1.5 lukem char *ptr; 258 1.1 cgd 259 1.1 cgd while (stat(name, &sbuf) >= 0) { 260 1.1 cgd for (ptr = name + letters + 2; ptr >= name + letters; ptr--) { 261 1.1 cgd (*ptr)++; 262 1.1 cgd if (*ptr <= '9') 263 1.1 cgd break; 264 1.1 cgd *ptr = '0'; 265 1.1 cgd } 266 1.17 dholland if (ptr < name + letters) { 267 1.30 christos errx(1, "Ran out of file names."); 268 1.1 cgd } 269 1.1 cgd } 270 1.1 cgd } 271 1.1 cgd 272 1.16 dholland static int 273 1.27 roy get_line(void) 274 1.1 cgd { 275 1.5 lukem char *ptr; 276 1.1 cgd 277 1.1 cgd for (ptr = buf; ptr < &buf[BSZ]; ) { 278 1.1 cgd *ptr = getc(ifp); 279 1.1 cgd if (feof(ifp)) 280 1.17 dholland return -1; 281 1.1 cgd if (*ptr++ == '\n') { 282 1.16 dholland *ptr = '\0'; 283 1.17 dholland return 1; 284 1.1 cgd } 285 1.1 cgd } 286 1.17 dholland while (getc(ifp) != '\n' && feof(ifp) == 0) { 287 1.17 dholland /* nothing */ 288 1.17 dholland } 289 1.15 dholland warnx("Line truncated to %d characters.", BSZ); 290 1.17 dholland return 1; 291 1.1 cgd } 292 1.1 cgd 293 1.17 dholland /* 294 1.17 dholland * Return 1 for 'end' alone on card (up to col. 72), 0 otherwise. 295 1.17 dholland */ 296 1.16 dholland static int 297 1.14 dholland lend(void) 298 1.1 cgd { 299 1.16 dholland const char *p; 300 1.1 cgd 301 1.17 dholland if ((p = skiplab(buf)) == 0) { 302 1.17 dholland return 0; 303 1.17 dholland } 304 1.19 dholland p = skipws(p); 305 1.17 dholland if (*p != 'e' && *p != 'E') { 306 1.17 dholland return 0; 307 1.17 dholland } 308 1.1 cgd p++; 309 1.19 dholland p = skipws(p); 310 1.17 dholland if (*p != 'n' && *p != 'N') { 311 1.17 dholland return 0; 312 1.17 dholland } 313 1.1 cgd p++; 314 1.19 dholland p = skipws(p); 315 1.17 dholland if (*p != 'd' && *p != 'D') { 316 1.17 dholland return 0; 317 1.17 dholland } 318 1.1 cgd p++; 319 1.19 dholland p = skipws(p); 320 1.17 dholland if (p - buf >= 72 || *p == '\n') { 321 1.17 dholland return 1; 322 1.17 dholland } 323 1.17 dholland return 0; 324 1.1 cgd } 325 1.1 cgd 326 1.17 dholland /* 327 1.17 dholland * check for keywords for subprograms 328 1.17 dholland * return 0 if comment card, 1 if found 329 1.17 dholland * name and put in arg string. invent name for unnamed 330 1.17 dholland * block datas and main programs. 331 1.17 dholland */ 332 1.16 dholland static int 333 1.14 dholland lname(char *s, size_t l) 334 1.1 cgd { 335 1.17 dholland #define LINESIZE 80 336 1.16 dholland const char *ptr, *p; 337 1.17 dholland char line[LINESIZE], *iptr = line; 338 1.1 cgd 339 1.1 cgd /* first check for comment cards */ 340 1.17 dholland if (buf[0] == 'c' || buf[0] == 'C' || buf[0] == '*') { 341 1.17 dholland return 0; 342 1.17 dholland } 343 1.24 dholland ptr = skipws(buf); 344 1.17 dholland if (*ptr == '\n') { 345 1.17 dholland return 0; 346 1.17 dholland } 347 1.1 cgd 348 1.1 cgd ptr = skiplab(buf); 349 1.17 dholland if (ptr == NULL) { 350 1.17 dholland return 0; 351 1.17 dholland } 352 1.1 cgd 353 1.1 cgd /* copy to buffer and converting to lower case */ 354 1.1 cgd p = ptr; 355 1.1 cgd while (*p && p <= &buf[71] ) { 356 1.11 dsl *iptr = tolower((unsigned char)*p); 357 1.1 cgd iptr++; 358 1.1 cgd p++; 359 1.1 cgd } 360 1.1 cgd *iptr = '\n'; 361 1.1 cgd 362 1.16 dholland if ((ptr = look(line, "subroutine")) != NULL || 363 1.16 dholland (ptr = look(line, "function")) != NULL || 364 1.16 dholland (ptr = functs(line)) != NULL) { 365 1.23 dholland if (scan_name(s, l, ptr)) { 366 1.17 dholland return 1; 367 1.17 dholland } 368 1.9 itojun strlcpy(s, x, l); 369 1.17 dholland } else if ((ptr = look(line, "program")) != NULL) { 370 1.23 dholland if (scan_name(s, l, ptr)) { 371 1.17 dholland return 1; 372 1.17 dholland } 373 1.9 itojun get_name(mainp, 4); 374 1.9 itojun strlcpy(s, mainp, l); 375 1.17 dholland } else if ((ptr = look(line, "blockdata")) != NULL) { 376 1.23 dholland if (scan_name(s, l, ptr)) { 377 1.17 dholland return 1; 378 1.17 dholland } 379 1.17 dholland get_name(blkp, 6); 380 1.9 itojun strlcpy(s, blkp, l); 381 1.17 dholland } else if ((ptr = functs(line)) != NULL) { 382 1.23 dholland if (scan_name(s, l, ptr)) { 383 1.17 dholland return 1; 384 1.17 dholland } 385 1.9 itojun strlcpy(s, x, l); 386 1.1 cgd } else { 387 1.9 itojun get_name(mainp, 4); 388 1.9 itojun strlcpy(s, mainp, l); 389 1.1 cgd } 390 1.17 dholland return 1; 391 1.1 cgd } 392 1.1 cgd 393 1.16 dholland static int 394 1.23 dholland scan_name(char *s, size_t smax, const char *ptr) 395 1.1 cgd { 396 1.1 cgd char *sptr; 397 1.23 dholland size_t sptrmax; 398 1.1 cgd 399 1.1 cgd /* scan off the name */ 400 1.19 dholland ptr = skipws(ptr); 401 1.1 cgd sptr = s; 402 1.23 dholland sptrmax = smax - 3; 403 1.1 cgd while (*ptr != '(' && *ptr != '\n') { 404 1.26 dholland if (*ptr != ' ' && *ptr != '\t' && *ptr != '/') { 405 1.23 dholland if (sptrmax == 0) { 406 1.23 dholland /* Not sure this is the right thing, so warn */ 407 1.23 dholland warnx("Output name too long; truncated"); 408 1.23 dholland break; 409 1.23 dholland } 410 1.1 cgd *sptr++ = *ptr; 411 1.23 dholland sptrmax--; 412 1.23 dholland } 413 1.1 cgd ptr++; 414 1.1 cgd } 415 1.1 cgd 416 1.17 dholland if (sptr == s) { 417 1.17 dholland return 0; 418 1.17 dholland } 419 1.1 cgd 420 1.1 cgd *sptr++ = '.'; 421 1.1 cgd *sptr++ = 'f'; 422 1.16 dholland *sptr++ = '\0'; 423 1.17 dholland return 1; 424 1.1 cgd } 425 1.1 cgd 426 1.17 dholland /* 427 1.17 dholland * look for typed functions such as: real*8 function, 428 1.17 dholland * character*16 function, character*(*) function 429 1.17 dholland */ 430 1.16 dholland static const char * 431 1.16 dholland functs(const char *p) 432 1.1 cgd { 433 1.16 dholland const char *ptr; 434 1.1 cgd 435 1.17 dholland if ((ptr = look(p, "character")) != NULL || 436 1.17 dholland (ptr = look(p, "logical")) != NULL || 437 1.17 dholland (ptr = look(p, "real")) != NULL || 438 1.17 dholland (ptr = look(p, "integer")) != NULL || 439 1.17 dholland (ptr = look(p, "doubleprecision")) != NULL || 440 1.17 dholland (ptr = look(p, "complex")) != NULL || 441 1.17 dholland (ptr = look(p, "doublecomplex")) != NULL) { 442 1.17 dholland while (*ptr == ' ' || *ptr == '\t' || *ptr == '*' 443 1.17 dholland || (*ptr >= '0' && *ptr <= '9') 444 1.17 dholland || *ptr == '(' || *ptr == ')') { 445 1.17 dholland ptr++; 446 1.17 dholland } 447 1.17 dholland ptr = look(ptr, "function"); 448 1.17 dholland return ptr; 449 1.1 cgd } 450 1.17 dholland else { 451 1.16 dholland return NULL; 452 1.17 dholland } 453 1.1 cgd } 454 1.1 cgd 455 1.17 dholland /* 456 1.17 dholland * if first 6 col. blank, return ptr to col. 7, 457 1.17 dholland * if blanks and then tab, return ptr after tab, 458 1.17 dholland * else return NULL (labelled statement, comment or continuation) 459 1.17 dholland */ 460 1.16 dholland static const char * 461 1.16 dholland skiplab(const char *p) 462 1.1 cgd { 463 1.16 dholland const char *ptr; 464 1.1 cgd 465 1.1 cgd for (ptr = p; ptr < &p[6]; ptr++) { 466 1.1 cgd if (*ptr == ' ') 467 1.1 cgd continue; 468 1.1 cgd if (*ptr == '\t') { 469 1.1 cgd ptr++; 470 1.1 cgd break; 471 1.1 cgd } 472 1.16 dholland return NULL; 473 1.1 cgd } 474 1.17 dholland return ptr; 475 1.1 cgd } 476 1.1 cgd 477 1.17 dholland /* 478 1.17 dholland * return NULL if m doesn't match initial part of s; 479 1.17 dholland * otherwise return ptr to next char after m in s 480 1.17 dholland */ 481 1.16 dholland static const char * 482 1.16 dholland look(const char *s, const char *m) 483 1.1 cgd { 484 1.16 dholland const char *sp, *mp; 485 1.1 cgd 486 1.1 cgd sp = s; mp = m; 487 1.1 cgd while (*mp) { 488 1.19 dholland sp = skipws(sp); 489 1.1 cgd if (*sp++ != *mp++) 490 1.16 dholland return NULL; 491 1.1 cgd } 492 1.17 dholland return sp; 493 1.1 cgd } 494 1.19 dholland 495 1.19 dholland static const char * 496 1.19 dholland skipws(const char *p) 497 1.19 dholland { 498 1.19 dholland while (*p == ' ' || *p == '\t') { 499 1.19 dholland p++; 500 1.19 dholland } 501 1.19 dholland return p; 502 1.19 dholland } 503