157676Sbostic /*- 257676Sbostic * Copyright (c) 1992 The Regents of the University of California. 357676Sbostic * All rights reserved. 457676Sbostic * 557676Sbostic * This code is derived from software contributed to Berkeley by 657676Sbostic * Rodney Ruddock of the University of Guelph. 757676Sbostic * 857676Sbostic * %sccs.include.redist.c% 957676Sbostic */ 1057676Sbostic 1157676Sbostic #ifndef lint 12*57710Sbostic static char sccsid[] = "@(#)address.c 5.2 (Berkeley) 01/23/93"; 1357676Sbostic #endif /* not lint */ 1457676Sbostic 15*57710Sbostic #include <sys/types.h> 16*57710Sbostic 17*57710Sbostic #include <db.h> 18*57710Sbostic #include <regex.h> 19*57710Sbostic #include <setjmp.h> 20*57710Sbostic #include <stdio.h> 21*57710Sbostic #include <string.h> 22*57710Sbostic 2357676Sbostic #include "ed.h" 24*57710Sbostic #include "extern.h" 2557676Sbostic 2657676Sbostic /* 2757676Sbostic * Make sure that address one comes before address two in the buffer 2857676Sbostic */ 2957676Sbostic 3057676Sbostic int 3157676Sbostic address_check(one, two) 32*57710Sbostic LINE *one, *two; 3357676Sbostic { 34*57710Sbostic LINE *l_cl; 3557676Sbostic 36*57710Sbostic for (l_cl = one; l_cl != NULL; l_cl = l_cl->below) 37*57710Sbostic if (l_cl == two) 38*57710Sbostic return (0); 39*57710Sbostic return (-1); 40*57710Sbostic } 4157676Sbostic 4257676Sbostic /* 4357676Sbostic * convert a number given by the user into variable 4457676Sbostic */ 4557676Sbostic int 4657676Sbostic dig_num_conv(inputt, errnum) 47*57710Sbostic FILE *inputt; 48*57710Sbostic int *errnum; 4957676Sbostic { 50*57710Sbostic int l_line = 0; 5157676Sbostic 52*57710Sbostic l_line = ss - '0'; 53*57710Sbostic while ((ss = getc(inputt)) != EOF) { 54*57710Sbostic if ((ss < '0') || (ss > '9')) 55*57710Sbostic break; 56*57710Sbostic l_line = (l_line * 10) + (ss - '0'); 57*57710Sbostic } 58*57710Sbostic *errnum = 0; 59*57710Sbostic ungetc(ss, inputt); 60*57710Sbostic return (l_line); 6157676Sbostic } 6257676Sbostic 6357676Sbostic /* 6457676Sbostic * Convert a numeric address into a LINE address (more useful for ed) 6557676Sbostic */ 66*57710Sbostic LINE * 67*57710Sbostic num_to_address(num, errnum) 68*57710Sbostic int num, *errnum; 6957676Sbostic { 70*57710Sbostic int l_line = 1; 71*57710Sbostic LINE *temp1; 7257676Sbostic 73*57710Sbostic for (temp1 = top; temp1->below != NULL; temp1 = temp1->below) { 74*57710Sbostic /* find the matching line number in the buffer */ 75*57710Sbostic if (l_line >= num) 76*57710Sbostic break; 77*57710Sbostic l_line++; 78*57710Sbostic } 7957676Sbostic 80*57710Sbostic if (l_line < num) { 81*57710Sbostic /* the number was wacko */ 82*57710Sbostic *errnum = -1; 83*57710Sbostic strcpy(help_msg, "bad line number"); 84*57710Sbostic return (NULL); 85*57710Sbostic } else 86*57710Sbostic if (num == 0) /* special case */ 87*57710Sbostic return (NULL); 88*57710Sbostic else 89*57710Sbostic return (temp1); 90*57710Sbostic } 9157676Sbostic 9257676Sbostic 9357676Sbostic /* 94*57710Sbostic * Figure out what the addresses are spec'd by the user. Note for backward 95*57710Sbostic * compatability the most recent addresses in a chain are used by the commands 96*57710Sbostic * (i.e. 3,5,17,22d deletes lines 17 to 22 inclusive. The two leading addresses 97*57710Sbostic * 3 and 5 are dropped as cmd_loop rolls through here the extra times). Hence, 98*57710Sbostic * the code may look a little wierder than it should. The variable l_order is 99*57710Sbostic * used to control for legally constructed addresses as described in ed(1). So, 100*57710Sbostic * "$-21" and "/RE/++++" are leagal but /RE/-$ is not. 10157676Sbostic */ 102*57710Sbostic LINE * 103*57710Sbostic address_conv(tempp, inputt, errnum) 104*57710Sbostic LINE *tempp; 105*57710Sbostic FILE *inputt; 106*57710Sbostic int *errnum; 10757676Sbostic { 108*57710Sbostic LINE *l_dot; 109*57710Sbostic int l_last, l_cnt, l_num, l_order, l_pass_flag; 11057676Sbostic 111*57710Sbostic l_dot = NULL; 112*57710Sbostic l_order = 0; 113*57710Sbostic l_pass_flag = 0; 114*57710Sbostic address_flag = 0; 11557676Sbostic 116*57710Sbostic l_last = ss; 117*57710Sbostic if (tempp == NULL) 118*57710Sbostic l_dot = current; 119*57710Sbostic else 120*57710Sbostic l_dot = tempp; 12157676Sbostic 122*57710Sbostic while ((ss = getc(inputt)) != EOF) { 123*57710Sbostic switch (ss) { 124*57710Sbostic case '0': case '1': case '2': case '3': case '4': 125*57710Sbostic case '5': case '6': case '7': case '8': case '9': 126*57710Sbostic if (l_order == (l_order | 4)) { 127*57710Sbostic *errnum = -1; 128*57710Sbostic strcpy(help_msg, "malformed address"); 129*57710Sbostic return (NULL); 130*57710Sbostic } 131*57710Sbostic l_order |= 1; 132*57710Sbostic l_num = dig_num_conv(inputt, errnum); 133*57710Sbostic /* 134*57710Sbostic * " " (<space>), historically, gets counted as a "+" 135*57710Sbostic * if it's between two 'addable' address forms. Goofy, 136*57710Sbostic * but it makes it compatible for those strange old 137*57710Sbostic * scripts (or users?) 138*57710Sbostic */ 139*57710Sbostic if ((l_last == '+') || 140*57710Sbostic ((l_last == ' ') && l_pass_flag)) { 141*57710Sbostic if (l_last == ' ') 142*57710Sbostic l_num++; 143*57710Sbostic for (l_cnt = 0; l_cnt < l_num - 1; l_cnt++) { 144*57710Sbostic if (l_dot == NULL) { 145*57710Sbostic *errnum = -1; 146*57710Sbostic return (NULL); 147*57710Sbostic } 148*57710Sbostic l_dot = l_dot->below; 149*57710Sbostic } 150*57710Sbostic } else 151*57710Sbostic if ((l_last == '-') || (l_last == '^')) { 152*57710Sbostic for (l_cnt = l_num - 1; 153*57710Sbostic l_cnt > 0; l_cnt--) { 154*57710Sbostic if (l_dot == NULL) { 155*57710Sbostic *errnum = -1; 156*57710Sbostic return (NULL); 157*57710Sbostic } 158*57710Sbostic l_dot = l_dot->above; 159*57710Sbostic } 160*57710Sbostic } else 161*57710Sbostic l_dot = num_to_address(l_num, errnum); 162*57710Sbostic if (*errnum < 0) 163*57710Sbostic return (NULL); 164*57710Sbostic l_pass_flag = 1; 165*57710Sbostic break; 166*57710Sbostic case '\'': 167*57710Sbostic case '$': 168*57710Sbostic case '?': 169*57710Sbostic case '/': 170*57710Sbostic case '.': 171*57710Sbostic if (l_order != 0) { 172*57710Sbostic *errnum = -1; 173*57710Sbostic strcpy(help_msg, "malformed address"); 174*57710Sbostic return (NULL); 175*57710Sbostic } 176*57710Sbostic l_order = 4; 177*57710Sbostic switch (ss) { 178*57710Sbostic case '\'': 179*57710Sbostic l_dot = get_mark(errnum); 180*57710Sbostic break; 181*57710Sbostic case '$': 182*57710Sbostic l_dot = bottom; /* set to bottom */ 183*57710Sbostic break; 184*57710Sbostic case '?': 185*57710Sbostic l_dot = search_r(inputt, errnum); 186*57710Sbostic break; 187*57710Sbostic case '/': 188*57710Sbostic l_dot = search(inputt, errnum); 189*57710Sbostic break; 190*57710Sbostic case '.': 191*57710Sbostic l_dot = current; 192*57710Sbostic break; 193*57710Sbostic } 194*57710Sbostic break; 195*57710Sbostic case '-': 196*57710Sbostic case '^': 197*57710Sbostic case '+': 198*57710Sbostic l_order = 2; 199*57710Sbostic if (ss == '+') { 200*57710Sbostic l_dot = l_dot->below; 201*57710Sbostic if (l_dot == NULL) { 202*57710Sbostic strcpy(help_msg, "at end of buffer"); 203*57710Sbostic *errnum = -1; 204*57710Sbostic return (NULL); 205*57710Sbostic } 206*57710Sbostic } else { 207*57710Sbostic l_dot = l_dot->above; 208*57710Sbostic if (l_dot == NULL) { 209*57710Sbostic strcpy(help_msg, "at top of buffer"); 210*57710Sbostic *errnum = -1; 211*57710Sbostic return (NULL); 212*57710Sbostic } 213*57710Sbostic } 214*57710Sbostic break; 215*57710Sbostic case ' ': 216*57710Sbostic break; /* ignore here, but see comment above */ 217*57710Sbostic default: 218*57710Sbostic ungetc(ss, inputt); 219*57710Sbostic return (l_dot); 220*57710Sbostic break; 221*57710Sbostic } 22257676Sbostic 223*57710Sbostic if (*errnum < 0) 224*57710Sbostic break; /* from the while-loop */ 225*57710Sbostic l_last = ss; 226*57710Sbostic } 22757676Sbostic 228*57710Sbostic if (ss == EOF) 229*57710Sbostic return (l_dot); 230*57710Sbostic *errnum = -1; 231*57710Sbostic return (NULL); 232*57710Sbostic } 233