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.4 (Berkeley) 03/01/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 if (top) { 77 for (temp1 = top; temp1->below != NULL; temp1 = temp1->below) { 78 /* find the matching line number in the buffer */ 79 if (l_line >= num) 80 break; 81 l_line++; 82 } 83 } 84 85 if ((l_line < num) || (!top)) { 86 /* the number was wacko */ 87 *errnum = -1; 88 strcpy(help_msg, "bad line number"); 89 return (NULL); 90 } else 91 if (num == 0) /* special case */ 92 return (NULL); 93 else 94 return (temp1); 95 } 96 97 98 /* 99 * Figure out what the addresses are spec'd by the user. Note for backward 100 * compatability the most recent addresses in a chain are used by the commands 101 * (i.e. 3,5,17,22d deletes lines 17 to 22 inclusive. The two leading addresses 102 * 3 and 5 are dropped as cmd_loop rolls through here the extra times). Hence, 103 * the code may look a little wierder than it should. The variable l_order is 104 * used to control for legally constructed addresses as described in ed(1). So, 105 * "$-21" and "/RE/++++" are legal but /RE/-$ is not. 106 */ 107 LINE * 108 address_conv(tempp, inputt, errnum) 109 LINE *tempp; 110 FILE *inputt; 111 int *errnum; 112 { 113 LINE *l_dot; 114 int l_last, l_cnt, l_num, l_order, l_pass_flag; 115 116 l_dot = NULL; 117 l_order = 0; 118 l_pass_flag = 0; 119 address_flag = 0; 120 121 l_last = ss; 122 if (tempp == NULL) 123 l_dot = current; 124 else 125 l_dot = tempp; 126 127 while ((ss = getc(inputt)) != EOF) { 128 switch (ss) { 129 case '0': case '1': case '2': case '3': case '4': 130 case '5': case '6': case '7': case '8': case '9': 131 if (l_order == (l_order | 4)) { 132 *errnum = -1; 133 strcpy(help_msg, "malformed address"); 134 return (NULL); 135 } 136 l_order |= 1; 137 l_num = dig_num_conv(inputt, errnum); 138 /* 139 * " " (<space>), historically, gets counted as a "+" 140 * if it's between two 'addable' address forms. Goofy, 141 * but it makes it compatible for those strange old 142 * scripts (or users?) 143 */ 144 if ((l_last == '+') || 145 ((l_last == ' ') && l_pass_flag)) { 146 if (l_last == ' ') 147 l_num++; 148 for (l_cnt = 0; l_cnt < l_num - 1; l_cnt++) { 149 if (l_dot == NULL) { 150 *errnum = -1; 151 return (NULL); 152 } 153 l_dot = l_dot->below; 154 } 155 } else 156 if ((l_last == '-') || (l_last == '^')) { 157 for (l_cnt = l_num - 1; 158 l_cnt > 0; l_cnt--) { 159 if (l_dot == NULL) { 160 *errnum = -1; 161 return (NULL); 162 } 163 l_dot = l_dot->above; 164 } 165 } else 166 l_dot = num_to_address(l_num, errnum); 167 if (*errnum < 0) 168 return (NULL); 169 l_pass_flag = 1; 170 break; 171 case '\'': 172 case '$': 173 case '?': 174 case '/': 175 case '.': 176 if (l_order != 0) { 177 *errnum = -1; 178 strcpy(help_msg, "malformed address"); 179 return (NULL); 180 } 181 l_order = 4; 182 switch (ss) { 183 case '\'': 184 l_dot = get_mark(inputt, errnum); 185 break; 186 case '$': 187 l_dot = bottom; /* set to bottom */ 188 break; 189 case '?': 190 l_dot = search_r(inputt, errnum); 191 break; 192 case '/': 193 l_dot = search(inputt, errnum); 194 break; 195 case '.': 196 l_dot = current; 197 break; 198 } 199 break; 200 case '-': 201 case '^': 202 case '+': 203 l_order = 2; 204 if (ss == '+') { 205 l_dot = l_dot->below; 206 if (l_dot == NULL) { 207 strcpy(help_msg, "at end of buffer"); 208 *errnum = -1; 209 return (NULL); 210 } 211 } else { 212 l_dot = l_dot->above; 213 if (l_dot == NULL) { 214 strcpy(help_msg, "at top of buffer"); 215 *errnum = -1; 216 return (NULL); 217 } 218 } 219 break; 220 case ' ': 221 break; /* ignore here, but see comment above */ 222 default: 223 ungetc(ss, inputt); 224 return (l_dot); 225 break; 226 } 227 228 if (*errnum < 0) 229 break; /* from the while-loop */ 230 l_last = ss; 231 } 232 233 if (ss == EOF) 234 return (l_dot); 235 *errnum = -1; 236 return (NULL); 237 } 238