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