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